diff --git a/compiler/vm.nim b/compiler/vm.nim index 0d53865027..7355e85fe1 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -495,18 +495,46 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = else: stackTrace(c, tos, pc, errNilAccess) of opcAddInt: decodeBC(rkInt) - regs[ra].intVal = regs[rb].intVal + regs[rc].intVal + let + bVal = regs[rb].intVal + cVal = regs[rc].intVal + sum = bVal +% cVal + if (sum xor bVal) >= 0 or (sum xor cVal) >= 0: + regs[ra].intVal = sum + else: + stackTrace(c, tos, pc, errOverOrUnderflow) of opcAddImmInt: decodeBImm(rkInt) #message(c.debug[pc], warnUser, "came here") #debug regs[rb].node - regs[ra].intVal = regs[rb].intVal + imm + let + bVal = regs[rb].intVal + cVal = imm + sum = bVal +% cVal + if (sum xor bVal) >= 0 or (sum xor cVal) >= 0: + regs[ra].intVal = sum + else: + stackTrace(c, tos, pc, errOverOrUnderflow) of opcSubInt: decodeBC(rkInt) - regs[ra].intVal = regs[rb].intVal - regs[rc].intVal + let + bVal = regs[rb].intVal + cVal = regs[rc].intVal + diff = bVal -% cVal + if (diff xor bVal) >= 0 or (diff xor not cVal) >= 0: + regs[ra].intVal = diff + else: + stackTrace(c, tos, pc, errOverOrUnderflow) of opcSubImmInt: decodeBImm(rkInt) - regs[ra].intVal = regs[rb].intVal - imm + let + bVal = regs[rb].intVal + cVal = imm + diff = bVal -% cVal + if (diff xor bVal) >= 0 or (diff xor not cVal) >= 0: + regs[ra].intVal = diff + else: + stackTrace(c, tos, pc, errOverOrUnderflow) of opcLenSeq: decodeBImm(rkInt) #assert regs[rb].kind == nkBracket @@ -539,7 +567,18 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = regs[ra].intVal = nimsets.cardSet(regs[rb].node) of opcMulInt: decodeBC(rkInt) - regs[ra].intVal = regs[rb].intVal * regs[rc].intVal + let + bVal = regs[rb].intVal + cVal = regs[rc].intVal + product = bVal *% cVal + floatProd = toBiggestFloat(bVal) * toBiggestFloat(cVal) + resAsFloat = toBiggestFloat(product) + if resAsFloat == floatProd: + regs[ra].intVal = product + elif 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd): + regs[ra].intVal = product + else: + stackTrace(c, tos, pc, errOverOrUnderflow) of opcDivInt: decodeBC(rkInt) if regs[rc].intVal == 0: stackTrace(c, tos, pc, errConstantDivisionByZero) @@ -632,7 +671,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcUnaryMinusInt: decodeB(rkInt) assert regs[rb].kind == rkInt - regs[ra].intVal = -regs[rb].intVal + let val = regs[rb].intVal + if val != int64.low: + regs[ra].intVal = -val + else: + stackTrace(c, tos, pc, errOverOrUnderflow) of opcUnaryMinusFloat: decodeB(rkFloat) assert regs[rb].kind == rkFloat diff --git a/lib/pure/events.nim b/lib/pure/events.nim index e76b846cf2..5830d9109e 100644 --- a/lib/pure/events.nim +++ b/lib/pure/events.nim @@ -68,7 +68,7 @@ proc clearHandlers*(handler: var TEventHandler) = ## Clears all of the callbacks from the event handler. setLen(handler.handlers, 0) -proc getEventhandler(emitter: var TEventEmitter, event: string): int = +proc getEventHandler(emitter: var TEventEmitter, event: string): int = for k in 0..high(emitter.s): if emitter.s[k].name == event: return k return -1 @@ -94,8 +94,6 @@ proc emit*(emitter: var TEventEmitter, event: string, args: TEventArgs) = var i = getEventHandler(emitter, event) if i >= 0: emit(emitter, emitter.s[i], args) - else: - raise newException(EInvalidEvent, "invalid event: " & event) proc initEventEmitter*(): TEventEmitter = ## Creates and returns a new EventEmitter. diff --git a/lib/wrappers/zip/zlib.nim b/lib/wrappers/zip/zlib.nim index f505b95a76..cb61783d25 100644 --- a/lib/wrappers/zip/zlib.nim +++ b/lib/wrappers/zip/zlib.nim @@ -182,3 +182,129 @@ proc zlibAllocMem*(AppData: Pointer, Items, Size: int): Pointer {.cdecl.} = proc zlibFreeMem*(AppData, `Block`: Pointer) {.cdecl.} = dealloc(`Block`) + +proc uncompress*(sourceBuf: cstring, sourceLen: int): string = + ## Given a deflated cstring returns its inflated version. + ## + ## Passing a nil cstring will crash this proc in release mode and assert in + ## debug mode. + ## + ## Returns nil on problems. Failure is a very loose concept, it could be you + ## passing a non deflated string, or it could mean not having enough memory + ## for the inflated version. + ## + ## The uncompression algorithm is based on + ## http://stackoverflow.com/questions/17820664 but does ignore some of the + ## original signed/unsigned checks, so may fail with big chunks of data + ## exceeding the positive size of an int32. The algorithm can deal with + ## concatenated deflated values properly. + assert (not sourceBuf.isNil) + + var z: TZStream + # Initialize input. + z.next_in = sourceBuf + + # Input left to decompress. + var left = zlib.Uint(sourceLen) + if left < 1: + # Incomplete gzip stream, or overflow? + return + + # Create starting space for output (guess double the input size, will grow if + # needed -- in an extreme case, could end up needing more than 1000 times the + # input size) + var space = zlib.Uint(left shl 1) + if space < left: + space = left + + var decompressed = newStringOfCap(space) + + # Initialize output. + z.next_out = addr(decompressed[0]) + # Output generated so far. + var have = 0 + + # Set up for gzip decoding. + z.avail_in = 0; + var status = inflateInit2(z, (15+16)) + if status != Z_OK: + # Out of memory. + return + + # Make sure memory allocated by inflateInit2() is freed eventually. + finally: discard inflateEnd(z) + + # Decompress all of self. + while true: + # Allow for concatenated gzip streams (per RFC 1952). + if status == Z_STREAM_END: + discard inflateReset(z) + + # Provide input for inflate. + if z.avail_in == 0: + # This only makes sense in the C version using unsigned values. + z.avail_in = left + left -= z.avail_in + + # Decompress the available input. + while true: + # Allocate more output space if none left. + if space == have: + # Double space, handle overflow. + space = space shl 1 + if space < have: + # Space was likely already maxed out. + discard inflateEnd(z) + return + + # Increase space. + decompressed.setLen(space) + # Update output pointer (might have moved). + z.next_out = addr(decompressed[have]) + + # Provide output space for inflate. + z.avail_out = zlib.Uint(space - have) + have += z.avail_out; + + # Inflate and update the decompressed size. + status = inflate(z, Z_SYNC_FLUSH); + have -= z.avail_out; + + # Bail out if any errors. + if status != Z_OK and status != Z_BUF_ERROR and status != Z_STREAM_END: + # Invalid gzip stream. + discard inflateEnd(z) + return + + # Repeat until all output is generated from provided input (note + # that even if z.avail_in is zero, there may still be pending + # output -- we're not done until the output buffer isn't filled) + if z.avail_out != 0: + break + # Continue until all input consumed. + if left == 0 and z.avail_in == 0: + break + + # Verify that the input is a valid gzip stream. + if status != Z_STREAM_END: + # Incomplete gzip stream. + return + + decompressed.setLen(have) + swap(result, decompressed) + + +proc inflate*(buffer: var string): bool {.discardable.} = + ## Convenience proc which inflates a string containing compressed data. + ## + ## Passing a nil string will crash this proc in release mode and assert in + ## debug mode. It is ok to pass a buffer which doesn't contain deflated data, + ## in this case the proc won't modify the buffer. + ## + ## Returns true if `buffer` was successfully inflated. + assert (not buffer.isNil) + if buffer.len < 1: return + var temp = uncompress(addr(buffer[0]), buffer.len) + if not temp.isNil: + swap(buffer, temp) + result = true diff --git a/tests/array/tarrayplus.nim b/tests/array/tarrayplus.nim index 9e08bbb0a1..0ea349f4f4 100644 --- a/tests/array/tarrayplus.nim +++ b/tests/array/tarrayplus.nim @@ -1,5 +1,5 @@ discard """ - errmsg: "type mismatch: got (array[0..2, float], array[0..1, float])" + errormsg: "type mismatch: got (array[0..2, float], array[0..1, float])" """ proc `+`*[R, T] (v1, v2: array[R, T]): array[R, T] = diff --git a/tests/generics/tbadgenericlambda.nim b/tests/generics/tbadgenericlambda.nim index 38e7f6cd73..2ab8e724db 100644 --- a/tests/generics/tbadgenericlambda.nim +++ b/tests/generics/tbadgenericlambda.nim @@ -1,5 +1,5 @@ discard """ - errmsg: "nested proc can have generic parameters only when" + errormsg: "nested proc can have generic parameters only when" line: 6 """ diff --git a/tests/generics/tmetafield.nim b/tests/generics/tmetafield.nim index 8e7f265494..f2fac8fdd6 100644 --- a/tests/generics/tmetafield.nim +++ b/tests/generics/tmetafield.nim @@ -1,8 +1,8 @@ discard """ cmd: "nimrod check $# $#" - errmsg: "'proc' is not a concrete type" - errmsg: "'Foo' is not a concrete type." - errmsg: "invalid type: 'TBaseMed'" + errormsg: "'proc' is not a concrete type" + errormsg: "'Foo' is not a concrete type." + errormsg: "invalid type: 'TBaseMed'" """ type diff --git a/tests/showoff/tdrdobbs_examples.nim b/tests/showoff/tdrdobbs_examples.nim index 0b3d86a05c..8a39990ba5 100644 --- a/tests/showoff/tdrdobbs_examples.nim +++ b/tests/showoff/tdrdobbs_examples.nim @@ -1,7 +1,7 @@ discard """ output: '''108 11 -1 1936 -4.0000000000000002e-001 +4.0000000000000002e-01 true truefalse''' """ diff --git a/tests/vm/toverflowopcaddimmint.nim b/tests/vm/toverflowopcaddimmint.nim new file mode 100644 index 0000000000..c36b9ed9b3 --- /dev/null +++ b/tests/vm/toverflowopcaddimmint.nim @@ -0,0 +1,11 @@ +discard """ + errormsg: "over- or underflow" +""" + +static: + proc p = + var + x = int64.high + discard x + 1 + assert false + p() diff --git a/tests/vm/toverflowopcaddint.nim b/tests/vm/toverflowopcaddint.nim new file mode 100644 index 0000000000..6d96afc78b --- /dev/null +++ b/tests/vm/toverflowopcaddint.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: "over- or underflow" +""" + +static: + proc p = + var + x = int64.high + y = 1 + discard x + y + assert false + p() diff --git a/tests/vm/toverflowopcmulint.nim b/tests/vm/toverflowopcmulint.nim new file mode 100644 index 0000000000..81b3234bad --- /dev/null +++ b/tests/vm/toverflowopcmulint.nim @@ -0,0 +1,11 @@ +discard """ + errormsg: "over- or underflow" +""" + +static: + proc p = + var + x = 1 shl 62 + discard x * 2 + assert false + p() diff --git a/tests/vm/toverflowopcsubimmint.nim b/tests/vm/toverflowopcsubimmint.nim new file mode 100644 index 0000000000..09d6f745bc --- /dev/null +++ b/tests/vm/toverflowopcsubimmint.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "over- or underflow" +""" + +static: + proc p = + var x = int64.low + discard x - 1 + assert false + p() diff --git a/tests/vm/toverflowopcsubint.nim b/tests/vm/toverflowopcsubint.nim new file mode 100644 index 0000000000..8d114f200e --- /dev/null +++ b/tests/vm/toverflowopcsubint.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: "over- or underflow" +""" + +static: + proc p = + var + x = int64.low + y = 1 + discard x - y + assert false + p()