Skip to content

Commit 1aef794

Browse files
Dominik KlembaV8-internal LUCI CQ
authored andcommitted
Add support for rest parameters in functions
This change adds a possibility of generation rest parameters. The logic in 'randomParameters' was updated to generate a rest parameter with 20% chance whenever possible The chance is an optional function argument, so we can modify that value in tests (and in the code, if necessary). Bug: 458042811, 456162872 Change-Id: Idaf6446cfd248878134e7a449746260e44cfb74b Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8741997 Reviewed-by: Matthias Liedtke <mliedtke@google.com> Reviewed-by: Pawel Krawczyk <pawkra@google.com> Commit-Queue: Dominik Klemba <tacet@google.com> Auto-Submit: Dominik Klemba <tacet@google.com>
1 parent 6c37c6e commit 1aef794

2 files changed

Lines changed: 41 additions & 14 deletions

File tree

Sources/Fuzzilli/Base/ProgramBuilder.swift

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -566,15 +566,15 @@ public class ProgramBuilder {
566566
//
567567
// This will attempt to find a parameter types for which at least a few variables of a compatible types are
568568
// currently available to (potentially) later be used as arguments for calling the generated subroutine.
569-
public func randomParameters(n wantedNumberOfParameters: Int? = nil) -> SubroutineDescriptor {
569+
public func randomParameters(n wantedNumberOfParameters: Int? = nil, withRestParameterProbability restProbability: Double = 0.2) -> SubroutineDescriptor {
570570
assert(probabilityOfUsingAnythingAsParameterTypeIfAvoidable >= 0 && probabilityOfUsingAnythingAsParameterTypeIfAvoidable <= 1)
571571

572572
// If the caller didn't specify how many parameters to generated, find an appropriate
573573
// number of parameters based on how many variables are currently visible (and can
574574
// therefore later be used as arguments for calling the new function).
575575
let n: Int
576576
if let requestedN = wantedNumberOfParameters {
577-
assert(requestedN > 0)
577+
assert(requestedN >= 0)
578578
n = requestedN
579579
} else {
580580
switch numberOfVisibleVariables {
@@ -603,15 +603,27 @@ public class ProgramBuilder {
603603
}
604604

605605
var params = ParameterList()
606-
for _ in 0..<n {
606+
607+
let generateRestParameter = n > 0 && probability(restProbability)
608+
let numPlainParams = generateRestParameter ? n - 1 : n
609+
610+
func randomParamType() -> ILType {
607611
if probability(probabilityOfUsingAnythingAsParameterTypeIfAvoidable) {
608-
params.append(.jsAnything)
612+
return .jsAnything
609613
} else {
610-
params.append(.plain(chooseUniform(from: candidates)))
614+
return chooseUniform(from: candidates)
611615
}
612616
}
613617

614-
// TODO: also generate rest parameters and maybe even optional ones sometimes?
618+
for _ in 0..<numPlainParams {
619+
params.append(.plain(randomParamType()))
620+
}
621+
622+
if generateRestParameter {
623+
params.append(.rest(randomParamType()))
624+
}
625+
626+
// TODO: also generate optional parameters sometimes?
615627

616628
return .parameters(params)
617629
}

Tests/FuzzilliTests/ProgramBuilderTest.swift

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -508,15 +508,15 @@ class ProgramBuilderTests: XCTestCase {
508508
let i = b.loadInt(42)
509509
b.loadInt(43)
510510
b.loadInt(44)
511-
XCTAssertEqual(b.randomParameters(n: 1).parameterTypes[0], .integer)
511+
XCTAssertEqual(b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .integer)
512512

513513
// The same is true if we have variables of other types, but not enough to
514514
// ensure that a function using these types as parameter types can be called
515515
// with multiple different argument values.
516516
let s = b.loadString("foo")
517517
let a = b.createIntArray(with: [1, 2, 3])
518518
let o = b.createObject(with: [:])
519-
XCTAssertEqual(b.randomParameters(n: 1).parameterTypes[0], .integer)
519+
XCTAssertEqual(b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .integer)
520520

521521
// But as soon as we have a sufficient number of other types as well,
522522
// we expect those to be used as well.
@@ -530,16 +530,16 @@ class ProgramBuilderTests: XCTestCase {
530530
let types = [b.type(of: i), b.type(of: s), b.type(of: a), b.type(of: o)]
531531
var usesOfParameterType = [ILType: Int]()
532532
for _ in 0..<100 {
533-
guard case .plain(let paramType) = b.randomParameters(n: 1).parameterTypes[0] else { return XCTFail("Unexpected parameter" )}
533+
guard case .plain(let paramType) = b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0] else { return XCTFail("Unexpected parameter" )}
534534
XCTAssert(types.contains(paramType))
535535
usesOfParameterType[paramType] = (usesOfParameterType[paramType] ?? 0) + 1
536536
}
537537
XCTAssert(usesOfParameterType.values.allSatisfy({ $0 > 0 }))
538538

539539
// However, if we set the probability of using .jsAnything as parameter to 100%, we expect to only see .jsAnything parameters.
540540
b.probabilityOfUsingAnythingAsParameterTypeIfAvoidable = 1.0
541-
XCTAssertEqual(b.randomParameters(n: 1).parameterTypes[0], .jsAnything)
542-
XCTAssertEqual(b.randomParameters(n: 1).parameterTypes[0], .jsAnything)
541+
XCTAssertEqual(b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .jsAnything)
542+
XCTAssertEqual(b.randomParameters(n: 1, withRestParameterProbability: 0).parameterTypes[0], .jsAnything)
543543
}
544544

545545
func testParameterGeneration3() {
@@ -562,7 +562,7 @@ class ProgramBuilderTests: XCTestCase {
562562
XCTAssertEqual(b.type(of: p1), .object(withProperties: ["x", "y"]))
563563
XCTAssertEqual(b.type(of: p1), b.type(of: p2))
564564

565-
let f1 = b.buildPlainFunction(with: b.randomParameters(n: 1)) { args in
565+
let f1 = b.buildPlainFunction(with: b.randomParameters(n: 1, withRestParameterProbability: 0)) { args in
566566
let p = args[0]
567567
XCTAssertEqual(b.type(of: p), b.type(of: p1))
568568
XCTAssertEqual(b.type(of: p).properties, ["x", "y"])
@@ -582,7 +582,7 @@ class ProgramBuilderTests: XCTestCase {
582582
XCTAssert(b.type(of: a1).properties.contains("length"))
583583
XCTAssert(b.type(of: a1).methods.contains("slice"))
584584

585-
let f2 = b.buildPlainFunction(with: b.randomParameters(n: 1)) { args in
585+
let f2 = b.buildPlainFunction(with: b.randomParameters(n: 1, withRestParameterProbability: 0)) { args in
586586
let a = args[0]
587587
XCTAssertEqual(b.type(of: a), b.type(of: a1))
588588
}
@@ -601,7 +601,7 @@ class ProgramBuilderTests: XCTestCase {
601601
XCTAssertEqual(b.type(of: n1), b.type(of: n2))
602602
XCTAssertEqual(b.type(of: n2), b.type(of: n3))
603603

604-
let f3 = b.buildPlainFunction(with: b.randomParameters(n: 1)) { args in
604+
let f3 = b.buildPlainFunction(with: b.randomParameters(n: 1, withRestParameterProbability: 0)) { args in
605605
let a = args[0]
606606
XCTAssertEqual(b.type(of: a), b.type(of: n1))
607607
}
@@ -610,6 +610,21 @@ class ProgramBuilderTests: XCTestCase {
610610
XCTAssert([n1, n2, n3].contains(args[0]))
611611
}
612612

613+
func testRestParameterGeneration() {
614+
let fuzzer = makeMockFuzzer()
615+
let b = fuzzer.makeBuilder()
616+
b.loadInt(42)
617+
b.loadInt(43)
618+
619+
// With probability 1.0, we should always generate a rest parameter if possible.
620+
let params = b.randomParameters(n: 2, withRestParameterProbability: 1.0)
621+
XCTAssertEqual(params.count, 2)
622+
XCTAssert(params.parameters.hasRestParameter)
623+
guard case .plain(_) = params.parameterTypes[0] else { return XCTFail("Expected a plain parameter") }
624+
guard case .rest(_) = params.parameterTypes[1] else { return XCTFail("Expected a rest parameter") }
625+
}
626+
627+
613628
func testObjectLiteralBuilding() {
614629
let fuzzer = makeMockFuzzer()
615630
let b = fuzzer.makeBuilder()

0 commit comments

Comments
 (0)