I get this segfault:
Verifying dependencies for [email protected]
Compiling /home/runner/libmtg/tests/test1 (from package libmtg) using c backend
[OK] can import
{"Island": (name: "Island", text: "({T}: Add {U}.)", imageUrl: "https://cards.scryfall.io/normal/front/a/c/acd6be3f-745c-41ad-95c9-1db66ba56be2.jpg?1712356421", expansion: "Outlaws of Thunder Junction", rarity: "common", collectorNumber: 279, cost: @[], typeLine: (superType: {Basic}, mainType: {Land}, subType: {Island}), power: 0, toughness: 0, eventHandleName: "")}
Lib unloaded
Traceback (most recent call last)
/home/runner/.choosenim/toolchains/nim-2.0.4/lib/pure/collections/tableimpl.nim(198) test1
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
Segmentation fault (core dumped)
Error: execution of an external program failed: '/home/runner/libmtg/tests/test1'
Tip: 5 messages have been suppressed, use --verbose to show them.
tools.nim(36) doCmd
Error: Execution failed with exit code 1
... Command: /home/runner/libmtg/nimble-env/bin/nim c --noNimblePath -d:NimblePkgVersion=0.1.0 --hints:off --colors:off -r --path:. /home/runner/libmtg/tests/test1
But the traceback makes no sense, as the echo was already successful. (Traceback (most recent call last) /home/runner/.choosenim/toolchains/nim-2.0.4/lib/pure/collections/tableimpl.nim(198) test1. Code after the echo statement also runs successfully, and I really can’t pinpoint the cause of this segfault.
Code:
import std/[dynlib, tables]
test "can cards":
type CardsProc = proc (): Table[string, CardObject] {.gcsafe, nimcall.}
let lib = loadLib("tests/cardbank.so")
assert lib != nil, "Error loading library"
let cards = cast[CardsProc](lib.checkedSymAddr("load"))
echo cards()
unloadLib(lib)
echo "Lib unloaded"
# Segfault
Haven't checked with a debugger, but I would assume it's a memory issue. I'm not sure if you're supposed to be able to pass managed memory in and out off dynamic libraries. It at least used to be the case that you had to link against nimrtl in order for it to only run one instance of the GC. But I think this got relaxed somewhat with ARC/ORC (I seem to remember that it's only required for ORC nowadays, but maybe someone else knows for sure).
That's where I'd start looking anyways
abbreviated --expandArc output:
let cards = cast[CardsProc](checkedSymAddr(lib, "load"))
echo [
:tmpD_1 = `$`(
:tmpD = cards()
:tmpD)
:tmpD_1]
unloadLib(lib)
echo ["Lib unloaded"]
finally:
`=destroy`(:tmpD_1)
`=destroy_1`(:tmpD)
That :tmpD = cards() return is getting destroyed after the library is unloaded. Is that safe to do?
Try this, to clean up cards before the unloadLib:
block:
let cards = cast[CardsProc](lib.checkedSymAddr("load"))
echo cards()