# Procedures dealing with serialization from/to libFuzzer's input buffer. Since the custom # mutator is in control of the process, there should be no errors. And if there are, they # should be fatal and the code should be fixed. User may also run the fuzzer without any # sanitizer, which means that errors should always be detected. import std/[options, tables, sets, macros] from typetraits import supportsCopyMem, distinctBase template getFieldValue(mFunc, tmpSym, fieldSym) = mFunc(tmpSym.fieldSym) template getKindValue(mFunc, tmpSym, kindSym) = var kindTmp = tmpSym.kindSym mFunc(kindTmp) {.cast(uncheckedAssign).}: tmpSym.kindSym = kindTmp proc foldObjectBody(tmpSym, typeNode, mFunc: NimNode): NimNode = case typeNode.kind of nnkEmpty: result = newNimNode(nnkNone) of nnkRecList: result = newStmtList() for it in typeNode: let x = foldObjectBody(tmpSym, it, mFunc) if x.kind != nnkNone: result.add x of nnkIdentDefs: expectLen(typeNode, 3) let fieldSym = typeNode[0] result = getAst(getFieldValue(mFunc, tmpSym, fieldSym)) of nnkRecCase: let kindSym = typeNode[0][0] result = newStmtList(getAst(getKindValue(mFunc, tmpSym, kindSym))) let inner = nnkCaseStmt.newTree(nnkDotExpr.newTree(tmpSym, kindSym)) for i in 1.. data.len: raiseEncoding() else: copyMem(data[pos].addr, buffer, bufLen) inc(pos, bufLen) proc write*[T](data: var openArray[byte], pos: var int, input: T) = writeData(data, pos, input.unsafeAddr, sizeof(input)) proc readData*(data: openArray[byte], pos: var int, buffer: pointer, bufLen: int): int = result = min(bufLen, data.len - pos) if result > 0: copyMem(buffer, data[pos].unsafeAddr, result) inc(pos, result) else: result = 0 proc read*[T](data: openArray[byte], pos: var int, output: var T) = if readData(data, pos, output.addr, sizeof(output)) != sizeof(output): raiseDecoding() proc readChar*(data: openArray[byte], pos: var int): char {.inline.} = read(data, pos, result) proc readBool*(data: openArray[byte], pos: var int): bool {.inline.} = read(data, pos, result) proc readInt8*(data: openArray[byte], pos: var int): int8 {.inline.} = read(data, pos, result) proc readInt16*(data: openArray[byte], pos: var int): int16 {.inline.} = read(data, pos, result) proc readInt32*(data: openArray[byte], pos: var int): int32 {.inline.} = read(data, pos, result) proc readInt64*(data: openArray[byte], pos: var int): int64 {.inline.} = read(data, pos, result) proc readUint8*(data: openArray[byte], pos: var int): uint8 {.inline.} = read(data, pos, result) proc readUint16*(data: openArray[byte], pos: var int): uint16 {.inline.} = read(data, pos, result) proc readUint32*(data: openArray[byte], pos: var int): uint32 {.inline.} = read(data, pos, result) proc readUint64*(data: openArray[byte], pos: var int): uint64 {.inline.} = read(data, pos, result) proc readFloat32*(data: openArray[byte], pos: var int): float32 {.inline.} = read(data, pos, result) proc readFloat64*(data: openArray[byte], pos: var int): float64 {.inline.} = read(data, pos, result) proc fromData*(data: openArray[byte]; pos: var int; output: var string) proc fromData*[S, T](data: openArray[byte]; pos: var int; output: var array[S, T]) proc fromData*[T](data: openArray[byte]; pos: var int; output: var seq[T]) proc fromData*[T](data: openArray[byte]; pos: var int; output: var SomeSet[T]) proc fromData*[K, V](data: openArray[byte]; pos: var int; output: var (Table[K, V]|OrderedTable[K, V])) proc fromData*[T](data: openArray[byte]; pos: var int; output: var ref T) proc fromData*[T](data: openArray[byte]; pos: var int; output: var Option[T]) proc fromData*[T: tuple](data: openArray[byte]; pos: var int; output: var T) proc fromData*[T: object](data: openArray[byte]; pos: var int; output: var T) {.nodestroy.} proc fromData*[T: distinct](data: openArray[byte]; pos: var int; output: var T) {.inline.} proc toData*(data: var openArray[byte]; pos: var int; input: string) proc toData*[S, T](data: var openArray[byte]; pos: var int; input: array[S, T]) proc toData*[T](data: var openArray[byte]; pos: var int; input: seq[T]) proc toData*[T](data: var openArray[byte]; pos: var int; input: SomeSet[T]) proc toData*[K, V](data: var openArray[byte]; pos: var int; input: (Table[K, V]|OrderedTable[K, V])) proc toData*[T](data: var openArray[byte]; pos: var int; input: ref T) proc toData*[T](data: var openArray[byte]; pos: var int; input: Option[T]) proc toData*[T: tuple](data: var openArray[byte]; pos: var int; input: T) proc toData*[T: object](data: var openArray[byte]; pos: var int; input: T) proc toData*[T: distinct](data: var openArray[byte]; pos: var int; input: T) {.inline.} proc toData*(data: var openArray[byte]; pos: var int; input: bool) = write(data, pos, input) proc fromData*(data: openArray[byte]; pos: var int; output: var bool) = read(data, pos, output) proc toData*(data: var openArray[byte]; pos: var int; input: char) = write(data, pos, input) proc fromData*(data: openArray[byte]; pos: var int; output: var char) = read(data, pos, output) proc toData*[T: SomeNumber](data: var openArray[byte]; pos: var int; input: T) = write(data, pos, input) proc fromData*[T: SomeNumber](data: openArray[byte]; pos: var int; output: var T) = read(data, pos, output) proc toData*[T: enum](data: var openArray[byte]; pos: var int; input: T) = write(data, pos, input) proc fromData*[T: enum](data: openArray[byte]; pos: var int; output: var T) = read(data, pos, output) proc toData*[T](data: var openArray[byte]; pos: var int; input: set[T]) = write(data, pos, input) proc fromData*[T](data: openArray[byte]; pos: var int; output: var set[T]) = read(data, pos, output) proc toData*(data: var openArray[byte]; pos: var int; input: string) = write(data, pos, int32(input.len)) writeData(data, pos, cstring(input), input.len) proc fromData*(data: openArray[byte]; pos: var int; output: var string) = let len = readInt32(data, pos).int output.setLen(len) if readData(data, pos, cstring(output), len) != len: raiseDecoding() proc toData*[S, T](data: var openArray[byte]; pos: var int; input: array[S, T]) = when supportsCopyMem(T): writeData(data, pos, input.unsafeAddr, sizeof(input)) else: for elem in input.items: toData(data, pos, elem) proc fromData*[S, T](data: openArray[byte]; pos: var int; output: var array[S, T]) = when supportsCopyMem(T): if readData(data, pos, output.addr, sizeof(output)) != sizeof(output): raiseDecoding() else: for i in low(output)..high(output): fromData(data, pos, output[i]) proc toData*[T](data: var openArray[byte]; pos: var int; input: seq[T]) = write(data, pos, int32(input.len)) when supportsCopyMem(T): if input.len > 0: writeData(data, pos, input[0].unsafeAddr, input.len * sizeof(T)) else: for elem in input.items: toData(data, pos, elem) proc fromData*[T](data: openArray[byte]; pos: var int; output: var seq[T]) = let len = readInt32(data, pos).int output.setLen(len) when supportsCopyMem(T): if len > 0: let bLen = len * sizeof(T) if readData(data, pos, output[0].addr, bLen) != bLen: raiseDecoding() else: for i in 0..