Skip to content

SIGSEGV: Compiler emits unitialized variable in the string slice operator #23435

@gcr

Description

@gcr

Description

  • Nim version: v2.0.2, arm64-native version
  • OS: MacOS Sonoma 14.2.1

Inside proc [][Idx, T](a: var array[Idx, T]; i: BackwardsIndex): var T, codegen contains an unitialized variable. In the middle of signaling a range error, the caller crashes before the traceback can be fully printed by dereferencing the uninitialized result.

Here's a minimal example:

proc foo() =
  for _ in @[1, 3, 5]:
    discard "abcde"[25..<10]
    break
  echo "Passed"

when isMainModule:
  foo()

Nim Version

$ nim --version
Nim Compiler Version 2.0.2 [MacOSX: arm64]
Compiled at 2023-12-15
Copyright (c) 2006-2023 by Andreas Rumpf

active boot switches: -d:release -d:nimUseLinenoise

Current Output

$ nim c test
Hint: used config file '/opt/homebrew/Cellar/nim/2.0.2/nim/config/nim.cfg' [Conf]
Hint: used config file '/opt/homebrew/Cellar/nim/2.0.2/nim/config/config.nims' [Conf]
......................................................................
Hint:  [Link]
Hint: mm: orc; threads: on; opt: none (DEBUG BUILD, `-d:release` generates faster code)
27618 lines; 0.178s; 30.352MiB peakmem; proj: /private/tmp/stuff/test; out: /private/tmp/stuff/test [SuccessX]
$ file test
test: Mach-O 64-bit executable arm64
$ ./test
Traceback (most recent call last)
/private/tmp/stuff/test.nim(8) test
/opt/homebrew/Cellar/nim/2.0.2/nim/lib/system.nim(370) foo
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
fish: Job 1, './test' terminated by signal SIGSEGV (Address boundary error)

Expected Output

Should throw an unhandled exception, not SIGSEGV:

/private/tmp/stuff/test.nim(8) test
/private/tmp/stuff/test.nim(2) foo
/opt/homebrew/Cellar/nim/2.0.2/nim/lib/system/indices.nim(85) []
/opt/homebrew/Cellar/nim/2.0.2/nim/lib/system/fatal.nim(53) sysFatal
Error: unhandled exception: value out of range: -15 notin 0 .. 9223372036854775807 [RangeDefect]
Error: execution of an external program failed: '/Users/kimmy/.cache/nim/test_d/test_FFA6C1D31EF4FF0BF49E574367D1CFEF1CB99BEC'

Possible Solution

See my comment below about break.

Additional Information

Watching the crash from the debugger's view, we have:

$ nim c -c --nimcache:. test; cc -g *.c; lldb ./a.out
Hint: used config file '/opt/homebrew/Cellar/nim/2.0.2/nim/config/nim.cfg' [Conf]
Hint: used config file '/opt/homebrew/Cellar/nim/2.0.2/nim/config/config.nims' [Conf]
......................................................................
Hint: mm: orc; threads: on; opt: none (DEBUG BUILD, `-d:release` generates faster code)
27618 lines; 0.116s; 30.352MiB peakmem; proj: /private/tmp/stuff/test; out: /private/tmp/stuff/test.json [SuccessX]
(lldb) target create "./a.out"
Current executable set to '/private/tmp/stuff/a.out' (arm64).
(lldb) r
Process 67319 launched: '/private/tmp/stuff/a.out' (arm64)
Process 67319 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x9)
    frame #0: 0x000000010000e834 a.out`foo__test_u1 at @mtest.nim.c:285:112
   282 						LA6_:;
   283 					}
   284 					{
-> 285 						nimlf_(370, "/opt/homebrew/Cellar/nim/2.0.2/nim/lib/system.nim"); if (colontmpD_.p && !(colontmpD_.p->cap & NIM_STRLIT_FLAG)) {
   286 	 deallocShared(colontmpD_.p);
   287 	}
   288 					}
Target 0: (a.out) stopped.

At this point, colontmpD_ happens to contain the last thing in stack. Looks like some earlier slice object:

(lldb) p colontmpD_
(NimStringV2) {
  len = 25
  p = 0x0000000000000009
}
(lldb)

colontmpD_ originates from the codegen for proc [][Idx, T](a: var array[Idx, T]; i: BackwardsIndex): var T, called earlier. Ultimately, NimStringV2 result; is unitialized before the function returns prematurely to signal the range error:

static N_INLINE(NimStringV2, X5BX5D___test_u93)(NimStringV2 s_p0, tyObject_HSlice__ZWg9b9a9br09cvqTdM59aM3bQ9bw x_p1) {
	NimStringV2 result;
	NI a;
	NI L;
	NI TM__ipcYmBC9bj9a1BW35ABoB1Kw_2;
	NI TM__ipcYmBC9bj9a1BW35ABoB1Kw_3;
	nimfr_("[]", "/opt/homebrew/Cellar/nim/2.0.2/nim/lib/system/indices.nim");
{	nimln_(83);	a = x_p1.a;
	nimln_(84);	if (nimSubInt(x_p1.b, a, &TM__ipcYmBC9bj9a1BW35ABoB1Kw_2)) { raiseOverflow(); goto BeforeRet_;
	};
	if (nimAddInt((NI)(TM__ipcYmBC9bj9a1BW35ABoB1Kw_2), ((NI)1), &TM__ipcYmBC9bj9a1BW35ABoB1Kw_3)) { raiseOverflow(); goto BeforeRet_;
	};
	L = (NI)(TM__ipcYmBC9bj9a1BW35ABoB1Kw_3);
	nimln_(85);	if ((L) < ((NI)0) || (L) > ((NI)IL64(9223372036854775807))){ raiseRangeErrorI(L, ((NI)0), ((NI)IL64(9223372036854775807))); goto BeforeRet_;
	}
// ^ control exits here... result.p is 0x000000009 on my system

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions