Nim icon indicating copy to clipboard operation
Nim copied to clipboard

SIGSEGV with `refc` and RVO

Open tersec opened this issue 1 month ago • 0 comments

Nim Version

Any combination of one of the Nim versions:

Nim Compiler Version 2.2.4 [Linux: amd64]
Compiled at 2025-11-17
Copyright (c) 2006-2025 by Andreas Rumpf

git hash: f7145dd26efeeeb6eeae6fff649db244d81b212d
active boot switches: -d:release
Nim Compiler Version 2.2.6 [Linux: amd64]
Compiled at 2025-11-17
Copyright (c) 2006-2025 by Andreas Rumpf

git hash: ab00c56904e3126ad826bb520d243513a139436a
active boot switches: -d:release
Nim Compiler Version 2.2.7 [Linux: amd64]
Compiled at 2025-11-17
Copyright (c) 2006-2025 by Andreas Rumpf

git hash: 5394c6814ba9de46b987a3def6bab8e64477b350
active boot switches: -d:release
Nim Compiler Version 2.3.1 [Linux: amd64]
Compiled at 2025-11-18
Copyright (c) 2006-2025 by Andreas Rumpf

git hash: 79ddb7d89e4320b448c35b5936ce150706bbf210
active boot switches: -d:release

And one of the C compilers:

gcc (Debian 15.2.0-8) 15.2.0
Copyright (C) 2025 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Debian clang version 19.1.7 (10.1)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/lib/llvm-19/bin

Description

e.nim:

import ./[c, t]

block:
  let a = new D
  a[] = p()
  discard a[]
block:
  let a = new D
  a[] = p()
  discard a[]
block:
  let a = new D
  a[] = p()
  discard a[]

t.nim:

import ./c
proc p*(): D =
  let c = M[uint64](data: @[0], indices: [1])
  result = D(g: c)

c.nim:

template a(T: type): int =
  when T is uint64: 1 else: 2

type
  M*[T] = object
    data*: seq[T]
    b: seq[int]
    indices*: array[a(T), int64]
  U = distinct uint64
  D* = object
    c: M[U]
    v: array[180000, int64]
    g*: M[uint64]

And one runs e.nim with --mm:refc.

p() does properly RVO:

N_LIB_PRIVATE N_NIMCALL(void,
                        p__t_u2)(tyObject_D__a8D29cxhmGxbkRzQf8Ot6tw *Result) {
  tyObject_M__HvRAY9c3CrEdjcIHy0QH9cQg c_1;
  NI T1_;
  NI T2_;
  NI T3_;
  nimfr_("p", "/tmp/t.nim");
  nimZeroMem(((void *)((&c_1))), sizeof(tyObject_M__HvRAY9c3CrEdjcIHy0QH9cQg));
  nimlf_(3, "/tmp/t.nim");
  nimZeroMem(((void *)((&c_1))), sizeof(tyObject_M__HvRAY9c3CrEdjcIHy0QH9cQg));
  c_1.data = ((tySequence__YdLNCDKYeipzJx3I8Xw82Q *)newSeq(
      (&NTIseqLuT__YdLNCDKYeipzJx3I8Xw82Q_), 1));
  c_1.data->data[0] = 0ULL;
  nimCopyMem(((void *)c_1.indices),
             ((NIM_CONST void *)TM__earX20ePV9cxitomwdUMS7g_2),
             sizeof(tyArray__kEO5nt0q5HB1HlDdv9b8C0A));
  nimln_(4);
  unsureAsgnRef(((void **)(&(*Result).c.data)), NIM_NIL);
  unsureAsgnRef(((void **)(&(*Result).c.b)), NIM_NIL);
  T1_ = ((NI)0);
  for (T1_ = 0; T1_ < 2; T1_++) {
    (*Result).c.indices[T1_] = 0;
  }
  T2_ = ((NI)0);
  for (T2_ = 0; T2_ < 180000; T2_++) {
    (*Result).v[T2_] = 0;
  }
  unsureAsgnRef(((void **)(&(*Result).g.data)), NIM_NIL);
  unsureAsgnRef(((void **)(&(*Result).g.b)), NIM_NIL);
  T3_ = ((NI)0);
  for (T3_ = 0; T3_ < 1; T3_++) {
    (*Result).g.indices[T3_] = 0;
  }
  genericSeqAssign(((&(*Result).g.data)), c_1.data,
                   (&NTIseqLuT__YdLNCDKYeipzJx3I8Xw82Q_));
  genericSeqAssign(((&(*Result).g.b)), c_1.b,
                   (&NTIseqLintT__qwqHTkRvwhrRyENtudHQ7g_));
  nimCopyMem(((void *)(*Result).g.indices), ((NIM_CONST void *)c_1.indices),
             sizeof(tyArray__kEO5nt0q5HB1HlDdv9b8C0A));
  popFrame();
}

and is called by

N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void) {
  {
    TFrame FR_;
    FR_.len = 0;

    nimRegisterGlobalMarker(TM__56TX8Bu5PD5fXC6a9cMUatQ_2);

    nimRegisterGlobalMarker(TM__56TX8Bu5PD5fXC6a9cMUatQ_3);

    nimRegisterGlobalMarker(TM__56TX8Bu5PD5fXC6a9cMUatQ_4);
  }
  {
    nimfr_("e", "/tmp/e.nim");
    {
      nimlf_(4, "/tmp/e.nim");
      asgnRef(((void **)((&a__e_u28))), new__e_u3());
      nimln_(5);
      p__t_u2(((&(*a__e_u28))));
      nimln_(6);
      (void)(*a__e_u28);
    }
    {
      nimln_(8);
      asgnRef(((void **)((&a__e_u32))), new__e_u3());
      nimln_(9);
      p__t_u2(((&(*a__e_u32))));
      nimln_(10);
      (void)(*a__e_u32);
    }
    {
      nimln_(12);
      asgnRef(((void **)((&a__e_u36))), new__e_u3());
      nimln_(13);
      p__t_u2(((&(*a__e_u36))));
      nimln_(14);
      (void)(*a__e_u36);
    }
    popFrame();
  }
}

Current Output

...........................................................................
CC: system/exceptions.nim
CC: std/private/digitsutils.nim
CC: system/dollars.nim
CC: std/typedthreads.nim
CC: sharedlist.nim
CC: system.nim
CC: c.nim
CC: t.nim
CC: e.nim
Hint:  [Link]
Hint: mm: refc; threads: on; opt: none (DEBUG BUILD, `-d:release` generates faster code)
30106 lines; 0.596s; 38.418MiB peakmem; proj: /tmp/e; out: /tmp/e [SuccessX]
Hint: /tmp/e [Exec]
Traceback (most recent call last)
/tmp/e.nim(13)           e
/tmp/t.nim(3)            p
/tmp/nim23/lib/system/gc.nim(497) newSeq
/tmp/nim23/lib/system/gc.nim(489) newObj
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
Segmentation fault
Error: execution of an external program failed: '/tmp/e'

Expected Output

No SIGSEGV

Known Workarounds

No response

Additional Information

No response

tersec avatar Nov 18 '25 14:11 tersec