Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compiler crash when using case..of..else with huge ranges #8838

Closed
xomachine opened this issue Sep 1, 2018 · 3 comments
Closed

Compiler crash when using case..of..else with huge ranges #8838

xomachine opened this issue Sep 1, 2018 · 3 comments

Comments

@xomachine
Copy link
Contributor

Consider the example:

let x = 0'i64
case x
of 0'i64..1'i64: discard
of 2'i64..(int64.high-1): discard  # Causes the crash
#of 2'i64..(int64.high-2): discard # Works fine
else: discard

case x
of 0'i64..2'i64: discard
#of 3'i64..(int64.high-1): discard # Causes the crash
of 3'i64..(int64.high-2): discard  # Causes the crash as well
#of 3'i64..(int64.high-3): discard # Works fine
else: discard

This code causes the compiler crash on the devel branch with following error:

$ nim -v
Nim Compiler Version 0.18.1 [Linux: amd64]
Compiled at 2018-09-01
Copyright (c) 2006-2018 by Andreas Rumpf

git hash: d06da9ccf01d41d06849f890e2821b8e791535ac
active boot switches:
$ nim c test.nim
Hint: used config file '/home/xomachine/.Soft/projects/Nim/config/nim.cfg' [Conf]
Hint: system [Processing]
Hint: test [Processing]
nim.nim(107)             nim
nim.nim(71)              handleCmdLine
cmdlinehelper.nim(84)    loadConfigsAndRunMainCommand
main.nim(162)            mainCommand
main.nim(73)             commandCompileToC
modules.nim(124)         compileProject
modules.nim(71)          compileModule
passes.nim(194)          processModule
passes.nim(103)          processTopLevelStmt
sem.nim(592)             myProcess
sem.nim(560)             semStmtAndGenerateGenerics
semstmts.nim(1933)       semStmt
semexprs.nim(919)        semExprNoType
semexprs.nim(2539)       semExpr
semstmts.nim(759)        semCase
semtypes.nim(556)        semCaseBranch
semtypes.nim(534)        semCaseBranchRange
semtypes.nim(529)        semBranchRange
system.nim(2811)         sysFatal
Error: unhandled exception: over- or underflow [OverflowError]

But on tag 0.18.0 it works fine:

$ nim -v
Nim Compiler Version 0.18.0 [Linux: amd64]
Copyright (c) 2006-2018 by Andreas Rumpf

active boot switches: -d:release -d:nativeStackTrace
$ nim c test.nim
Hint: used config file '/etc/nim.cfg' [Conf]
Hint: system [Processing]
Hint: test [Processing]
CC: nesm_test
CC: stdlib_system
Hint:  [Link]
Hint: operation successful (11729 lines compiled; 0.986 sec total; 22.176MiB peakmem; Debug Build) [SuccessX]
@skilchen
Copy link
Contributor

skilchen commented Sep 2, 2018

Thats because you bootstrapped your current compiler without -d:release (i.e. you have overflow_checks:on) but the 0.18.0 one was probably bootstrapped with -d:release (overflow_checks:off).
.
IMHO the whole thing about ranges, ordinal types and the like is a highly dubious matter in Nim. I think, the fact that Nim inherits these things from Pascal is a design mistake.

One example of the problematic is the procedure lengthOrd in compiler/types.nim.

proc lengthOrd*(conf: ConfigRef; t: PType): BiggestInt =
  case t.skipTypes(tyUserTypeClasses).kind
  of tyInt64, tyInt32, tyInt: result = lastOrd(conf, t)
  of tyDistinct: result = lengthOrd(conf, t.sons[0])
  else:
    let last = lastOrd(conf, t)
    let first = firstOrd(conf, t)
    # XXX use a better overflow check here:
    if last == high(BiggestInt) and first <= 0:
      result = last
    else:
      result = last - first + 1

The length of the ordinals int64, int32, int is clearly not the high value of the corresponding type but rather the high value of the matching unsigned type + 1. (Now this is kind of a problem for int64 because Nim can't represent high(uint64) + 1, but Nim could detect this overflow and handle it gracefully, or simply ignore it as with check_overflow:off which causes no problems here).

When Nim tries to detect if you covered all possible values in a case statement it performs a last - first + 1 calculation which causes the overflow you are seeing in the reported compiler crash (which is one of the reasons why Pascal claimed that int64 is not true ordinal type and Nim seems to repeat this).

If you write the following pointless case statement:

let x = 0'i32
case x of
low(int32)..high(int32): discard

Nim will claim that you have not covered all cases, which is evidently nonsense. This is also a consequence of the buggy lengthOrd procedure mentioned above.

(Don't try to compile this for the js backend..., see #8821)

@Araq
Copy link
Member

Araq commented Sep 2, 2018

IMHO the whole thing about ranges, ordinal types and the like is a highly dubious matter in Nim. I think, the fact that Nim inherits these things from Pascal is a design mistake.

A documented limitation hardly qualifies as a design mistake. Be my guest and improve it.

@narimiran
Copy link
Member

Nim now (as of v0.20.99) internally has int128 and all the original examples now successfully compile.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants