Skip to content

Commit

Permalink
implemented bigint support
Browse files Browse the repository at this point in the history
  • Loading branch information
carl-smith authored and Samuel Groß committed Jun 30, 2020
1 parent fde8373 commit f8f43cb
Show file tree
Hide file tree
Showing 17 changed files with 175 additions and 55 deletions.
16 changes: 10 additions & 6 deletions Sources/Fuzzilli/Core/CodeGenerators.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ public func IntegerLiteralGenerator(_ b: ProgramBuilder) {
b.loadInt(b.genInt())
}

public func BigIntLiteralGenerator(_ b: ProgramBuilder) {
b.loadBigInt(b.genInt())
}

public func FloatLiteralGenerator(_ b: ProgramBuilder) {
b.loadFloat(b.genFloat())
}
Expand Down Expand Up @@ -325,7 +329,7 @@ public func IfStatementGenerator(_ b: ProgramBuilder) {

public func WhileLoopGenerator(_ b: ProgramBuilder) {
let start = b.loadInt(0)
let end = b.loadInt(Int.random(in: 0...10))
let end = b.loadInt(Int64.random(in: 0...10))
let loopVar = b.phi(start)
b.whileLoop(loopVar, .lessThan, end) {
b.generate()
Expand All @@ -336,7 +340,7 @@ public func WhileLoopGenerator(_ b: ProgramBuilder) {

public func DoWhileLoopGenerator(_ b: ProgramBuilder) {
let start = b.loadInt(0)
let end = b.loadInt(Int.random(in: 0...10))
let end = b.loadInt(Int64.random(in: 0...10))
let loopVar = b.phi(start)
b.doWhileLoop(loopVar, .lessThan, end) {
b.generate()
Expand All @@ -347,7 +351,7 @@ public func DoWhileLoopGenerator(_ b: ProgramBuilder) {

public func ForLoopGenerator(_ b: ProgramBuilder) {
let start = b.loadInt(0)
let end = b.loadInt(Int.random(in: 0...10))
let end = b.loadInt(Int64.random(in: 0...10))
let step = b.loadInt(1)
b.forLoop(start, .lessThan, end, .Add, step) { _ in
b.generate()
Expand Down Expand Up @@ -403,7 +407,7 @@ public func ThrowGenerator(_ b: ProgramBuilder) {
//

public func TypedArrayGenerator(_ b: ProgramBuilder) {
let size = b.loadInt(Int.random(in: 0...0x10000))
let size = b.loadInt(Int64.random(in: 0...0x10000))
let constructor = b.loadBuiltin(chooseUniform(from: ["Uint8Array", "Int8Array", "Uint16Array", "Int16Array", "Uint32Array", "Int32Array", "Float32Array", "Float64Array", "Uint8ClampedArray", "DataView"]))
b.construct(constructor, withArgs: [size])
}
Expand Down Expand Up @@ -499,7 +503,7 @@ public func LengthChangeGenerator(_ b: ProgramBuilder) {
let target = b.randVar(ofType: .object())
let newLength: Variable
if probability(0.5) {
newLength = b.loadInt(Int.random(in: 0..<3))
newLength = b.loadInt(Int64.random(in: 0..<3))
} else {
newLength = b.loadInt(b.genIndex())
}
Expand All @@ -510,7 +514,7 @@ public func LengthChangeGenerator(_ b: ProgramBuilder) {
public func ElementKindChangeGenerator(_ b: ProgramBuilder) {
let target = b.randVar(ofType: .object())
let value = b.randVar()
b.storeElement(value, at: Int.random(in: 0..<3), of: target)
b.storeElement(value, at: Int64.random(in: 0..<3), of: target)
}

// Generates a JavaScript 'with' statement
Expand Down
5 changes: 4 additions & 1 deletion Sources/Fuzzilli/Core/Environment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
/// Model of the execution environment.
public protocol Environment: Component {
/// List of integer values that might yield interesting behaviour or trigger edge cases in the target language.
var interestingIntegers: [Int] { get }
var interestingIntegers: [Int64] { get }

/// List of floating point values that might yield interesting behaviour or trigger edge cases in the target language.
var interestingFloats: [Double] { get }
Expand All @@ -42,6 +42,9 @@ public protocol Environment: Component {

/// The type representing integers in the target environment.
var intType: Type { get }

/// The type representing bigints in the target environment.
var bigIntType: Type { get }

/// The type representing floats in the target environment.
var floatType: Type { get }
Expand Down
25 changes: 22 additions & 3 deletions Sources/Fuzzilli/Core/JavaScriptEnvironment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@

public class JavaScriptEnvironment: ComponentBase, Environment {
// Possible return values of the 'typeof' operator.
public static let jsTypeNames = ["undefined", "boolean", "number", "string", "symbol", "function", "object"]
public static let jsTypeNames = ["undefined", "boolean", "number", "string", "symbol", "function", "object", "bigint"]

// Integer values that are more likely to trigger edge-cases.
public let interestingIntegers = [-9007199254740993, -9007199254740992, -9007199254740991, // Smallest integer value that is still precisely representable by a double
public let interestingIntegers: [Int64] = [-9007199254740993, -9007199254740992, -9007199254740991, // Smallest integer value that is still precisely representable by a double
-4294967297, -4294967296, -4294967295, // Negative Uint32 max
-2147483649, -2147483648, -2147483647, // Int32 min
-1073741824, -536870912, -268435456, // -2**32 / {4, 8, 16}
Expand All @@ -41,6 +41,7 @@ public class JavaScriptEnvironment: ComponentBase, Environment {
public let interestingStrings = jsTypeNames

public var intType = Type.integer
public var bigIntType = Type.bigint
public var floatType = Type.float
public var booleanType = Type.boolean
public var stringType = Type.jsString
Expand Down Expand Up @@ -91,6 +92,7 @@ public class JavaScriptEnvironment: ComponentBase, Environment {
registerObjectGroup(.jsArrayConstructor)
registerObjectGroup(.jsStringConstructor)
registerObjectGroup(.jsSymbolConstructor)
registerObjectGroup(.jsBigIntConstructor)
registerObjectGroup(.jsBooleanConstructor)
registerObjectGroup(.jsNumberConstructor)
registerObjectGroup(.jsMathObject)
Expand All @@ -112,6 +114,7 @@ public class JavaScriptEnvironment: ComponentBase, Environment {
registerBuiltin("Boolean", ofType: .jsBooleanConstructor)
registerBuiltin("Number", ofType: .jsNumberConstructor)
registerBuiltin("Symbol", ofType: .jsSymbolConstructor)
registerBuiltin("BigInt", ofType: .jsBigIntConstructor)
registerBuiltin("RegExp", ofType: .jsRegExpConstructor)
registerBuiltin("ArrayBuffer", ofType: .jsArrayBufferConstructor)
for variant in ["Uint8Array", "Int8Array", "Uint16Array", "Int16Array", "Uint32Array", "Int32Array", "Float32Array", "Float64Array", "Uint8ClampedArray"] {
Expand Down Expand Up @@ -258,7 +261,7 @@ public extension Type {

/// Type of a JavaScript Symbol.
static let jsSymbol = Type.object(ofGroup: "Symbol", withProperties: ["__proto__", "description"])

/// Type of a plain JavaScript object.
static let jsPlainObject = Type.object(ofGroup: "Object", withProperties: ["__proto__"])

Expand Down Expand Up @@ -314,6 +317,9 @@ public extension Type {

/// Type of the JavaScript Symbol constructor builtin.
static let jsSymbolConstructor = Type.function([.string] => .jsSymbol) + .object(ofGroup: "SymbolConstructor", withProperties: ["iterator", "asyncIterator", "match", "matchAll", "replace", "search", "split", "hasInstance", "isConcatSpreadable", "unscopable", "species", "toPrimitive", "toStringTag"], withMethods: ["for", "keyFor"])

/// Type of the JavaScript BigInt constructor builtin.
static let jsBigIntConstructor = Type.function([.number] => .bigint) + .object(ofGroup: "BigIntConstructor", withProperties: ["prototype"], withMethods: ["asIntN", "asUintN"])

/// Type of the JavaScript RegExp constructor builtin.
static let jsRegExpConstructor = Type.jsFunction([.string] => .object())
Expand Down Expand Up @@ -763,6 +769,19 @@ public extension ObjectGroup {
"keyFor" : [.jsSymbol] => .jsString,
]
)

/// Object group modelling the JavaScript BigInt constructor builtin
static let jsBigIntConstructor = ObjectGroup(
name: "BigIntConstructor",
instanceType: .jsBigIntConstructor,
properties: [
"prototype" : .object()
],
methods: [
"asIntN" : [.number, .bigint] => .bigint,
"asUintN" : [.number, .bigint] => .bigint,
]
)

/// Object group modelling the JavaScript Boolean constructor builtin
static let jsBooleanConstructor = ObjectGroup(
Expand Down
23 changes: 15 additions & 8 deletions Sources/Fuzzilli/Core/ProgramBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class ProgramBuilder {

/// Property names and integer values previously seen in the current program.
private var seenPropertyNames = Set<String>()
private var seenIntegers = Set<Int>()
private var seenIntegers = Set<Int64>()

/// The program currently being constructed.
private var program = Program()
Expand Down Expand Up @@ -57,21 +57,21 @@ public class ProgramBuilder {


/// Generates a random integer for the current program context.
public func genInt() -> Int {
public func genInt() -> Int64 {
// Either pick a previously seen integer or generate a random one
if probability(0.15) && seenIntegers.count >= 2 {
return chooseUniform(from: seenIntegers)
} else {
return withEqualProbability({
chooseUniform(from: self.fuzzer.environment.interestingIntegers)
}, {
Int.random(in: -0x100000000...0x100000000)
Int64.random(in: -0x100000000...0x100000000)
})
}
}

/// Generates a random index value for the current program context.
public func genIndex() -> Int {
public func genIndex() -> Int64 {
return genInt()
}

Expand Down Expand Up @@ -365,9 +365,14 @@ public class ProgramBuilder {
}

@discardableResult
public func loadInt(_ value: Int) -> Variable {
public func loadInt(_ value: Int64) -> Variable {
return perform(LoadInteger(value: value)).output
}

@discardableResult
public func loadBigInt(_ value: Int64) -> Variable {
return perform(LoadBigInt(value: value)).output
}

@discardableResult
public func loadFloat(_ value: Double) -> Variable {
Expand Down Expand Up @@ -434,15 +439,15 @@ public class ProgramBuilder {
}

@discardableResult
public func loadElement(_ index: Int, of array: Variable) -> Variable {
public func loadElement(_ index: Int64, of array: Variable) -> Variable {
return perform(LoadElement(index: index), withInputs: [array]).output
}

public func storeElement(_ value: Variable, at index: Int, of array: Variable) {
public func storeElement(_ value: Variable, at index: Int64, of array: Variable) {
perform(StoreElement(index: index), withInputs: [array, value])
}

public func deleteElement(_ index: Int, of array: Variable) {
public func deleteElement(_ index: Int64, of array: Variable) {
perform(DeleteElement(index: index), withInputs: [array])
}

Expand Down Expand Up @@ -739,6 +744,8 @@ public class ProgramBuilder {
switch operation {
case let op as LoadInteger:
seenIntegers.insert(op.value)
case let op as LoadBigInt:
seenIntegers.insert(op.value)
case let op as LoadProperty:
seenPropertyNames.insert(op.propertyName)
case let op as StoreProperty:
Expand Down
7 changes: 5 additions & 2 deletions Sources/Fuzzilli/FuzzIL/AbstractInterpreter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ public struct AbstractInterpreter {
case is LoadInteger:
set(instr.output, environment.intType)

case is LoadBigInt:
set(instr.output, environment.bigIntType)

case is LoadFloat:
set(instr.output, environment.floatType)

Expand Down Expand Up @@ -287,14 +290,14 @@ public struct AbstractInterpreter {
.Exp,
.Div,
.Mod:
set(instr.output, .number)
set(instr.output, .number | .bigint)
case .BitAnd,
.BitOr,
.Xor,
.LShift,
.RShift,
.UnRShift:
set(instr.output, .integer)
set(instr.output, .integer | .bigint)
case .LogicAnd,
.LogicOr:
set(instr.output, .boolean)
Expand Down
20 changes: 12 additions & 8 deletions Sources/Fuzzilli/FuzzIL/Instruction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,9 @@ extension Instruction: ProtobufConvertible {
case is Nop:
$0.nop = Fuzzilli_Protobuf_Nop()
case let op as LoadInteger:
$0.loadInteger = Fuzzilli_Protobuf_LoadInteger.with { $0.value = Int64(op.value) }
$0.loadInteger = Fuzzilli_Protobuf_LoadInteger.with { $0.value = op.value }
case let op as LoadBigInt:
$0.loadBigInt = Fuzzilli_Protobuf_LoadBigInt.with { $0.value = op.value }
case let op as LoadFloat:
$0.loadFloat = Fuzzilli_Protobuf_LoadFloat.with { $0.value = op.value }
case let op as LoadString:
Expand Down Expand Up @@ -288,11 +290,11 @@ extension Instruction: ProtobufConvertible {
case let op as DeleteProperty:
$0.deleteProperty = Fuzzilli_Protobuf_DeleteProperty.with { $0.propertyName = op.propertyName }
case let op as LoadElement:
$0.loadElement = Fuzzilli_Protobuf_LoadElement.with { $0.index = Int64(op.index) }
$0.loadElement = Fuzzilli_Protobuf_LoadElement.with { $0.index = op.index }
case let op as StoreElement:
$0.storeElement = Fuzzilli_Protobuf_StoreElement.with { $0.index = Int64(op.index) }
$0.storeElement = Fuzzilli_Protobuf_StoreElement.with { $0.index = op.index }
case let op as DeleteElement:
$0.deleteElement = Fuzzilli_Protobuf_DeleteElement.with { $0.index = Int64(op.index) }
$0.deleteElement = Fuzzilli_Protobuf_DeleteElement.with { $0.index = op.index }
case is LoadComputedProperty:
$0.loadComputedProperty = Fuzzilli_Protobuf_LoadComputedProperty()
case is StoreComputedProperty:
Expand Down Expand Up @@ -441,7 +443,9 @@ extension Instruction: ProtobufConvertible {
}
op = cachedOp
case .loadInteger(let p):
op = LoadInteger(value: Int(clamping: p.value))
op = LoadInteger(value: p.value)
case .loadBigInt(let p):
op = LoadBigInt(value: p.value)
case .loadFloat(let p):
op = LoadFloat(value: p.value)
case .loadString(let p):
Expand Down Expand Up @@ -469,11 +473,11 @@ extension Instruction: ProtobufConvertible {
case .deleteProperty(let p):
op = DeleteProperty(propertyName: p.propertyName)
case .loadElement(let p):
op = LoadElement(index: Int(clamping: p.index))
op = LoadElement(index: p.index)
case .storeElement(let p):
op = StoreElement(index: Int(clamping: p.index))
op = StoreElement(index: p.index)
case .deleteElement(let p):
op = DeleteElement(index: Int(clamping: p.index))
op = DeleteElement(index: p.index)
case .loadComputedProperty(_):
op = LoadComputedProperty()
case .storeComputedProperty(_):
Expand Down
26 changes: 18 additions & 8 deletions Sources/Fuzzilli/FuzzIL/Operations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,19 @@ class Nop: Operation {
}

class LoadInteger: Operation {
let value: Int
let value: Int64

init(value: Int) {
init(value: Int64) {
self.value = value
super.init(numInputs: 0, numOutputs: 1, attributes: [.isPrimitive, .isParametric, .isLiteral])
}
}

class LoadBigInt: Operation {
// This could be a bigger integer type, but it's most likely not worth the effort
let value: Int64

init(value: Int64) {
self.value = value
super.init(numInputs: 0, numOutputs: 1, attributes: [.isPrimitive, .isParametric, .isLiteral])
}
Expand Down Expand Up @@ -208,27 +218,27 @@ class DeleteProperty: Operation {
}

class LoadElement: Operation {
let index: Int
let index: Int64

init(index: Int) {
init(index: Int64) {
self.index = index
super.init(numInputs: 1, numOutputs: 1, attributes: [.isParametric])
}
}

class StoreElement: Operation {
let index: Int
let index: Int64

init(index: Int) {
init(index: Int64) {
self.index = index
super.init(numInputs: 2, numOutputs: 0, attributes: [.isParametric])
}
}

class DeleteElement: Operation {
let index: Int
let index: Int64

init(index: Int) {
init(index: Int64) {
self.index = index
super.init(numInputs: 1, numOutputs: 0, attributes: [.isParametric])
}
Expand Down
Loading

0 comments on commit f8f43cb

Please sign in to comment.