Skip to content

Stack overflow-triggered segfault in refc and ORC with inline iterator on large, heap-allocated case object #25694

@tersec

Description

@tersec

Nim Version

Nim Compiler Version 2.2.8 [Linux: amd64]
Compiled at 2026-04-02
Copyright (c) 2006-2026 by Andreas Rumpf

git hash: 4f500679b196fad944caa50a753f5bbfaefda001
active boot switches: -d:release
Nim Compiler Version 2.2.9 [Linux: amd64]
Compiled at 2026-04-02
Copyright (c) 2006-2026 by Andreas Rumpf

git hash: 5df28ab02a1da50be882bb0a9461233a9e6a278b
active boot switches: -d:release
Nim Compiler Version 2.3.1 [Linux: amd64]
Compiled at 2026-04-02
Copyright (c) 2006-2026 by Andreas Rumpf

git hash: 854c1f15bada3055fb041cc7ba96378c32d34667
active boot switches: -d:release

Description

type B = object
  case k: bool
  of false: discard
  of true: e: array[8 * 1024 * 1024, byte]
iterator items(_: array[8 * 1024 * 1024, byte]): int = yield 0
for v in (ref B)(k: true)[].e: break

In refc it compiles to

typedef struct tyObject_B__9cP0FlnvUIg6lZwAVk6WAbw
    tyObject_B__9cP0FlnvUIg6lZwAVk6WAbw;

/* ... */

typedef NU8 tyArray__3pbntMZ5y8cYIl0gvWQyuQ[8388608];
struct tyObject_B__9cP0FlnvUIg6lZwAVk6WAbw {
  NIM_BOOL k;
  union {
    tyArray__3pbntMZ5y8cYIl0gvWQyuQ e;
  };
};

/* ... */

N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void) {
  {
    {
      tyArray__3pbntMZ5y8cYIl0gvWQyuQ colontmp_;
      tyObject_B__9cP0FlnvUIg6lZwAVk6WAbw *T2_;
      nimZeroMem(((void *)colontmp_), sizeof(tyArray__3pbntMZ5y8cYIl0gvWQyuQ));
      T2_ = NIM_NIL;
      T2_ = ((tyObject_B__9cP0FlnvUIg6lZwAVk6WAbw *)newObj(
          (&NTIrefb__cr9ahW89aorgzXnwaewqJX7w_),
          sizeof(tyObject_B__9cP0FlnvUIg6lZwAVk6WAbw)));
      (*T2_).k = NIM_TRUE;
      nimZeroMem(((void *)(*T2_).e), sizeof(tyArray__3pbntMZ5y8cYIl0gvWQyuQ));
      if ((!(((2 & (((NU8)1) << (((NU)(*T2_).k) & 7U))) != 0)))) {
        raiseFieldError2(((NimStringDesc *)(&TM__kRiC3mInDeMIjkHObdNpJg_2)),
                         reprDiscriminant((((NI)(*T2_).k) + ((NI)IL64(0))),
                                          (&NTIbool__VaVACK0bpYmqIQ0mKcHfQQ_)));
      }
      nimCopyMem(((void *)colontmp_), ((NIM_CONST void *)(*T2_).e),
                 sizeof(tyArray__3pbntMZ5y8cYIl0gvWQyuQ));
      v__u_u6 = ((NI)0);
      goto LA1;
    }
  LA1:;
    popFrame();
  }
}

where it copies through tyArray__3pbntMZ5y8cYIl0gvWQyuQ colontmp_; which is put on the stack.

For ORC, it compiles to:

N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void) {
  {
    NIM_BOOL *nimErr_;
    nimErr_ = nimErrorFlag();
    {
      tyObject_B__9cP0FlnvUIg6lZwAVk6WAbw *colontmpD_;
      tyArray__3pbntMZ5y8cYIl0gvWQyuQ colontmp_;
      tyObject_B__9cP0FlnvUIg6lZwAVk6WAbw *T3_;
      colontmpD_ = NIM_NIL;
      nimZeroMem(((void *)colontmp_), sizeof(tyArray__3pbntMZ5y8cYIl0gvWQyuQ));
      T3_ = NIM_NIL;
      T3_ = ((tyObject_B__9cP0FlnvUIg6lZwAVk6WAbw *)nimNewObj(
          sizeof(tyObject_B__9cP0FlnvUIg6lZwAVk6WAbw),
          NIM_ALIGNOF(tyObject_B__9cP0FlnvUIg6lZwAVk6WAbw)));
      (*T3_).k = NIM_TRUE;
      nimZeroMem(((void *)(*T3_).e), sizeof(tyArray__3pbntMZ5y8cYIl0gvWQyuQ));
      colontmpD_ = T3_;
      if ((!(((2 & (((NU8)1) << (((NU)(*colontmpD_).k) & 7U))) != 0)))) {
        raiseFieldError2(TM__kRiC3mInDeMIjkHObdNpJg_3, ((NI)(*colontmpD_).k));
        goto LA2_;
      }
      nimCopyMem(((void *)colontmp_), ((NIM_CONST void *)(*colontmpD_).e),
                 sizeof(tyArray__3pbntMZ5y8cYIl0gvWQyuQ));
      v__u_u6 = ((NI)0);
      eqdestroy___u_u55(colontmpD_);
      goto LA1;
      {
      LA2_:;
      }
      {
        eqdestroy___u_u55(colontmpD_);
      }
      if (NIM_UNLIKELY((*nimErr_))) {
        goto BeforeRet_;
      }
    }
  LA1:;
  BeforeRet_:;
    nimTestErrorFlag();
    popFrame();
  }
}

which similarly puts a tyArray__3pbntMZ5y8cYIl0gvWQyuQ colontmp_; on the stack.

It also does a bunch wasteful memory zeroing and copying in both cases. The iterator doesn't even use that input value.

Current Output

refc:
.........................................................................
CC: system.nim
CC: u.nim
Hint:  [Link]
Hint: mm: refc; threads: on; opt: none (DEBUG BUILD, `-d:release` generates faster code)
30558 lines; 0.536s; 38.023MiB peakmem; proj: /tmp/u.nim; out: /tmp/u [SuccessX]
Hint: /tmp/u [Exec]
Segmentation fault
Error: execution of an external program failed: '/tmp/u'

ORC:
......................................................................
CC: system/exceptions.nim
CC: std/private/digitsutils.nim
CC: system/dollars.nim
CC: system.nim
CC: u.nim
Hint:  [Link]
Hint: mm: orc; threads: on; opt: none (DEBUG BUILD, `-d:release` generates faster code)
29528 lines; 0.495s; 37.953MiB peakmem; proj: /tmp/u.nim; out: /tmp/u [SuccessX]
Hint: /tmp/u [Exec]
Segmentation fault
Error: execution of an external program failed: '/tmp/u'

Expected Output


Known Workarounds

No response

Additional Information

No response

Metadata

Metadata

Assignees

No one assigned

    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