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.54k stars 1.47k forks source link

SIGSEGV: Illegal storage access. (Attempt to read from nil?) when using nim-2.2.0 and nim-2.0.10 but it works in nim-1.6.20 and nim-2.0.8 #24242

Open forchid opened 2 weeks ago

forchid commented 2 weeks ago

Description

Test source

# Very slow ... but very quick in nim-2.0.8(1.6.20 best)!
#import std/lists
import std/os
#import std/strformat
import strutils

type
  ObjRef = ref object of RootObj
    data: int
    remark: string
    parent: ObjRef
    children: seq[ObjRef]

proc test(o: ObjRef, i: int) =
    #echo "data = ", o.data
    var o = new(ObjRef)
    o.data = i
    #o.remark = fmt"*ObjRef*#{i}Foo-bar-foo-bar-foo-bar#{i}"
    var c = ObjRef(data: i + 1)
    o.children.add(c)
    c.parent = o
    o.children = @[]

proc printDiagnostics() =
  echo("Total memory available: " & formatSize(getTotalMem()) & " bytes")
  echo("Free memory: " & formatSize(getFreeMem()) & " bytes")
  echo("Occupied memory: " & formatSize(getOccupiedMem()) & " bytes")

proc main =
    var
        o: ObjRef
        #i = 0
        n = 100000000
        #a = initSinglyLinkedList[ObjRef]()
        a = newSeq[ObjRef]()

    #while i <= n:
    for i in 1 .. n + 1:
        #inc i
        o = new(ObjRef)
        o.data = i
        #o.remark = fmt"ObjRef#{i}Foo-bar-foo-bar-foo-bar#{i}"
        var c = ObjRef(data: i + 1)
        o.children.add(c)
        c.parent = o;
        o.test(i)
        a.add(o)

        if i mod 1000_0000 == 0:
            #a = initSinglyLinkedList[ObjRef]()
            for item in a: item.children = @[]
            a = @[]

        if i mod 10000000 == 0:
            echo "i = ", i
            o.test(i)
            printDiagnostics();

main()

const STM = 1000
for i in 1 .. 1800:
    printDiagnostics();
    echo $i & ". Sleep " & $STM & "ms"
    sleep(STM)
echo "Bye!"

Nim Version

%nim22_home%\bin\nim -v Nim Compiler Version 2.2.0 [Windows: amd64] Compiled at 2024-10-02 Copyright (c) 2006-2024 by Andreas Rumpf

active boot switches: -d:release

Current Output

>%nim22_home%\bin\nim c -d:release objtest.nim
Hint: used config file '...\nim-2.2.0\config\nim.cfg' [Conf]
Hint: used config file '...\nim-2.2.0\config\config.nims' [Conf]
.....................................................................................................................
Hint:  [Link]
Hint: mm: orc; threads: on; opt: speed; options: -d:release
51928 lines; 0.953s; 73.387MiB peakmem; proj: ...\objtest.nim; out: ...\objtest.exe [SuccessX]

>objtest
i = 10000000
Total memory available: 2.363GiB bytes
Free memory: 526.309MiB bytes
Occupied memory: 176MiB bytes
SIGSEGV: Illegal storage access. (Attempt to read from nil?)

>echo %errorlevel%
1

Expected Output

>objtest
i = 10000000
Total memory available: 2.363GiB bytes
Free memory: 526.309MiB bytes
Occupied memory: 176MiB bytes
i = 20000000
...

Known Workarounds

No response

Additional Information

No response

tersec commented 2 weeks ago

Seems ORC-only. refc doesn't seem affected.

metagn commented 2 weeks ago

This code is basically a pure stress test of the cycle collector. The segfault is probably a legitimate issue but there are some tips I would give to improve the performance on ORC, and do work around this issue.

The fact that ObjRef uses inheritance isn't related.

forchid commented 2 weeks ago
  • Weirdly enough, not using {.cursor.} but still marking as {.acyclic.}/using ARC also works,

@metagn This test actually hasn't cyclic refs for these cyclic relationships broken manually.

metagn commented 2 weeks ago

The parent and children are mutually cyclic with each other. If the parent is not marked {.cursor.}, when the child is destroyed, the parent is destroyed as well. This normally causes issues but it's not encountered in this test, if that's what you meant.