Skip to content

Commit ec80efa

Browse files
LiedtkeV8-internal LUCI CQ
authored andcommitted
Extend new code generation logic to allow specifying more than just a
type for input requirements and output guarantees. Bug: 445356784 Change-Id: Ib1319c8e42e33688c7c0921b166e46e50b031748 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8760696 Commit-Queue: Matthias Liedtke <[email protected]> Reviewed-by: Carl Smith <[email protected]>
1 parent 2e3e639 commit ec80efa

File tree

5 files changed

+196
-67
lines changed

5 files changed

+196
-67
lines changed

Sources/Fuzzilli/Base/ProgramBuilder.swift

Lines changed: 33 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -770,8 +770,8 @@ public class ProgramBuilder {
770770
(.wasmTypeDef(), {
771771
// Call into the WasmTypeGroup generator (or other that provide a .wasmTypeDef)
772772
let generators = self.fuzzer.codeGenerators.filter { gen in
773-
gen.produces.contains { type in
774-
type.Is(.wasmTypeDef())
773+
gen.produces.contains { produces in
774+
produces.type.Is(.wasmTypeDef())
775775
}
776776
}
777777
let _ = self.complete(generator: generators.randomElement(), withBudget: 5)
@@ -862,8 +862,8 @@ public class ProgramBuilder {
862862
// Right now only use generators that require a single context.
863863
$0.parts.last!.requiredContext.isSingle &&
864864
$0.parts.last!.requiredContext.satisfied(by: self.context) &&
865-
$0.parts.last!.produces.contains(where: { producedType in
866-
producedType.Is(type)
865+
$0.parts.last!.produces.contains(where: { produces in
866+
produces.type.Is(type)
867867
})
868868
})
869869
if generators.count > 0 {
@@ -1798,14 +1798,14 @@ public class ProgramBuilder {
17981798
struct BuildAction {
17991799
var name: String
18001800
var outcome = ActionOutcome.started
1801-
var produces: [ILType]
1801+
var produces: [GeneratorStub.Constraint]
18021802
}
18031803

18041804
var pendingActions: Stack<BuildAction> = Stack()
18051805
var actions = [(BuildAction, Int)]()
18061806
var indent = 0
18071807

1808-
mutating func startAction(_ actionName: String, produces: [ILType]) {
1808+
mutating func startAction(_ actionName: String, produces: [GeneratorStub.Constraint]) {
18091809
let action = BuildAction(name: actionName, produces: produces)
18101810
// Mark this action as `.started`.
18111811
actions.append((action, indent))
@@ -1820,16 +1820,14 @@ public class ProgramBuilder {
18201820
finishedAction.outcome = .success
18211821
actions.append((finishedAction, indent))
18221822
#if DEBUG
1823-
// Now Check that we've seen these new types.
1824-
for t in finishedAction.produces {
1825-
if !newlyCreatedVariableTypes.contains(where: {
1826-
$0.Is(t)
1827-
}) {
1823+
// Now Check that we have variables that match the the specified productions.
1824+
for requirement in finishedAction.produces {
1825+
if !newlyCreatedVariableTypes.contains(where: requirement.fulfilled) {
18281826
var fatalErrorString = ""
18291827
fatalErrorString += "Action: \(finishedAction.name)\n"
18301828
fatalErrorString += "Action guaranteed it would produce: \(finishedAction.produces)\n"
18311829
fatalErrorString += "\(getLogString())\n"
1832-
fatalErrorString += "newlyCreatedVariableTypes: \(newlyCreatedVariableTypes) does not contain expected type \(t)"
1830+
fatalErrorString += "newlyCreatedVariableTypes: \(newlyCreatedVariableTypes) does not contain anything matching \(requirement)"
18331831
fatalError(fatalErrorString)
18341832
}
18351833
}
@@ -2113,31 +2111,29 @@ public class ProgramBuilder {
21132111
var numberOfGeneratedInstructions = 0
21142112

21152113
// Calculate all input requirements of this CodeGenerator.
2116-
let inputTypes = Set(generator.parts.reduce([]) { res, gen in
2117-
return res + gen.inputs.types
2114+
let inputRequirements = Set(generator.parts.reduce([]) { res, gen in
2115+
return res + gen.inputs.constraints
21182116
})
21192117

2120-
var availableTypes = inputTypes.filter {
2121-
randomVariable(ofType: $0) != nil
2118+
var fulfilledRequirements = inputRequirements.filter { requirement in
2119+
findVariable {requirement.fulfilled(by: self.type(of: $0))} != nil
21222120
}
21232121

21242122
// Add the current context to the seen Contexts as well.
21252123
var seenContexts: [Context] = [context]
21262124

2127-
let contextsAndTypes = generator.parts.map { ($0.providedContext, $0.inputs.types) }
2125+
let contextsAndRequirements = generator.parts.map { ($0.providedContext, $0.inputs.constraints) }
21282126

21292127
// Check if the can be produced along this generator, otherwise we need to bail.
2130-
for (contexts, types) in contextsAndTypes {
2128+
for (contexts, requirements) in contextsAndRequirements {
21312129
// We've seen the current context.
21322130
for context in contexts {
21332131
seenContexts.append(context)
21342132
}
21352133

2136-
for type in types {
2134+
for requirement in requirements {
21372135
// If we don't have the type available, check if we can produce it in the current context or a seen context.
2138-
if !availableTypes.contains(where: {
2139-
type.Is($0)
2140-
}) {
2136+
if !fulfilledRequirements.contains(where: requirement.fulfilled) {
21412137
// Check if we have generators that can produce the type reachable from this context.
21422138
let reachableContexts: Context = seenContexts.reduce(Context.empty) { res, ctx in [res, fuzzer.contextGraph.getReachableContexts(from: ctx).reduce(Context.empty) { res, ctx in [res, ctx]}]
21432139
}
@@ -2151,25 +2147,25 @@ public class ProgramBuilder {
21512147

21522148
// Filter to see if they produce this type. Crucially to avoid dependency cycles, these also need to be valuegenerators.
21532149
let canProduceThisType = callableGenerators.contains(where: { generator in
2154-
generator.produces.contains(where: { $0.Is(type) })
2150+
generator.produces.contains(where: { requirement.fulfilled(by: $0) })
21552151
})
21562152

21572153
// We cannot run if this is false.
21582154
if !canProduceThisType {
21592155
// TODO(cffsmith): track some statistics on how often this happens.
2160-
buildLog?.reportFailure(reason: "Cannot produce type \(type) starting in original context \(context).")
2156+
buildLog?.reportFailure(reason: "Cannot produce type \(requirement) starting in original context \(context).")
21612157
return 0
21622158
} else {
21632159
// Mark the type as available.
2164-
availableTypes.insert(type)
2160+
fulfilledRequirements.insert(requirement)
21652161
}
21662162
}
21672163
}
21682164
}
21692165

21702166
// Try to create the types that we need for this generator.
21712167
// At this point we've guaranteed that we can produce the types somewhere along the yield points of this generator.
2172-
createRequiredInputVariables(forTypes: inputTypes)
2168+
createRequiredInputVariables(for: inputRequirements)
21732169

21742170
// Push the remaining stubs, we need to call them to close all Contexts properly.
21752171
for part in generator.tail.reversed() {
@@ -2191,7 +2187,7 @@ public class ProgramBuilder {
21912187
while scheduled.count > depth {
21922188
let codeSizePre = code.count
21932189
// Check if we need to or can create types here.
2194-
createRequiredInputVariables(forTypes: inputTypes)
2190+
createRequiredInputVariables(for: inputRequirements)
21952191
// Build into the block.
21962192
buildRecursive(n: budgetPerYieldPoint)
21972193
// Call the next scheduled stub.
@@ -2215,22 +2211,22 @@ public class ProgramBuilder {
22152211
}
22162212

22172213
// Todo, the context graph could also find ideal paths that allow type creation.
2218-
private func createRequiredInputVariables(forTypes types: Set<ILType>) {
2219-
for type in types {
2214+
private func createRequiredInputVariables(for requirements: Set<GeneratorStub.Constraint>) {
2215+
for requirement in requirements {
2216+
let type = requirement.type
22202217
if type.Is(.jsAnything) && context.contains(.javascript) {
22212218
let _ = findOrGenerateType(type)
22222219
} else {
22232220
if type.Is(.wasmAnything) && context.contains(.wasmFunction) {
22242221
// Check if we can produce it with findOrGenerateWasmVar
22252222
let _ = currentWasmFunction.generateRandomWasmVar(ofType: type)
22262223
}
2227-
if randomVariable(ofType: type) == nil {
2224+
if (findVariable {requirement.fulfilled(by: self.type(of: $0))} == nil) {
2225+
22282226
// Check for other CodeGenerators that can produce the given type in this context.
22292227
let usableGenerators = fuzzer.codeGenerators.filter {
22302228
$0.requiredContext.isSubset(of: context) &&
2231-
$0.produces.contains {
2232-
$0.Is(type)
2233-
}
2229+
$0.produces.contains(where: requirement.fulfilled)
22342230
}
22352231

22362232
// Cannot build type here.
@@ -2344,18 +2340,18 @@ public class ProgramBuilder {
23442340
switch generator.inputs.mode {
23452341
case .loose:
23462342
// Find inputs that are probably compatible with the desired input types using randomVariable(forUseAs:)
2347-
inputs = generator.inputs.types.map(randomVariable(forUseAs:))
2343+
inputs = generator.inputs.constraints.map {randomVariable(forUseAs: $0.type)}
23482344

23492345
case .strict:
23502346
// Find inputs of the required type using randomVariable(ofType:)
2351-
for inputType in generator.inputs.types {
2352-
guard let input = randomVariable(ofType: inputType) else {
2347+
for requirement in generator.inputs.constraints {
2348+
guard let input = (findVariable {requirement.fulfilled(by: self.type(of: $0))}) else {
23532349
// Cannot run this generator
23542350
if generator.providedContext != [] {
23552351
fatalError("This generator is supposed to provide a context but cannot as we've failed to find the necessary inputs.")
23562352
}
23572353
// This early return also needs to report a failure.
2358-
buildLog?.reportFailure(reason: "Cannot find variable that satifies input constraints \(inputType).")
2354+
buildLog?.reportFailure(reason: "Cannot find variable that satifies input constraints \(requirement.type).")
23592355
return 0
23602356
}
23612357
inputs.append(input)

0 commit comments

Comments
 (0)