diff --git a/lib/system/arithmetics.nim b/lib/system/arithmetics.nim index 5711004822..b2e4e41720 100644 --- a/lib/system/arithmetics.nim +++ b/lib/system/arithmetics.nim @@ -306,15 +306,15 @@ proc `mod`*(x, y: uint32): uint32 {.magic: "ModU", noSideEffect.} proc `mod`*(x, y: uint64): uint64 {.magic: "ModU", noSideEffect.} proc `+=`*[T: SomeInteger](x: var T, y: T) {. - magic: "Inc", noSideEffect.} + magic: "Inc", noSideEffect, systemRaisesDefect.} ## Increments an integer. proc `-=`*[T: SomeInteger](x: var T, y: T) {. - magic: "Dec", noSideEffect.} + magic: "Dec", noSideEffect, systemRaisesDefect.} ## Decrements an integer. proc `*=`*[T: SomeInteger](x: var T, y: T) {. - inline, noSideEffect.} = + inline, noSideEffect, systemRaisesDefect.} = ## Binary `*=` operator for integers. x = x * y @@ -339,20 +339,22 @@ proc `+=`*[T: float|float32|float64] (x: var T, y: T) {. x = x + y proc `-=`*[T: float|float32|float64] (x: var T, y: T) {. - inline, noSideEffect.} = + inline, noSideEffect, systemRaisesDefect.} = ## Decrements in place a floating point number. x = x - y proc `*=`*[T: float|float32|float64] (x: var T, y: T) {. - inline, noSideEffect.} = + inline, noSideEffect, systemRaisesDefect.} = ## Multiplies in place a floating point number. x = x * y -proc `/=`*(x: var float64, y: float64) {.inline, noSideEffect.} = +proc `/=`*(x: var float64, y: float64) {. + inline, noSideEffect, systemRaisesDefect.} = ## Divides in place a floating point number. x = x / y -proc `/=`*[T: float|float32](x: var T, y: T) {.inline, noSideEffect.} = +proc `/=`*[T: float|float32](x: var T, y: T) {. + inline, noSideEffect, systemRaisesDefect.} = ## Divides in place a floating point number. x = x / y diff --git a/tests/stdlib/tmisc_issues.nim b/tests/stdlib/tmisc_issues.nim index 4f7707d976..18dea064cf 100644 --- a/tests/stdlib/tmisc_issues.nim +++ b/tests/stdlib/tmisc_issues.nim @@ -64,3 +64,120 @@ block: # bug #24683 cast[ptr int](addr x)[] = 10 doAssert x == @[1, 2, 3, 4, 45, 56, 67, 999, 88, 777] + +when not defined(js): + block: + var x = high int + var result = x + + # assert that multiplying highest int by highest int overflows + + doAssertRaises(OverflowDefect): + x *= x + + doAssertRaises(OverflowDefect): + result *= x + + # overflow via compound assignment on int + var a = high(int) + doAssertRaises(OverflowDefect): + a += 1 + + var b = low(int) + doAssertRaises(OverflowDefect): + b -= 1 + + var c = high(int) + doAssertRaises(OverflowDefect): + c *= 2 + + # add smaller signed types too + var a8 = high(int8) + doAssertRaises(OverflowDefect): + a8 += 1 + + var b8 = low(int8) + doAssertRaises(OverflowDefect): + b8 -= 1 + + var c8 = high(int8) + doAssertRaises(OverflowDefect): + c8 *= 2 + + var a16 = high(int16) + doAssertRaises(OverflowDefect): + a16 += 1 + + var b16 = low(int16) + doAssertRaises(OverflowDefect): + b16 -= 1 + + # arithmetic operations that can overflow (non-compound direct ops) + doAssertRaises(OverflowDefect): + discard high(int) + 1 + + doAssertRaises(OverflowDefect): + discard low(int) - 1 + + doAssertRaises(OverflowDefect): + discard high(int) * 2 + + doAssertRaises(OverflowDefect): + discard low(int) div -1 + + # int8 overflow for signed operations + doAssertRaises(OverflowDefect): + discard high(int8) + 1'i8 + + doAssertRaises(OverflowDefect): + discard low(int8) - 1'i8 + + doAssertRaises(OverflowDefect): + discard high(int8) * 2'i8 + + # enum overflow, from arithmetics.succ/pred + type E = enum eA, eB + doAssertRaises(OverflowDefect): + discard eB.succ + doAssertRaises(OverflowDefect): + discard eA.pred + + # floating-point compound divide should produce inf (not raise by defect) + var f = 1.0 + f /= 0.0 + # 1.0/0.0 is inf, check not finite + #doAssert not f.isFinite # `isFinite` not in this context, but avoid crash + # simple check ensures it mutated to a very large value + # (in Nim, `inf` is represented as 1e300*1e300; this compares as true) + doAssert f == 1.0 / 0.0 + + # Additional overflow cases across various integer widths + doAssertRaises(OverflowDefect): + discard high(int32) + 1'i32 + + doAssertRaises(OverflowDefect): + discard low(int32) - 1'i32 + + doAssertRaises(OverflowDefect): + discard high(int64) + 1'i64 + + doAssertRaises(OverflowDefect): + discard low(int64) - 1'i64 + + doAssertRaises(OverflowDefect): + discard -low(int64) + + doAssertRaises(OverflowDefect): + discard abs(low(int8)) + + doAssertRaises(OverflowDefect): + discard high(int32) * 2'i32 + + doAssertRaises(OverflowDefect): + discard high(int64) * 2'i64 + + doAssertRaises(OverflowDefect): + discard low(int32) div -1'i32 + + doAssertRaises(OverflowDefect): + discard low(int64) div -1'i64