Skip to content

Trace ptr in refc #25080

@arnetheduck

Description

@arnetheduck

Nim Version

2.2.4

Description

type X = object
  v: ptr byte

proc f() =
  var data = newSeq[byte](10)
  var xxx = (ref X)(v: addr data[0])
  echo repr(x[].v)

In the above example, X contains a pointer that gets initialized to the memory owned by data - while unsafe, this technique allows low-level libraries to work around the lack of stable view types, such as in serialization where high-performance deserialization can be implemented without copying the source data.

The usage of ptr in this example looks like it should be safe because scope-wise, data outlives xxx and therefore one would assume that accessing v via the pointer is safe.

Not so, however. In the generated C code, the last access to data is addr data[0] which means that the C optimiser can reuse the stack memory of data for repr locals and thus the only source of "traced" pointers to data is gone.

repr then invokes the GC to allocate strings and depending on what was going on in the GC earlier, crashes and UB ensues.

There are two ways to address this problem:

  • insert a "fake" reference to data at the end of the scope, to inform the C compiler of the lifetime - I believe this is what happens with orc/arc
  • in refc, trace ptr conservatively when it appears as a an object field or variable - this would mean following X.v when doing tracing and noticing that v is an internal pointer to data and therefore data should not be collected.

This latter approach already "more or less" happens for local variables because the stack is conservatively traced - extending this facility to ptr in fields would make the GC safer overall and the extra tracing should be cheap (compared to fake end-of-life references)

Current Output


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