From 0d5595ef2a328e069de8fda1567c91fb262f4a85 Mon Sep 17 00:00:00 2001 From: SUZUKI Sosuke Date: Mon, 6 Oct 2025 17:02:46 +0900 Subject: [PATCH 1/9] Update JSC (#530) * Update revision for JavaScriptCore * Remove `webkit.patch` --- Targets/JavaScriptCore/Patches/.gitkeep | 0 Targets/JavaScriptCore/Patches/webkit.patch | 27 --------------------- Targets/JavaScriptCore/REVISION | 2 +- 3 files changed, 1 insertion(+), 28 deletions(-) create mode 100644 Targets/JavaScriptCore/Patches/.gitkeep delete mode 100644 Targets/JavaScriptCore/Patches/webkit.patch diff --git a/Targets/JavaScriptCore/Patches/.gitkeep b/Targets/JavaScriptCore/Patches/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/Targets/JavaScriptCore/Patches/webkit.patch b/Targets/JavaScriptCore/Patches/webkit.patch deleted file mode 100644 index 7c4b80d67..000000000 --- a/Targets/JavaScriptCore/Patches/webkit.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff --git a/Source/JavaScriptCore/shell/CMakeLists.txt b/Source/JavaScriptCore/shell/CMakeLists.txt -index 3d0e023c7eed..e553323a94a8 100644 ---- a/Source/JavaScriptCore/shell/CMakeLists.txt -+++ b/Source/JavaScriptCore/shell/CMakeLists.txt -@@ -20,6 +20,10 @@ if (WIN32) - list(APPEND jsc_LIBRARIES Winmm) - endif () - -+if (ENABLE_FUZZILLI) -+ list(APPEND jsc_SOURCES ../fuzzilli/Fuzzilli.cpp) -+endif() -+ - WEBKIT_EXECUTABLE_DECLARE(jsc) - - if (DEVELOPER_MODE) -diff --git a/Source/cmake/OptionsJSCOnly.cmake b/Source/cmake/OptionsJSCOnly.cmake -index cf578475c298..fb8885f7633c 100644 ---- a/Source/cmake/OptionsJSCOnly.cmake -+++ b/Source/cmake/OptionsJSCOnly.cmake -@@ -18,6 +18,7 @@ set(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_ - WEBKIT_OPTION_BEGIN() - WEBKIT_OPTION_DEFINE(ENABLE_STATIC_JSC "Whether to build JavaScriptCore as a static library." PUBLIC OFF) - WEBKIT_OPTION_DEFINE(USE_LIBBACKTRACE "Whether to enable usage of libbacktrace." PUBLIC OFF) -+WEBKIT_OPTION_DEFINE(ENABLE_FUZZILLI "Whether to build JavaScriptCore with support for Fuzzilli." PUBLIC OFF) - WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_REMOTE_INSPECTOR PRIVATE OFF) - if (WIN32) - WEBKIT_OPTION_DEFAULT_PORT_VALUE(USE_SYSTEM_MALLOC PRIVATE OFF) diff --git a/Targets/JavaScriptCore/REVISION b/Targets/JavaScriptCore/REVISION index b793b87dd..e3feb04e1 100644 --- a/Targets/JavaScriptCore/REVISION +++ b/Targets/JavaScriptCore/REVISION @@ -1 +1 @@ -a38ab639b9f37940f21f2abbadb592ba0ceb2ca3 +33b130ec17ce2cc298ac28ac3a693e14a271d863 From cd1ab9ecf8343b9300016aa8c85f4681d71fa4b5 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 6 Oct 2025 10:06:47 +0200 Subject: [PATCH 2/9] [github] Lower timeout for github actions If the LiveTests generate endless loops and the test's timeout mechanism doesn't terminate it, the action can run for multiple hours. Change-Id: I20d40fcb95d8c526320db3439624cf4d7079ef78 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8633202 Auto-Submit: Matthias Liedtke Commit-Queue: Matthias Liedtke Reviewed-by: Danylo Mocherniuk --- .github/workflows/swift.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index ea0f69ec6..c5e6a903f 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -8,6 +8,7 @@ on: jobs: build: + timeout-minutes: 30 strategy: matrix: os: [macos-latest, ubuntu-latest] From 4be47060cd5999a7eef6e490752a7413a30b9868 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 6 Oct 2025 15:59:35 +0200 Subject: [PATCH 3/9] [github] Also run tests with d8 (previously only Node.js) Change-Id: I89b0829edfb72d72e22b9dc4e41862b76a8db711 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8637337 Commit-Queue: Matthias Liedtke Reviewed-by: Danylo Mocherniuk Auto-Submit: Matthias Liedtke --- .github/workflows/swift.yml | 12 ++++++++--- Tests/FuzzilliTests/LiveTests.swift | 31 +++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index c5e6a903f..082bf4b71 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -1,4 +1,4 @@ -name: build +name: build_test on: push: @@ -7,7 +7,7 @@ on: branches: [ main ] jobs: - build: + build_test: timeout-minutes: 30 strategy: matrix: @@ -27,5 +27,11 @@ jobs: - uses: actions/checkout@v2 - name: Build run: swift build -v - - name: Run tests + - name: Run tests with Node.js run: swift test -v + - name: Install jsvu + run: npm install jsvu -g + - name: Install d8 + run: jsvu --os=default --engines=v8 + - name: Run tests with d8 + run: FUZZILLI_TEST_SHELL=~/.jsvu/engines/v8/v8 swift test -v diff --git a/Tests/FuzzilliTests/LiveTests.swift b/Tests/FuzzilliTests/LiveTests.swift index 6a1e467aa..4ffb8c5d9 100644 --- a/Tests/FuzzilliTests/LiveTests.swift +++ b/Tests/FuzzilliTests/LiveTests.swift @@ -24,6 +24,28 @@ class LiveTests: XCTestCase { // Set to true to log failing programs static let VERBOSE = false + /// Meta-test ensuring that the test framework can successfully terminate an endless loop. + func testEndlessLoopTermination() throws { + let runner = try GetJavaScriptExecutorOrSkipTest() + + let results = try Self.runLiveTest(iterations: 1, withRunner: runner, timeoutInSeconds: 1) { b in + b.loadInt(123) // prefix + + let module = b.buildWasmModule() { module in + module.addWasmFunction(with: [] => []) { function, label, args in + function.wasmBuildLoop(with: [] => [], args: []) { label, args in + function.wasmBranch(to: label) + return [] + } + return [] + } + } + b.callMethod(module.getExportedMethod(at: 0), on: module.loadExports(), withArgs: []) + } + assert(results.failureRate == 1) + assert(results.failureMessages.count == 1) + } + func testValueGeneration() throws { let runner = try GetJavaScriptExecutorOrSkipTest() @@ -142,7 +164,7 @@ class LiveTests: XCTestCase { // The closure can use the ProgramBuilder to emit a program of a specific // shape that is then executed with the given runner. We then check that // we stay below the maximum failure rate over the given number of iterations. - static func runLiveTest(iterations n: Int = 250, withRunner runner: JavaScriptExecutor, body: (ProgramBuilder) -> Void) throws -> (failureRate: Double, failureMessages: [String: Int]) { + static func runLiveTest(iterations n: Int = 250, withRunner runner: JavaScriptExecutor, timeoutInSeconds: Int = 5, body: (ProgramBuilder) -> Void) throws -> (failureRate: Double, failureMessages: [String: Int]) { let liveTestConfig = Configuration(logLevel: .error, enableInspection: true) // We have to use the proper JavaScriptEnvironment here. @@ -178,7 +200,7 @@ class LiveTests: XCTestCase { } DispatchQueue.concurrentPerform(iterations: n) { i in - let result = executeAndParseResults(program: programs[i], runner: runner) + let result = executeAndParseResults(program: programs[i], runner: runner, timeoutInSeconds: timeoutInSeconds) results[i] = result } @@ -214,10 +236,11 @@ class LiveTests: XCTestCase { } } - static func executeAndParseResults(program: (program: Program, jsProgram: String), runner: JavaScriptExecutor) -> ExecutionResult { + static func executeAndParseResults(program: (program: Program, jsProgram: String), runner: JavaScriptExecutor, timeoutInSeconds: Int) -> ExecutionResult { do { - let result = try runner.executeScript(program.jsProgram, withTimeout: 5 * Seconds) + let result = try runner.executeScript(program.jsProgram, + withTimeout: Double(timeoutInSeconds) * Seconds) if result.isFailure { var signature: String? = nil From 673e2b6d2f3a489a768a42ee0fbb094737e0b9ed Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 6 Oct 2025 11:52:58 +0200 Subject: [PATCH 4/9] [github] Add job for linux release build & test Change-Id: I2c2f574e7c99948b70d86212c5daa8cdd083692a Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8635657 Reviewed-by: Danylo Mocherniuk Commit-Queue: Matthias Liedtke --- .github/workflows/swift.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 082bf4b71..1848ff9f0 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -12,6 +12,11 @@ jobs: strategy: matrix: os: [macos-latest, ubuntu-latest] + kind: [debug] + include: + # On linux also build and test release. + - os: ubuntu-latest + kind: release runs-on: ${{ matrix.os }} @@ -26,12 +31,12 @@ jobs: run: swift --version - uses: actions/checkout@v2 - name: Build - run: swift build -v + run: swift build -c ${{ matrix.kind }} -v - name: Run tests with Node.js - run: swift test -v + run: swift test -c ${{ matrix.kind }} -v - name: Install jsvu run: npm install jsvu -g - name: Install d8 run: jsvu --os=default --engines=v8 - name: Run tests with d8 - run: FUZZILLI_TEST_SHELL=~/.jsvu/engines/v8/v8 swift test -v + run: FUZZILLI_TEST_SHELL=~/.jsvu/engines/v8/v8 swift test -c ${{ matrix.kind }} -v From f9603287acece81124e8020f2b92d036c12803be Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 6 Oct 2025 17:01:47 +0200 Subject: [PATCH 5/9] [github] Don't cancel early if other job fails Right now the MacOS job is broken. That doesn't mean that we don't care about the results of the linux job any more. In an ideal world, all jobs would be green. Right now this is simply not the case, so we should provide the best possible information. Change-Id: Ifb107d8ed6b9c116e5c151293dd10bf38dc90c95 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8643676 Commit-Queue: Danylo Mocherniuk Auto-Submit: Matthias Liedtke Reviewed-by: Danylo Mocherniuk Commit-Queue: Matthias Liedtke --- .github/workflows/swift.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 1848ff9f0..d2822a14b 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -10,6 +10,8 @@ jobs: build_test: timeout-minutes: 30 strategy: + # If macos-latest fails, we still don't want to cancel ubuntu-latest or the other way around. + fail-fast: false matrix: os: [macos-latest, ubuntu-latest] kind: [debug] From 2107b729b0038e240155e01e7abc7fa035433efd Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 6 Oct 2025 14:58:14 +0200 Subject: [PATCH 6/9] New codegen: Don't reroll to splice on each 'level' Previously we had ProgramBuilder.buildRecursive() to recursively generate code into a program which was replaced with ProgramBuilder.build() calls with the new code generation mechanism. However the default BuildingMode is .generatingAndSplicing which now rerolls a die on each build(n: x) call in a code generator whether to generate or splice which significantly increases the amount of splicing done by Fuzzilli. As splicing is very expensive and involves rewriting the whole program, we should not randomly splice when running CodeGenerators. For ProgramTemplates (similarly to before) each build call still rolls a die whether to generate or splice (however, when deciding to generate on a build() call, this decision will then "stick" as code generators will be using .generating in all cases now. Bug: 448862171 Change-Id: I982c0f992994d2592de43b71c2b59f3dd334e2bb Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8637338 Commit-Queue: Matthias Liedtke Reviewed-by: Carl Smith --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 12 +++++-- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 18 +++++------ .../Fuzzilli/CodeGen/WasmCodeGenerators.swift | 32 +++++++++---------- .../Profiles/V8CommonProfile.swift | 6 ++-- Tests/FuzzilliTests/ProgramBuilderTest.swift | 2 +- 5 files changed, 39 insertions(+), 31 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 46c8de95c..9f4749f29 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -1933,6 +1933,14 @@ public class ProgramBuilder { } } + // Like build(n:by) but forcing BuildingMode to generating. Splicing is an operation that + // affects the whole program, so we shouldn't roll a die on every buildRecursive() call in a + // code generator whether we'd want to splice an operation into the current block (which happens + // with the default mode .generatingAndSplicing). + public func buildRecursive(n budget: Int) { + build(n: budget, by: .generating) + } + /// Run ValueGenerators until we have created at least N new variables. /// Returns both the number of generated instructions and of newly created variables. @discardableResult @@ -1998,7 +2006,7 @@ public class ProgramBuilder { // We need to update the inputs later, so take note of the visible variables here. let oldVisibleVariables = visibleVariables - build(n: defaultCodeGenerationAmount) + build(n: defaultCodeGenerationAmount, by: mode) let newVisibleVariables = visibleVariables.filter { v in let t = type(of: v) @@ -2111,7 +2119,7 @@ public class ProgramBuilder { // Check if we need to or can create types here. createRequiredInputVariables(forTypes: inputTypes) // Build into the block. - build(n: budgetPerYieldPoint) + buildRecursive(n: budgetPerYieldPoint) // Call the next scheduled stub. let _ = callNext() numberOfGeneratedInstructions += code.count - codeSizePre diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index aaeb788c8..26d073e41 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -268,7 +268,7 @@ public let CodeGenerators: [CodeGenerator] = [ } let o = b.buildObjectLiteral { obj in - b.build(n: Int.random(in: 0...10)) + b.buildRecursive(n: Int.random(in: 0...10)) } objType = b.type(of: o) @@ -344,7 +344,7 @@ public let CodeGenerators: [CodeGenerator] = [ // Create the class. let c = b.buildClassDefinition(withSuperclass: superclass, isExpression: probability(0.3)) { cls in - b.build(n: defaultCodeGenerationAmount) + b.buildRecursive(n: defaultCodeGenerationAmount) } // And construct a few instances of it. @@ -2414,7 +2414,7 @@ public let CodeGenerators: [CodeGenerator] = [ let loopVar = b.loadInt(0) b.buildDoWhileLoop( do: { - b.build(n: defaultCodeGenerationAmount) + b.buildRecursive(n: defaultCodeGenerationAmount) b.unary(.PostInc, loopVar) }, while: { @@ -2462,7 +2462,7 @@ public let CodeGenerators: [CodeGenerator] = [ // Generate a for-loop without any loop variables. let counter = b.loadInt(10) b.buildForLoop({}, { b.unary(.PostDec, counter) }) { - b.build(n: 4) + b.buildRecursive(n: 4) } } else { // Generate a for-loop with two loop variables. @@ -2475,7 +2475,7 @@ public let CodeGenerators: [CodeGenerator] = [ b.unary(.PostDec, vs[1]) } ) { _ in - b.build(n: 4) + b.buildRecursive(n: 4) } } }, @@ -2932,7 +2932,7 @@ public let CodeGenerators: [CodeGenerator] = [ if probability(0.5) { imitation = b.buildObjectLiteral { obj in obj.addMethod("valueOf", with: .parameters(n: 0)) { _ in - b.build(n: 3) + b.buildRecursive(n: 3) b.doReturn(orig) } } @@ -2943,7 +2943,7 @@ public let CodeGenerators: [CodeGenerator] = [ imitation = b.buildObjectLiteral { obj in obj.addComputedMethod(toPrimitive, with: .parameters(n: 0)) { _ in - b.build(n: 3) + b.buildRecursive(n: 3) b.doReturn(orig) } } @@ -2961,14 +2961,14 @@ public let CodeGenerators: [CodeGenerator] = [ let constructor = b.getProperty("constructor", of: orig) let cls = b.buildClassDefinition(withSuperclass: constructor, isExpression: probability(0.3)) { _ in - b.build(n: 3) + b.buildRecursive(n: 3) } imitation = b.construct( cls, withArgs: b.randomArguments(forCalling: cls)) } else { imitation = b.buildObjectLiteral { obj in obj.setPrototype(to: orig) - b.build(n: 3) + b.buildRecursive(n: 3) } } } else { diff --git a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift index f1816e9a8..685cb0c0f 100644 --- a/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift @@ -155,7 +155,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ CodeGenerator("WasmForwardReferenceGenerator", inContext: .single(.wasmTypeGroup)) { b in // TODO(cffsmith): think about this. - b.wasmDefineAndResolveForwardReference {b.build(n: defaultCodeGenerationAmount)} + b.wasmDefineAndResolveForwardReference {b.buildRecursive(n: defaultCodeGenerationAmount)} }, CodeGenerator( @@ -1289,7 +1289,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ loopCtr, function.consti32(1), binOpKind: .Sub) function.wasmReassign(variable: loopCtr, to: result) - b.build(n: defaultCodeGenerationAmount) + b.buildRecursive(n: defaultCodeGenerationAmount) // Backedge of loop, we continue if it is not equal to zero. let isNotZero = function.wasmi32CompareOp( @@ -1314,7 +1314,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ function.wasmBuildLoop(with: parameters => outputTypes, args: args) { label, loopArgs in - b.build(n: defaultCodeGenerationAmount) + b.buildRecursive(n: defaultCodeGenerationAmount) let loopCtr = function.wasmi32BinOp( args[0], function.consti32(1), binOpKind: .Add) let condition = function.wasmi32CompareOp( @@ -1341,14 +1341,14 @@ public let WasmCodeGenerators: [CodeGenerator] = [ let recursiveCallCount = 2 + tags.count function.wasmBuildLegacyTry(with: parameters => [], args: args) { label, args in - b.build(n: 4) + b.buildRecursive(n: 4) for (i, tag) in tags.enumerated() { function.WasmBuildLegacyCatch(tag: tag) { _, _, _ in - b.build(n: 4) + b.buildRecursive(n: 4) } } } catchAllBody: { label in - b.build(n: 4) + b.buildRecursive(n: 4) } }, @@ -1368,20 +1368,20 @@ public let WasmCodeGenerators: [CodeGenerator] = [ function.wasmBuildLegacyTryWithResult( with: signature, args: args, body: { label, args in - b.build(n: 4) + b.buildRecursive(n: 4) return outputTypes.map(function.findOrGenerateWasmVar) }, catchClauses: tags.enumerated().map { i, tag in ( tag, { _, _, _ in - b.build(n: 4) + b.buildRecursive(n: 4) return outputTypes.map(function.findOrGenerateWasmVar) } ) }, catchAllBody: { label in - b.build(n: 4) + b.buildRecursive(n: 4) return outputTypes.map(function.findOrGenerateWasmVar) }) }, @@ -1403,20 +1403,20 @@ public let WasmCodeGenerators: [CodeGenerator] = [ function.wasmBuildLegacyTryWithResult( with: signature, args: args, body: { label, args in - b.build(n: 4) + b.buildRecursive(n: 4) return outputTypes.map(function.findOrGenerateWasmVar) }, catchClauses: tags.enumerated().map { i, tag in ( tag, { _, _, _ in - b.build(n: 4) + b.buildRecursive(n: 4) return outputTypes.map(function.findOrGenerateWasmVar) } ) }, catchAllBody: { label in - b.build(n: 4) + b.buildRecursive(n: 4) return outputTypes.map(function.findOrGenerateWasmVar) }) }, @@ -1433,7 +1433,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ function.wasmBuildLegacyTryDelegateWithResult( with: parameters => outputTypes, args: args, body: { _, _ in - b.build(n: 4) + b.buildRecursive(n: 4) return outputTypes.map(function.findOrGenerateWasmVar) }, delegate: label) }, @@ -1612,7 +1612,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ let results = parameterTypes.map(function.findOrGenerateWasmVar) function.wasmEndBlock( outputTypes: signature.outputTypes, args: results) - b.build(n: 4) + b.buildRecursive(n: 4) } }, @@ -1672,7 +1672,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ with: tryParameters => tryOutputTypes, args: tryArgs, catches: catches ) { _, _ in - b.build(n: defaultCodeGenerationAmount) + b.buildRecursive(n: defaultCodeGenerationAmount) return tryOutputTypes.map(function.findOrGenerateWasmVar) } outputTypesList.reversed().enumerated().forEach { @@ -1681,7 +1681,7 @@ public let WasmCodeGenerators: [CodeGenerator] = [ function.findOrGenerateWasmVar) function.wasmEndBlock( outputTypes: outputTypes, args: results) - b.build(n: defaultCodeGenerationAmount) + b.buildRecursive(n: defaultCodeGenerationAmount) } } ]), diff --git a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift index fb06b05d0..dc3a6e03f 100644 --- a/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift +++ b/Sources/FuzzilliCli/Profiles/V8CommonProfile.swift @@ -110,11 +110,11 @@ public let WorkerGenerator = CodeGenerator("WorkerGenerator") { b in // Generate a random onmessage handler for incoming messages. let onmessageFunction = b.buildPlainFunction(with: .parameters(n: 1)) { args in - b.build(n: Int.random(in: 2...5)) + b.buildRecursive(n: Int.random(in: 2...5)) } b.setProperty("onmessage", of: this, to: onmessageFunction) - b.build(n: Int.random(in: 3...10)) + b.buildRecursive(n: Int.random(in: 3...10)) } let workerConstructor = b.createNamedVariable(forBuiltin: "Worker") @@ -249,7 +249,7 @@ public let MapTransitionFuzzer = ProgramTemplate("MapTransitionFuzzer") { b in } let f = b.buildPlainFunction(with: parameters) { params in - b.build(n: Int.random(in: 3...10)) + b.buildRecursive(n: Int.random(in: 3...10)) b.doReturn(b.randomJsVariable()) } diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index ad5977ab0..542f36f6c 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -75,7 +75,7 @@ class ProgramBuilderTests: XCTestCase { let fuzzer = makeMockFuzzer(environment: env) let b = fuzzer.makeBuilder() - let codeGenerators = fuzzer.codeGenerators.filter { codeGenerator in + let codeGenerators = fuzzer.codeGenerators.filter { codeGenerator in // Filter out Generators that do a reassignment as these will make our Variables be typed as .jsAnything. !codeGenerator.name.contains("Reassign") } From dc981ce448a6fab92b023e41a493d42cc3355e17 Mon Sep 17 00:00:00 2001 From: Matthias Liedtke Date: Mon, 6 Oct 2025 18:28:59 +0200 Subject: [PATCH 7/9] Fix order in Opcodes.swift to be in line with program.proto Commit adfa084a75e58e71a1877c3ea2c430a3f114e7ef manually modified the program.proto, so these got out of sync. Bug: 446634535 Change-Id: I63438de9d88684a766b2f4f2cfc7f88a5b5b1079 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8643678 Reviewed-by: Michael Achenbach Auto-Submit: Matthias Liedtke Commit-Queue: Michael Achenbach --- Sources/Fuzzilli/FuzzIL/Opcodes.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/Fuzzilli/FuzzIL/Opcodes.swift b/Sources/Fuzzilli/FuzzIL/Opcodes.swift index f9fda2f00..44bca30d2 100644 --- a/Sources/Fuzzilli/FuzzIL/Opcodes.swift +++ b/Sources/Fuzzilli/FuzzIL/Opcodes.swift @@ -67,8 +67,6 @@ enum Opcode { case classAddInstanceComputedProperty(ClassAddInstanceComputedProperty) case beginClassInstanceMethod(BeginClassInstanceMethod) case endClassInstanceMethod(EndClassInstanceMethod) - case beginClassInstanceComputedMethod(BeginClassInstanceComputedMethod) - case endClassInstanceComputedMethod(EndClassInstanceComputedMethod) case beginClassInstanceGetter(BeginClassInstanceGetter) case endClassInstanceGetter(EndClassInstanceGetter) case beginClassInstanceSetter(BeginClassInstanceSetter) @@ -80,8 +78,6 @@ enum Opcode { case endClassStaticInitializer(EndClassStaticInitializer) case beginClassStaticMethod(BeginClassStaticMethod) case endClassStaticMethod(EndClassStaticMethod) - case beginClassStaticComputedMethod(BeginClassStaticComputedMethod) - case endClassStaticComputedMethod(EndClassStaticComputedMethod) case beginClassStaticGetter(BeginClassStaticGetter) case endClassStaticGetter(EndClassStaticGetter) case beginClassStaticSetter(BeginClassStaticSetter) @@ -363,4 +359,8 @@ enum Opcode { case wasmDefineSignatureType(WasmDefineSignatureType) case createNamedDisposableVariable(CreateNamedDisposableVariable) case createNamedAsyncDisposableVariable(CreateNamedAsyncDisposableVariable) + case beginClassInstanceComputedMethod(BeginClassInstanceComputedMethod) + case endClassInstanceComputedMethod(EndClassInstanceComputedMethod) + case beginClassStaticComputedMethod(BeginClassStaticComputedMethod) + case endClassStaticComputedMethod(EndClassStaticComputedMethod) } From 99d89a23a33276368ee11514d5da024d86860d7d Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Thu, 2 Oct 2025 17:50:28 +0200 Subject: [PATCH 8/9] Probabilistically return in certain class methods and computed object methods Bug: 446634535 Change-Id: I9c2e556efcbc6288e5cc92baca471b4ac1482797 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8636358 Commit-Queue: Michael Achenbach Reviewed-by: Matthias Liedtke --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 6 ++++++ Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 16 ++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 9f4749f29..260f39467 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -2978,6 +2978,12 @@ public class ProgramBuilder { } } + public func maybeReturnRandomJsVariable(_ prob: Double) { + if probability(prob) { + doReturn(randomJsVariable()) + } + } + @discardableResult public func yield(_ value: Variable? = nil) -> Variable { if let argument = value { diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 26d073e41..ca9ee3b92 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -431,7 +431,7 @@ public let CodeGenerators: [CodeGenerator] = [ let disposableVariable = b.buildObjectLiteral { obj in obj.addProperty("value", as: val) obj.addComputedMethod(dispose, with: .parameters(n: 0)) { args in - b.doReturn(b.randomJsVariable()) + b.maybeReturnRandomJsVariable(0.9) } } b.loadDisposableVariable(disposableVariable) @@ -448,7 +448,7 @@ public let CodeGenerators: [CodeGenerator] = [ obj.addProperty("value", as: val) obj.addComputedMethod(asyncDispose, with: .parameters(n: 0)) { args in - b.doReturn(b.randomJsVariable()) + b.maybeReturnRandomJsVariable(0.9) } } b.loadAsyncDisposableVariable(asyncDisposableVariable) @@ -861,7 +861,7 @@ public let CodeGenerators: [CodeGenerator] = [ "ClassInstanceMethodEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in - b.doReturn(b.randomJsVariable()) + b.maybeReturnRandomJsVariable(0.9) b.emit(EndClassInstanceMethod()) }, ]), @@ -899,7 +899,7 @@ public let CodeGenerators: [CodeGenerator] = [ "ClassInstanceComputedMethodEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in - b.doReturn(b.randomJsVariable()) + b.maybeReturnRandomJsVariable(0.9) b.emit(EndClassInstanceComputedMethod()) }, ]), @@ -1107,7 +1107,7 @@ public let CodeGenerators: [CodeGenerator] = [ "ClassStaticMethodEndGenerator", inContext: .single([.javascript, .classMethod, .subroutine, .method]) ) { b in - b.doReturn(b.randomJsVariable()) + b.maybeReturnRandomJsVariable(0.9) b.emit(EndClassStaticMethod()) }, ]), @@ -1145,7 +1145,7 @@ public let CodeGenerators: [CodeGenerator] = [ "ClassStaticComputedMethodEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in - b.doReturn(b.randomJsVariable()) + b.maybeReturnRandomJsVariable(0.9) b.emit(EndClassStaticComputedMethod()) }, ]), @@ -1283,7 +1283,7 @@ public let CodeGenerators: [CodeGenerator] = [ "ClassPrivateInstanceMethodEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in - b.doReturn(b.randomJsVariable()) + b.maybeReturnRandomJsVariable(0.9) b.emit(EndClassPrivateInstanceMethod()) }, ]), @@ -1345,7 +1345,7 @@ public let CodeGenerators: [CodeGenerator] = [ "ClassPrivateStaticMethodEndGenerator", inContext: .single([.javascript, .subroutine, .method, .classMethod]) ) { b in - b.doReturn(b.randomJsVariable()) + b.maybeReturnRandomJsVariable(0.9) b.emit(EndClassPrivateStaticMethod()) }, From bf67855578d12b68a89b7515898389d87746290e Mon Sep 17 00:00:00 2001 From: Michael Achenbach Date: Tue, 7 Oct 2025 12:08:45 +0200 Subject: [PATCH 9/9] Refactoring - helper for Symbol properties Also canonically hide the intermediate variable used for "Symbol" as done in some of the existing use cases. Bug: 446634535 Change-Id: I00794d4120057ef7e096ca913f827f8872d6ce41 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8646836 Reviewed-by: Matthias Liedtke Commit-Queue: Michael Achenbach --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 9 +++++++ Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 27 ++++++------------- Tests/FuzzilliTests/LifterTest.swift | 16 +++++------ 3 files changed, 25 insertions(+), 27 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 260f39467..e8990e253 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -3131,6 +3131,15 @@ public class ProgramBuilder { return emit(CreateNamedAsyncDisposableVariable(name), withInputs: [initialValue]).output } + @discardableResult + public func createSymbolProperty(_ name: String) -> Variable { + let Symbol = createNamedVariable(forBuiltin: "Symbol") + // The Symbol constructor is just a "side effect" and probably + // shouldn't be used by following generators. + hide(Symbol) + return getProperty(name, of: Symbol) + } + @discardableResult public func eval(_ string: String, with arguments: [Variable] = [], hasOutput: Bool = false) -> Variable? { let instr = emit(Eval(string, numArguments: arguments.count, hasOutput: hasOutput), withInputs: arguments) diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index ca9ee3b92..6611acdef 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -426,8 +426,7 @@ public let CodeGenerators: [CodeGenerator] = [ "DisposableVariableGenerator", inContext: .single(.subroutine), inputs: .one ) { b, val in assert(b.context.contains(.subroutine)) - let dispose = b.getProperty( - "dispose", of: b.createNamedVariable(forBuiltin: "Symbol")) + let dispose = b.createSymbolProperty("dispose") let disposableVariable = b.buildObjectLiteral { obj in obj.addProperty("value", as: val) obj.addComputedMethod(dispose, with: .parameters(n: 0)) { args in @@ -442,8 +441,7 @@ public let CodeGenerators: [CodeGenerator] = [ inputs: .one ) { b, val in assert(b.context.contains(.asyncFunction)) - let asyncDispose = b.getProperty( - "asyncDispose", of: b.createNamedVariable(forBuiltin: "Symbol")) + let asyncDispose = b.createSymbolProperty("asyncDispose") let asyncDisposableVariable = b.buildObjectLiteral { obj in obj.addProperty("value", as: val) obj.addComputedMethod(asyncDispose, with: .parameters(n: 0)) { @@ -2672,11 +2670,8 @@ public let CodeGenerators: [CodeGenerator] = [ CodeGenerator( "WellKnownPropertyLoadGenerator", inputs: .preferred(.object()) ) { b, obj in - let Symbol = b.createNamedVariable(forBuiltin: "Symbol") - // The Symbol constructor is just a "side effect" of this generator and probably shouldn't be used by following generators. - b.hide(Symbol) - let name = chooseUniform(from: JavaScriptEnvironment.wellKnownSymbols) - let propertyName = b.getProperty(name, of: Symbol) + let propertyName = b.createSymbolProperty( + chooseUniform(from: JavaScriptEnvironment.wellKnownSymbols)) let needGuard = b.type(of: obj).MayBe(.nullish) b.getComputedProperty(propertyName, of: obj, guard: needGuard) }, @@ -2684,10 +2679,8 @@ public let CodeGenerators: [CodeGenerator] = [ CodeGenerator( "WellKnownPropertyStoreGenerator", inputs: .preferred(.object()) ) { b, obj in - let Symbol = b.createNamedVariable(forBuiltin: "Symbol") - b.hide(Symbol) - let name = chooseUniform(from: JavaScriptEnvironment.wellKnownSymbols) - let propertyName = b.getProperty(name, of: Symbol) + let propertyName = b.createSymbolProperty( + chooseUniform(from: JavaScriptEnvironment.wellKnownSymbols)) let val = b.randomJsVariable() b.setComputedProperty(propertyName, of: obj, to: val) }, @@ -2937,9 +2930,7 @@ public let CodeGenerators: [CodeGenerator] = [ } } } else { - let toPrimitive = b.getProperty( - "toPrimitive", - of: b.createNamedVariable(forBuiltin: "Symbol")) + let toPrimitive = b.createSymbolProperty("toPrimitive") imitation = b.buildObjectLiteral { obj in obj.addComputedMethod(toPrimitive, with: .parameters(n: 0)) { _ in @@ -3081,9 +3072,7 @@ public let CodeGenerators: [CodeGenerator] = [ }, CodeGenerator("IteratorGenerator", produces: [.iterable]) { b in - let Symbol = b.createNamedVariable(forBuiltin: "Symbol") - b.hide(Symbol) - let iteratorSymbol = b.getProperty("iterator", of: Symbol) + let iteratorSymbol = b.createSymbolProperty("iterator") b.hide(iteratorSymbol) let iterableObject = b.buildObjectLiteral { obj in obj.addComputedMethod(iteratorSymbol, with: .parameters(n: 0)) { diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 8d020d82d..7758461d1 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -518,7 +518,7 @@ class LifterTests: XCTestCase { let null = b.loadNull() let v4 = b.binary(v3, v1, with: .Add) let otherObject = b.createNamedVariable(forBuiltin: "SomeObject") - let toPrimitive = b.getProperty("toPrimitive", of: b.createNamedVariable(forBuiltin: "Symbol")) + let toPrimitive = b.createSymbolProperty("toPrimitive") b.buildObjectLiteral { obj in obj.addProperty("p1", as: v1) obj.addProperty("__proto__", as: null) @@ -653,9 +653,7 @@ class LifterTests: XCTestCase { let two = b.loadInt(2) let baz = b.loadString("baz") let baz42 = b.binary(baz, i, with: .Add) - let toPrimitive = b.getProperty( - "toPrimitive", - of: b.createNamedVariable(forBuiltin: "Symbol")) + let toPrimitive = b.createSymbolProperty("toPrimitive") let sm = b.loadString("sm") let C = b.buildClassDefinition() { cls in cls.addInstanceProperty("foo") @@ -1827,8 +1825,7 @@ class LifterTests: XCTestCase { let b = fuzzer.makeBuilder() let s = b.loadString("Hello World") - let Symbol = b.createNamedVariable(forBuiltin: "Symbol") - let iterator = b.getProperty("iterator", of: Symbol) + let iterator = b.createSymbolProperty("iterator") let r = b.callComputedMethod(iterator, on: s) b.callMethod("next", on: r) @@ -3168,7 +3165,10 @@ class LifterTests: XCTestCase { let f = b.buildPlainFunction(with: .parameters(n: 0)) { args in let v1 = b.loadInt(1) let v2 = b.loadInt(42) - let dispose = b.getProperty("dispose", of: b.createNamedVariable(forBuiltin: "Symbol")); + let numVariables = b.numberOfVisibleVariables + let dispose = b.createSymbolProperty("dispose"); + // Test that the intermediate variable for "Symbol" stays hidden. + XCTAssertEqual(b.numberOfVisibleVariables, numVariables + 1) let disposableVariable = b.buildObjectLiteral { obj in obj.addProperty("value", as: v1) obj.addComputedMethod(dispose, with: .parameters(n:0)) { args in @@ -3220,7 +3220,7 @@ class LifterTests: XCTestCase { let f = b.buildAsyncFunction(with: .parameters(n: 0)) { args in let v1 = b.loadInt(1) let v2 = b.loadInt(42) - let asyncDispose = b.getProperty("asyncDispose", of: b.createNamedVariable(forBuiltin: "Symbol")) + let asyncDispose = b.createSymbolProperty("asyncDispose") let asyncDisposableVariable = b.buildObjectLiteral { obj in obj.addProperty("value", as: v1) obj.addComputedMethod(asyncDispose, with: .parameters(n:0)) { args in