diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index cc7b8617f..46a117015 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -1,4 +1,4 @@ -name: build +name: build_test on: push: @@ -7,10 +7,18 @@ on: branches: [ main ] jobs: - build: + 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] + include: + # On linux also build and test release. + - os: ubuntu-latest + kind: release runs-on: ${{ matrix.os }} @@ -26,11 +34,14 @@ jobs: uses: swift-actions/setup-swift@v2 with: swift-version: "6.0.3" - - uses: actions/checkout@v2 - - name: Build - run: swift build -v - - - name: Run tests - run: swift test -v + run: swift build -c ${{ matrix.kind }} -v + - name: Run tests with Node.js + 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 -c ${{ matrix.kind }} -v diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 46c8de95c..e8990e253 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 @@ -2970,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 { @@ -3117,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 aaeb788c8..6611acdef 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. @@ -426,12 +426,11 @@ 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 - b.doReturn(b.randomJsVariable()) + b.maybeReturnRandomJsVariable(0.9) } } b.loadDisposableVariable(disposableVariable) @@ -442,13 +441,12 @@ 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)) { args in - b.doReturn(b.randomJsVariable()) + b.maybeReturnRandomJsVariable(0.9) } } b.loadAsyncDisposableVariable(asyncDisposableVariable) @@ -861,7 +859,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 +897,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 +1105,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 +1143,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 +1281,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 +1343,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()) }, @@ -2414,7 +2412,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 +2460,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 +2473,7 @@ public let CodeGenerators: [CodeGenerator] = [ b.unary(.PostDec, vs[1]) } ) { _ in - b.build(n: 4) + b.buildRecursive(n: 4) } } }, @@ -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) }, @@ -2932,18 +2925,16 @@ 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) } } } 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 - b.build(n: 3) + b.buildRecursive(n: 3) b.doReturn(orig) } } @@ -2961,14 +2952,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 { @@ -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/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/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) } 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/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 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 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 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") }