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
lent + tuple destructuring in VM iterators give random GC crashes (stack addresses escape) #17527
Comments
adding nim c -o:bin/nim_D20210326T125756.3 -d:useSysAssert -d:useGcAssert -d:release --stacktrace --debugger:native --excessivestacktrace --lineTrace -g --skipusercfg -d:nimCompilerStackraceHints --stacktracemsgs compiler/nim it fails with: proc incRef(c: PCell) {.inline.} =
gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
c.refcount = c.refcount +% rcIncrement
# and not colorMask
logCell("incRef", c) stacktrace: https://gist.github.com/timotheecour/f1e3a97dff99a02046d23e2bb13af133 |
sysAssert(c.freeList.zeroField == 0, "rawAlloc 8")
failsgcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
fails
@Araq after a very painful reduction, I finally have a repro with 0 dependencies and 0 changes to stdlib: when true:
#[
]#
iterator items2*[IX, T](a: array[IX, T]): lent T {.inline.} =
var i = low(IX)
if i <= high(IX):
while true:
yield a[i]
if i >= high(IX): break
inc(i)
proc main() =
for i in 0..<1000:
for (key, val) in items2([("any", "bar")]):
debugEcho i
debugEcho key
static: main() nim c --lib:lib -o:bin/nim_temp1 -d:useSysAssert -d:useGcAssert -d:release --stacktrace --debugger:native --excessivestacktrace --lineTrace -g --skipusercfg compiler/nim $nim_prs_D/bin/nim_temp1 c -d:case10 --skipparentcfg --skipusercfg $timn_D/tests/nim/all/t12092.nim
with debugging note
right above future PR should allow this (maybe even better, controlled by a EDIT: done in #18244 |
gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
fails
update retrying snippet with import std/vmutils
static: vmTrace(true) now that #18244 was merged, it shows this user-code trace which is complementary to the compiler stacktrace: ...
/Users/timothee/git_clone/nim/Nim_devel/lib/system/iterators_1.nim(120, 11) [opcLtInt] while i < b:
/Users/timothee/git_clone/nim/Nim_devel/lib/system/iterators_1.nim(120, 3) [opcFJmp] while i < b:
/Users/timothee/git_clone/nim/timn/tests/nim/all/t12555.nim(19, 9) [opcAsgnInt] for i in 0..<1000:
/Users/timothee/git_clone/nim/timn/tests/nim/all/t12555.nim(20, 12) [opcLdNull] for (key, val) in items2([("any", "bar")]):
/Users/timothee/git_clone/nim/timn/tests/nim/all/t12555.nim(20, 17) [opcLdNull] for (key, val) in items2([("any", "bar")]):
/Users/timothee/git_clone/nim/timn/tests/nim/all/t12555.nim(11, 16) [opcLdImmInt] var i = low(IX)
/Users/timothee/git_clone/nim/timn/tests/nim/all/t12555.nim(12, 8) [opcConv] if i <= high(IX):
/Users/timothee/git_clone/nim/timn/tests/nim/all/t12555.nim(12, 17) [opcLdImmInt] if i <= high(IX):
/Users/timothee/git_clone/nim/timn/tests/nim/all/t12555.nim(12, 10) [opcLeInt] if i <= high(IX):
/Users/timothee/git_clone/nim/timn/tests/nim/all/t12555.nim(12, 10) [opcFJmp] if i <= high(IX):
/Users/timothee/git_clone/nim/timn/tests/nim/all/t12555.nim(20, 32) [opcLdNull] for (key, val) in items2([("any", "bar")]):
/Users/timothee/git_clone/nim/timn/tests/nim/all/t12555.nim(20, 32) [opcLdNullReg] for (key, val) in items2([("any", "bar")]):
/Users/timothee/git_clone/nim/timn/tests/nim/all/t12555.nim(20, 33) [opcLdNull] for (key, val) in items2([("any", "bar")]):
SIGSEGV: Illegal storage access. (Attempt to read from nil?) |
The "minimal reduction" above: when true:
#[
]#
iterator items2*[IX, T](a: array[IX, T]): lent T {.inline.} =
var i = low(IX)
if i <= high(IX):
while true:
yield a[i]
if i >= high(IX): break
inc(i)
proc main() =
for i in 0..<1000:
for (key, val) in items2([("any", "bar")]):
debugEcho i
debugEcho key
static: main() by itself, compiles and runs and seems to give the correct output on 2.0, the actual output is very long because of Removing followup needed label because of comment above:
|
#17525 fails in CI, after investigation it fails with:
which indicates a nim bug; and in fact it's a gc bug:
tests/tmatching.nim is a large file (2698 LOC), so i tried mimizing a bit to fusion/tests/tmatching6.nim (138 LOC), see https://gist.github.com/timotheecour/f8ce7fc19199df35722c15a916a96ab8 but the smaller the file the more rare the bug occurs when you run compile it, so to reproduce this reliably, use the original file tests/tmatching.nim; seemingly unrelated changes (eg adding comments or commenting out unused code) lead to reproducing the bug or not so it's hard to minimize.
to reproduce reliably:
iterator items*[IX, T](a: array[IX, T]): T {.inline.} =
=>iterator items*[IX, T](a: array[IX, T]): lent2 T {.inline.} =
)nim c -o:bin/nim_D20210326T125756 -d:useSysAssert -d:release --stacktrace compiler/nim
$nim_prs_D/bin/nim_D20210326T125756 c tests/tmatching.nim
stacktrace with lldb:
lldb -o "b exit" -o run -- $nim_prs_D/bin/nim_D20210326T125756 c tests/tmatching.nim
when compiling nim with -g:
Additional Information
1.5.1 3e03f67
fusion 24f04ab8e38435156f8f885dea0a57c18b02626b
TODO
nimVMDebugLOC
EDIT: => enable VM tracing in user code via{.define(nimVmTrace).}
#18244The text was updated successfully, but these errors were encountered: