Skip to content

Commit d6d10b0

Browse files
author
Samuel Groß
committed
Implement a new Splicing Algorithm
Splicing refers to the process of taking a subset of the instructions of one program and inserting them into another program, possibly connecting their data-flows together. Splicing must always produce a valid program. In particular, all input variables used by the spliced instructions must be available, and the instructions must exist in the correct context (e.g. a BeginSwitchCase must only occur inside a BeginSwitch). The new splicing algorithm achieves this and runs in linear time. Its main features include: - Computation of data-flow dependencies between instructions to determine which instructions to splice - Probabilistic remapping of some variables to existing and "compatible" variables in the host program to connect the dataflows of the programs - The ability to splice instructions with special context requirements. For example, it can (only) splice an Await instruction if there is an open async function in the host program - The ability to to splice into restricted contexts. For example, it can splice a SwitchCase block from one program into a Switch block in another program See the many tests in ProgramBuilderTest.swift for examples and the comments in ProgramBuilder.swift for an explanation of the algorithm.
1 parent 04f1e61 commit d6d10b0

File tree

8 files changed

+1478
-592
lines changed

8 files changed

+1478
-592
lines changed

Sources/Fuzzilli/Core/ProgramBuilder.swift

Lines changed: 246 additions & 155 deletions
Large diffs are not rendered by default.

Sources/Fuzzilli/FuzzIL/Instruction.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ public struct Instruction {
221221
/// BeginSwitch/EndSwitch Blocks. See BeginSwitchCase.
222222
public var skipsSurroundingContext: Bool {
223223
assert(isBlockStart)
224-
return op.attributes.contains(.skipsSurroundingContext)
224+
return op.attributes.contains(.resumesSurroundingContext)
225225
}
226226

227227
/// Whether this instruction is an internal instruction that should not "leak" into

Sources/Fuzzilli/FuzzIL/JsOperations.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,7 +1162,7 @@ class BeginSwitch: JsOperation {
11621162

11631163
class BeginSwitchCase: JsOperation {
11641164
init() {
1165-
super.init(numInputs: 1, numOutputs: 0, attributes: [.isBlockStart, .skipsSurroundingContext], requiredContext: [.switchBlock], contextOpened: [.switchCase])
1165+
super.init(numInputs: 1, numOutputs: 0, attributes: [.isBlockStart, .resumesSurroundingContext], requiredContext: [.switchBlock], contextOpened: [.switchCase, .javascript])
11661166
}
11671167
}
11681168

@@ -1171,7 +1171,7 @@ class BeginSwitchCase: JsOperation {
11711171
/// such that, if necessary, the BeginSwitch/EndSwitch reducer can remove the whole switch case altogether.
11721172
class BeginSwitchDefaultCase: JsOperation {
11731173
init() {
1174-
super.init(numInputs: 0, numOutputs: 0, attributes: [.isBlockStart, .skipsSurroundingContext], requiredContext: [.switchBlock], contextOpened: [.switchCase])
1174+
super.init(numInputs: 0, numOutputs: 0, attributes: [.isBlockStart, .resumesSurroundingContext], requiredContext: [.switchBlock], contextOpened: [.switchCase, .javascript])
11751175
}
11761176
}
11771177

Sources/Fuzzilli/FuzzIL/Operation.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,9 @@ public class Operation {
100100
static let isVariadic = Attributes(rawValue: 1 << 9)
101101
// The operation propagates the surrounding context.
102102
static let propagatesSurroundingContext = Attributes(rawValue: 1 << 10)
103-
// The instruction starts an empty context, but the surrounding context
104-
// is propagated into child blocks of this instruction. This is useful
105-
// for example for BeginSwitch and BeginSwitchCase.
106-
static let skipsSurroundingContext = Attributes(rawValue: 1 << 11)
103+
// The instruction resumes the context from before its parent context.
104+
// This is useful for example for BeginSwitch and BeginSwitchCase.
105+
static let resumesSurroundingContext = Attributes(rawValue: 1 << 11)
107106
}
108107
}
109108

Sources/Fuzzilli/FuzzIL/Semantics.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ extension Operation {
2727
case is CallFunction,
2828
is CallMethod,
2929
is CallComputedMethod:
30-
// We assume that a constructor doesn't modify its arguments when called
30+
// We assume that a constructor doesn't modify its arguments when called.
3131
return true
3232
case is StoreProperty,
3333
is StoreElement,
@@ -37,6 +37,10 @@ extension Operation {
3737
is DeleteComputedProperty,
3838
is DeleteElement:
3939
return inputIdx == 0
40+
case is BeginWhileLoop,
41+
is BeginDoWhileLoop:
42+
// We assume that loops mutate their run value (but, somewhat arbitrarily, not the value that it is compared against).
43+
return inputIdx == 0
4044
default:
4145
return false
4246
}
@@ -72,7 +76,7 @@ extension Instruction {
7276
}
7377

7478
/// Returns true if this operation could mutate any of the given input variables when executed.
75-
func mayMutate(_ vars: VariableSet) -> Bool {
79+
func mayMutate(anyOf vars: VariableSet) -> Bool {
7680
for (idx, input) in inputs.enumerated() {
7781
if vars.contains(input) {
7882
if op.mayMutate(input: idx) {

Sources/Fuzzilli/Util/VariableSet.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,16 @@ public struct VariableSet: Hashable, Codable {
161161
return result
162162
}
163163

164+
/// Returns true if this set is a subset of the provided set.
165+
public func isSubset(of other: VariableSet) -> Bool {
166+
for (i, w) in words.enumerated() {
167+
if i >= other.words.count || w & other.words[i] != w {
168+
return false
169+
}
170+
}
171+
return true
172+
}
173+
164174
/// Returns true if this set and the provided set have no variables in common.
165175
public func isDisjoint(with other: VariableSet) -> Bool {
166176
for (i, w) in other.words.enumerated() {
@@ -171,7 +181,7 @@ public struct VariableSet: Hashable, Codable {
171181
return true
172182
}
173183

174-
/// Returns true if this and the provided set have no variables in common.
184+
/// Returns true if this set and the provided set have no variables in common.
175185
public func isDisjoint<S: Sequence>(with other: S) -> Bool where S.Element == Variable {
176186
for v in other {
177187
if contains(v) {

0 commit comments

Comments
 (0)