Skip to content

Commit 5e8b0b7

Browse files
aartbikcommit-bot@chromium.org
authored andcommitted
[dart/fuzzer] Fuzz support for spread and control flow collections
Rationale: Follows the documented grammar to allow for arbitary nested spead/if/for inside collections (list, set, maps). #36218 #36214 Change-Id: Ie5b5828a323401c4db14045e6edd0587677f2c19 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/98261 Reviewed-by: Aart Bik <[email protected]> Reviewed-by: Vyacheslav Egorov <[email protected]> Reviewed-by: Siva Annamalai <[email protected]> Commit-Queue: Aart Bik <[email protected]>
1 parent c3113b0 commit 5e8b0b7

File tree

1 file changed

+91
-37
lines changed

1 file changed

+91
-37
lines changed

runtime/tools/dartfuzz/dartfuzz.dart

Lines changed: 91 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import 'dartfuzz_api_table.dart';
1313
// Version of DartFuzz. Increase this each time changes are made
1414
// to preserve the property that a given version of DartFuzz yields
1515
// the same fuzzed program for a deterministic random seed.
16-
const String version = '1.5';
16+
const String version = '1.6';
1717

1818
// Restriction on statement and expression depths.
1919
const int stmtDepth = 2;
@@ -101,10 +101,10 @@ class DartFuzz {
101101
void emitClasses() {
102102
assert(classFields.length == classMethods.length);
103103
for (int i = 0; i < classFields.length; i++) {
104-
currentClass = i;
105104
emitLn('class X$i ${i == 0 ? "" : "extends X${i - 1}"} {');
106105
indent += 2;
107106
emitVarDecls('$fieldName${i}_', classFields[i]);
107+
currentClass = i;
108108
emitMethods('$methodName${i}_', classMethods[i]);
109109
emitLn('void run() {');
110110
indent += 2;
@@ -156,7 +156,7 @@ class DartFuzz {
156156
for (int i = 0; i < vars.length; i++) {
157157
DartType tp = vars[i];
158158
emitLn('${tp.name} $name$i = ', newline: false);
159-
emitLiteral(tp);
159+
emitLiteral(0, tp);
160160
emit(';', newline: true);
161161
}
162162
emit('', newline: true);
@@ -534,39 +534,96 @@ class DartFuzz {
534534

535535
void emitString() {
536536
emit("'");
537-
int l = rand.nextInt(8);
538-
for (int i = 0; i < l; i++) {
537+
for (int i = 0, n = rand.nextInt(8); i < n; i++) {
539538
emitChar();
540539
}
541540
emit("'");
542541
}
543542

544-
void emitList(String open, String close) {
545-
emit('$open ');
546-
int l = 1 + rand.nextInt(4);
547-
for (int i = 0; i < l; i++) {
548-
emitInt();
549-
if (i != (l - 1)) {
550-
emit(', ');
551-
}
543+
void emitElementExpr(int depth, DartType tp) {
544+
if (currentMethod != null) {
545+
emitExpr(depth, tp);
546+
} else {
547+
emitLiteral(depth, tp);
552548
}
553-
emit(' $close');
554549
}
555550

556-
void emitMap() {
557-
emit('{ ');
558-
int l = 1 + rand.nextInt(4);
559-
for (int i = 0; i < l; i++) {
560-
emit('$i : ');
561-
emitString();
562-
if (i != (l - 1)) {
551+
void emitElement(int depth, DartType tp) {
552+
if (tp == DartType.INT_STRING_MAP) {
553+
emitSmallPositiveInt();
554+
emit(' : ');
555+
emitElementExpr(depth, DartType.STRING);
556+
} else {
557+
emitElementExpr(depth, DartType.INT);
558+
}
559+
}
560+
561+
void emitCollectionElement(int depth, DartType tp) {
562+
int r = depth <= exprDepth ? rand.nextInt(10) : 10;
563+
switch (r + 3) {
564+
// TODO(ajcbik): enable when on by default
565+
// Favors elements over control-flow collections.
566+
case 0:
567+
emit('...'); // spread
568+
emitCollection(depth + 1, tp);
569+
break;
570+
case 1:
571+
emit('if (');
572+
emitElementExpr(depth + 1, DartType.BOOL);
573+
emit(') ');
574+
emitCollectionElement(depth + 1, tp);
575+
if (rand.nextBool()) {
576+
emit(' else ');
577+
emitCollectionElement(depth + 1, tp);
578+
}
579+
break;
580+
case 2:
581+
{
582+
int i = localVars.length;
583+
emit('for (int $localName$i ');
584+
// For-loop (induction, list, set).
585+
switch (rand.nextInt(3)) {
586+
case 0:
587+
emit('= 0; $localName$i < ');
588+
emitSmallPositiveInt();
589+
emit('; $localName$i++) ');
590+
break;
591+
case 1:
592+
emit('in ');
593+
emitCollection(depth + 1, DartType.INT_LIST);
594+
emit(') ');
595+
break;
596+
default:
597+
emit('in ');
598+
emitCollection(depth + 1, DartType.INT_SET);
599+
emit(') ');
600+
break;
601+
}
602+
nest++;
603+
localVars.add(DartType.INT);
604+
emitCollectionElement(depth + 1, tp);
605+
localVars.removeLast();
606+
nest--;
607+
break;
608+
}
609+
default:
610+
emitElement(depth, tp);
611+
break;
612+
}
613+
}
614+
615+
void emitCollection(int depth, DartType tp) {
616+
emit(tp == DartType.INT_LIST ? '[ ' : '{ ');
617+
for (int i = 0, n = 1 + rand.nextInt(8); i < n; i++) {
618+
emitCollectionElement(depth, tp);
619+
if (i != (n - 1)) {
563620
emit(', ');
564621
}
565622
}
566-
emit(' }');
623+
emit(tp == DartType.INT_LIST ? ' ]' : ' }');
567624
}
568625

569-
void emitLiteral(DartType tp) {
626+
void emitLiteral(int depth, DartType tp) {
570627
if (tp == DartType.BOOL) {
571628
emitBool();
572629
} else if (tp == DartType.INT) {
@@ -575,12 +632,10 @@ class DartFuzz {
575632
emitDouble();
576633
} else if (tp == DartType.STRING) {
577634
emitString();
578-
} else if (tp == DartType.INT_LIST) {
579-
emitList('[', ']');
580-
} else if (tp == DartType.INT_SET) {
581-
emitList('{', '}');
582-
} else if (tp == DartType.INT_STRING_MAP) {
583-
emitMap();
635+
} else if (tp == DartType.INT_LIST ||
636+
tp == DartType.INT_SET ||
637+
tp == DartType.INT_STRING_MAP) {
638+
emitCollection(depth, tp);
584639
} else {
585640
assert(false);
586641
}
@@ -642,7 +697,7 @@ class DartFuzz {
642697
void emitTerminal(int depth, DartType tp) {
643698
switch (rand.nextInt(2)) {
644699
case 0:
645-
emitLiteral(tp);
700+
emitLiteral(depth, tp);
646701
break;
647702
default:
648703
emitVar(depth, tp);
@@ -694,7 +749,7 @@ class DartFuzz {
694749
emit('(');
695750
emitExpr(depth + 1, tp);
696751
emitBinaryOp(tp);
697-
emitLiteral(tp);
752+
emitLiteral(depth + 1, tp);
698753
emit(')');
699754
return;
700755
}
@@ -774,8 +829,9 @@ class DartFuzz {
774829
void emitMethodCall(int depth, DartType tp) {
775830
// Only call backward to avoid infinite recursion.
776831
if (currentClass == null) {
777-
// Outside a class: call backward in global methods.
778-
if (pickedCall(depth, tp, methodName, globalMethods, currentMethod)) {
832+
// Outside a class but inside a method: call backward in global methods.
833+
if (currentMethod != null &&
834+
pickedCall(depth, tp, methodName, globalMethods, currentMethod)) {
779835
return;
780836
}
781837
} else {
@@ -996,17 +1052,15 @@ class DartFuzz {
9961052

9971053
List<DartType> fillTypes1() {
9981054
List<DartType> list = new List<DartType>();
999-
int n = 1 + rand.nextInt(4);
1000-
for (int i = 0; i < n; i++) {
1055+
for (int i = 0, n = 1 + rand.nextInt(4); i < n; i++) {
10011056
list.add(getType());
10021057
}
10031058
return list;
10041059
}
10051060

10061061
List<List<DartType>> fillTypes2() {
10071062
List<List<DartType>> list = new List<List<DartType>>();
1008-
int n = 1 + rand.nextInt(4);
1009-
for (int i = 0; i < n; i++) {
1063+
for (int i = 0, n = 1 + rand.nextInt(4); i < n; i++) {
10101064
list.add(fillTypes1());
10111065
}
10121066
return list;

0 commit comments

Comments
 (0)