Skip to content

Commit 2e8f648

Browse files
authored
Added support for finally blocks (googleprojectzero#196)
1 parent 2bd387d commit 2e8f648

File tree

15 files changed

+250
-15
lines changed

15 files changed

+250
-15
lines changed

Sources/Fuzzilli/Core/CodeGenerators.swift

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -444,9 +444,25 @@ public let CodeGenerators: [CodeGenerator] = [
444444
b.beginTry() {
445445
b.generateRecursive()
446446
}
447-
b.beginCatch() { _ in
448-
b.generateRecursive()
449-
}
447+
withEqualProbability({
448+
// try-catch-finally
449+
b.beginCatch() { _ in
450+
b.generateRecursive()
451+
}
452+
b.beginFinally() {
453+
b.generateRecursive()
454+
}
455+
}, {
456+
// try-catch
457+
b.beginCatch() { _ in
458+
b.generateRecursive()
459+
}
460+
}, {
461+
// try-finally
462+
b.beginFinally() {
463+
b.generateRecursive()
464+
}
465+
})
450466
b.endTryCatch()
451467
},
452468

Sources/Fuzzilli/Core/ProgramBuilder.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,11 @@ public class ProgramBuilder {
12611261
body(exception)
12621262
}
12631263

1264+
public func beginFinally(_ body: () -> Void) {
1265+
perform(BeginFinally())
1266+
body()
1267+
}
1268+
12641269
public func endTryCatch() {
12651270
perform(EndTryCatch())
12661271
}

Sources/Fuzzilli/FuzzIL/AbstractInterpreter.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public struct AbstractInterpreter {
7070
state.mergeStates(typeChanges: &typeChanges)
7171
case is BeginTry,
7272
is BeginCatch,
73+
is BeginFinally,
7374
is EndTryCatch:
7475
break
7576
case is BeginWith,

Sources/Fuzzilli/FuzzIL/Instruction.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,8 @@ extension Instruction: ProtobufConvertible {
450450
$0.beginTry = Fuzzilli_Protobuf_BeginTry()
451451
case is BeginCatch:
452452
$0.beginCatch = Fuzzilli_Protobuf_BeginCatch()
453+
case is BeginFinally:
454+
$0.beginFinally = Fuzzilli_Protobuf_BeginFinally()
453455
case is EndTryCatch:
454456
$0.endTryCatch = Fuzzilli_Protobuf_EndTryCatch()
455457
case is ThrowException:
@@ -665,6 +667,8 @@ extension Instruction: ProtobufConvertible {
665667
op = BeginTry()
666668
case .beginCatch(_):
667669
op = BeginCatch()
670+
case .beginFinally(_):
671+
op = BeginFinally()
668672
case .endTryCatch(_):
669673
op = EndTryCatch()
670674
case .throwException(_):

Sources/Fuzzilli/FuzzIL/Operations.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,12 @@ class BeginCatch: ControlFlowOperation {
840840
}
841841
}
842842

843+
class BeginFinally: ControlFlowOperation {
844+
init() {
845+
super.init(numInputs: 0, attributes: [.isBlockBegin, .isBlockEnd])
846+
}
847+
}
848+
843849
class EndTryCatch: ControlFlowOperation {
844850
init() {
845851
super.init(numInputs: 0, attributes: [.isBlockEnd])

Sources/Fuzzilli/FuzzIL/Semantics.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,10 @@ extension Operation {
125125
case is BeginForOf:
126126
return endOp is EndForOf
127127
case is BeginTry:
128-
return endOp is BeginCatch
128+
return endOp is BeginCatch || endOp is BeginFinally
129129
case is BeginCatch:
130+
return endOp is BeginFinally || endOp is EndTryCatch
131+
case is BeginFinally:
130132
return endOp is EndTryCatch
131133
case is BeginCodeString:
132134
return endOp is EndCodeString

Sources/Fuzzilli/Lifting/FuzzILLifter.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,11 @@ public class FuzzILLifter: Lifter {
311311
w.emit("BeginCatch -> \(instr.innerOutput)")
312312
w.increaseIndentionLevel()
313313

314+
case is BeginFinally:
315+
w.decreaseIndentionLevel()
316+
w.emit("BeginFinally")
317+
w.increaseIndentionLevel()
318+
314319
case is EndTryCatch:
315320
w.decreaseIndentionLevel()
316321
w.emit("EndTryCatch")

Sources/Fuzzilli/Lifting/JavaScriptLifter.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,11 @@ public class JavaScriptLifter: Lifter {
520520
w.emit("} catch(\(instr.innerOutput)) {")
521521
w.increaseIndentionLevel()
522522

523+
case is BeginFinally:
524+
w.decreaseIndentionLevel()
525+
w.emit("} finally {")
526+
w.increaseIndentionLevel()
527+
523528
case is EndTryCatch:
524529
w.decreaseIndentionLevel()
525530
w.emit("}")

Sources/Fuzzilli/Minimization/BlockReducer.swift

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ struct BlockReducer: Reducer {
2626
reduceLoop(loop: group.block(0), in: &code, with: verifier)
2727

2828
case is BeginTry:
29-
reduceTryCatch(tryCatch: group, in: &code, with: verifier)
29+
reduceTryCatchFinally(tryCatch: group, in: &code, with: verifier)
3030

3131
case is BeginIf:
3232
// We reduce ifs simply by removing the whole block group.
@@ -115,10 +115,10 @@ struct BlockReducer: Reducer {
115115
reduceGenericBlockGroup(codestring, in: &code, with: verifier)
116116
}
117117

118-
private func reduceTryCatch(tryCatch: BlockGroup, in code: inout Code, with verifier: ReductionVerifier) {
119-
// We first try to remove only the try-catch block instructions.
118+
private func reduceTryCatchFinally(tryCatch: BlockGroup, in code: inout Code, with verifier: ReductionVerifier) {
119+
// We first try to remove only the try-catch-finally block instructions.
120120
// If that doesn't work, then we try to remove the try block including
121-
// its last instruction but keepp the body of the catch block.
121+
// its last instruction but keep the body of the catch and/or finally block.
122122
// If the body isn't required, it will be removed by the
123123
// other reducers. On the other hand, this successfully
124124
// reduces code like
@@ -128,35 +128,40 @@ struct BlockReducer: Reducer {
128128
// throw 42;
129129
// } catch {
130130
// do_something_important2();
131+
// } finally {
132+
// do_something_important3();
131133
// }
132134
//
133135
// to
134136
//
135137
// do_something_important1();
136138
// do_something_important2();
139+
// do_something_important3();
137140
//
138141

139142
var candidates = [Int]()
140143

141-
candidates.append(tryCatch[0].index)
142-
candidates.append(tryCatch[1].index)
143-
candidates.append(tryCatch[2].index)
144+
for i in 0...tryCatch.numBlocks {
145+
candidates.append(tryCatch[i].index)
146+
}
144147

145148
if verifier.tryNopping(candidates, in: &code) {
146149
return
147150
}
148151

152+
var removedLastTryBlockInstruction = false
149153
// Find the last instruction in try block and try removing that as well.
150154
for i in stride(from: tryCatch[1].index - 1, to: tryCatch[0].index, by: -1) {
151155
if !(code[i].op is Nop) {
152156
if !code[i].isBlock {
153157
candidates.append(i)
158+
removedLastTryBlockInstruction = true
154159
}
155160
break
156161
}
157162
}
158163

159-
if candidates.count == 4 && verifier.tryNopping(candidates, in: &code) {
164+
if removedLastTryBlockInstruction && verifier.tryNopping(candidates, in: &code) {
160165
return
161166
}
162167

@@ -168,15 +173,16 @@ struct BlockReducer: Reducer {
168173
// const v17 = Math(v16,v16);
169174
// }
170175
// } catch {
176+
// } finally {
171177
// }
172178
//
173-
if candidates.count == 4 {
179+
if removedLastTryBlockInstruction {
174180
candidates.removeLast()
175181
}
176182

177-
// Find last instruction in try block
183+
// Remove all instructions in the body of the try block
178184
for i in stride(from: tryCatch[1].index - 1, to: tryCatch[0].index, by: -1) {
179-
if !(tryCatch.code[i].op is Nop) {
185+
if !(code[i].op is Nop) {
180186
candidates.append(i)
181187
}
182188
}

Sources/Fuzzilli/Protobuf/operations.pb.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,16 @@ public struct Fuzzilli_Protobuf_BeginCatch {
12131213
public init() {}
12141214
}
12151215

1216+
public struct Fuzzilli_Protobuf_BeginFinally {
1217+
// SwiftProtobuf.Message conformance is added in an extension below. See the
1218+
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
1219+
// methods supported on all messages.
1220+
1221+
public var unknownFields = SwiftProtobuf.UnknownStorage()
1222+
1223+
public init() {}
1224+
}
1225+
12161226
public struct Fuzzilli_Protobuf_EndTryCatch {
12171227
// SwiftProtobuf.Message conformance is added in an extension below. See the
12181228
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
@@ -3414,6 +3424,25 @@ extension Fuzzilli_Protobuf_BeginCatch: SwiftProtobuf.Message, SwiftProtobuf._Me
34143424
}
34153425
}
34163426

3427+
extension Fuzzilli_Protobuf_BeginFinally: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
3428+
public static let protoMessageName: String = _protobuf_package + ".BeginFinally"
3429+
public static let _protobuf_nameMap = SwiftProtobuf._NameMap()
3430+
3431+
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
3432+
while let _ = try decoder.nextFieldNumber() {
3433+
}
3434+
}
3435+
3436+
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
3437+
try unknownFields.traverse(visitor: &visitor)
3438+
}
3439+
3440+
public static func ==(lhs: Fuzzilli_Protobuf_BeginFinally, rhs: Fuzzilli_Protobuf_BeginFinally) -> Bool {
3441+
if lhs.unknownFields != rhs.unknownFields {return false}
3442+
return true
3443+
}
3444+
}
3445+
34173446
extension Fuzzilli_Protobuf_EndTryCatch: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
34183447
public static let protoMessageName: String = _protobuf_package + ".EndTryCatch"
34193448
public static let _protobuf_nameMap = SwiftProtobuf._NameMap()

0 commit comments

Comments
 (0)