-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Open
Description
Nim Version
Nim Compiler Version 2.2.6 [Linux: amd64]
Compiled at 2025-10-31
Copyright (c) 2006-2025 by Andreas Rumpf
git hash: ab00c56
active boot switches: -d:release
Description
Here is a snippet closure_segfault_elif.nim demonstrating the problem:
var p1: proc() {.closure.}
var p2: proc() {.closure.}
var p3: proc() {.closure.}
proc makeClosure(): proc(i: int) =
var arr = @[0,0,0]
echo "arr defined: " & $arr
var p = proc(i: int) =
if i == 0:
p1 = proc() =
arr[0] = 1
echo "p1; arr = " & $arr
elif i == 1:
p2 = proc() =
arr[1] = 2
echo "p2; arr = " & $arr
p3 = proc() =
arr[2] = 3
echo "p3; arr = " & $arr
return p
var dostuff = makeClosure()
dostuff(0) # define p1
dostuff(1) # define p2, p3
p1()
p2()
p3() # causes segfault if p3 is assigned in 'elif' blockThe closure p3 will not capture arr and will segfault when it is called. The same error occurs if an else block is used instead of elif.
Current Output
arr defined: @[0, 0, 0]
p1; arr = @[1, 0, 0]
p2; arr = @[1, 2, 0]
Traceback (most recent call last)
closure_segfault_elif.nim(27) closure_segfault_elif
closure_segfault_elif.nim(18) :anonymous
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
Segmentation fault (core dumped)
Expected Output
arr defined: @[0, 0, 0]
p1; arr = @[1, 0, 0]
p2; arr = @[1, 2, 0]
p3; arr = @[1, 2, 3]
Known Workarounds
Using if for all branches instead of if...elif resolves the problem:
var p1: proc() {.closure.}
var p2: proc() {.closure.}
var p3: proc() {.closure.}
proc makeClosure(): proc(i: int) =
var arr = @[0,0,0]
echo "arr defined: " & $arr
var p = proc(i: int) =
if i == 0:
p1 = proc() =
arr[0] = 1
echo "p1; arr = " & $arr
if i == 1:
p2 = proc() =
arr[1] = 2
echo "p2; arr = " & $arr
p3 = proc() =
arr[2] = 3
echo "p3; arr = " & $arr
return p
var dostuff = makeClosure()
dostuff(0) # define p1
dostuff(1) # define p2, p3
p1()
p2()
p3()The problem does not occur if a greater or equal number of closures are assigned in the if block as the elif block:
var p1: proc() {.closure.}
var p2: proc() {.closure.}
var p3: proc() {.closure.}
var p4: proc() {.closure.}
proc makeClosure(): proc(i: int) =
var arr = @[0,0,0]
echo "arr defined: " & $arr
var p = proc(i: int) =
if i == 0:
p1 = proc() =
arr[0] = 1
echo "p1; arr = " & $arr
p4 = proc() =
arr[0] = 9
echo "p4; arr = " & $arr
elif i == 1:
p2 = proc() =
arr[1] = 2
echo "p2; arr = " & $arr
p3 = proc() =
arr[2] = 3
echo "p3; arr = " & $arr
return p
var dostuff = makeClosure()
dostuff(0) # define p1, p4
dostuff(1) # define p2, p3
p1()
p2()
p3()
p4()The problem does not occur if closures are only assigned in one branch of the if...elif statement:
var p2: proc() {.closure.}
var p3: proc() {.closure.}
proc makeClosure(): proc(i: int) =
var arr = @[0,0,0]
echo "arr defined: " & $arr
var p = proc(i: int) =
if i == 0:
discard
elif i == 1:
p2 = proc() =
arr[1] = 2
echo "p2; arr = " & $arr
p3 = proc() =
arr[2] = 3
echo "p3; arr = " & $arr
return p
var dostuff = makeClosure()
dostuff(0) # do nothing
dostuff(1) # define p2, p3
p2()
p3()Additional Information
No response
Metadata
Metadata
Assignees
Labels
No labels