nim-lang / Nim

Nim is a statically typed compiled systems programming language. It combines successful concepts from mature languages like Python, Ada and Modula. Its design focuses on efficiency, expressiveness, and elegance (in that order of priority).
https://nim-lang.org
Other
16.23k stars 1.46k forks source link

VM value out of range only with --cpu:arm #18646

Closed ajusa closed 2 years ago

ajusa commented 2 years ago

Nim VM has value out of range when raising 2^31 and --cpu:arm

Example

import math
const a: uint32 = (2 ^ 31).uint32

Current Output

stack trace: (most recent call last)
/home/ajusa/Documents/tmp/hid.nim(2, 22)
/home/ajusa/.choosenim/toolchains/nim-#devel/lib/pure/math.nim(1112, 16) ^
/home/ajusa/.choosenim/toolchains/nim-#devel/lib/system/arithmetics.nim(468, 9) *=
/home/ajusa/.choosenim/toolchains/nim-#devel/lib/system/arithmetics.nim(468, 9) Error: unhandled exception: value out of range

Expected Output

(Blank, since this should compile correctly). It does compile correctly without --cpu:arm

Additional Information

I think that 2^30 works just fine, it was 2^31 that gave me an issue in the project I am working on.

$ nim -v
Nim Compiler Version 1.5.1 [Linux: amd64]
Compiled at 2021-08-04
Copyright (c) 2006-2021 by Andreas Rumpf

git hash: 6563a685c1076cb5342f65d192b8f2a983220dba
active boot switches: -d:release

Also had the same issue on Nim 1.4.4, shouldn't be a regression.

demotomohiro commented 2 years ago

I don't think this is a bug.

With --cc:arm option, sizeof(int) become 4 bytes and it seems sizeof(int) in VM also become 4 bytes. Type of literals 2 and 31 in your code is int type. Expression 2 ^ 31 calls ^ operator defined in math module with the first argument as int type and calculate the result as int type. 2 ^ 31 cannot be represent with 32bit signed int value. (2 ^ 63 cannot be repesent with 64bit signed int value and echo (2 ^ 63).uint64 cause overflow error on 64bit CPU)

Following code result in overflow on my raspberry pi3:

import std/math

static:
  echo hostCPU

echo "sizeof int:", sizeof(int)
echo 2^31

output:

[alarm@rasp proj]$ nim c intsizetest.nim
Hint: used config file '/home/alarm/src/nim-1.5.1/config/nim.cfg' [Conf]
Hint: used config file '/home/alarm/src/nim-1.5.1/config/config.nims' [Conf]
.............................................................
arm
CC: intsizetest.nim
Hint:  [Link]
Hint: gc: refc; opt: none (DEBUG BUILD, `-d:release` generates faster code)
30551 lines; 2.312s; 25.977MiB peakmem; proj: /home/alarm/proj/intsizetest.nim; out: /home/alarm/proj/intsizetest [SuccessX]
[alarm@rasp proj]$ ./intsizetest
sizeof int:4
/home/alarm/proj/intsizetest.nim(7) intsizetest
/home/alarm/src/nim-1.5.1/lib/pure/math.nim(1112) ^
/home/alarm/src/nim-1.5.1/lib/system/arithmetics.nim(468) *=
/home/alarm/src/nim-1.5.1/lib/system/fatal.nim(53) sysFatal
Error: unhandled exception: over- or underflow [OverflowDefect]

When I write the expression as first argument is uint32 type like 2.uint32 ^ 31, it works without overflow on my raspberry pi 3.

ajusa commented 2 years ago

2.uint32 ^ 31

I see, that would explain the issue along with the correct way of doing things. I was unaware that setting the CPU to arm makes integers 32bit, including in the VM. Closing :smile: