Description
Feature Request: Add Free Callback for void* v
in nix_create_external_value
Is your feature request related to a problem?
Currently, the nix_create_external_value
API takes a void* v
argument, which is typically used as user data. While the returned ExternalValue*
is owned by the Nix evaluator, there is no clear mechanism for managing the lifecycle of void* v
. Since Nix cannot free this memory itself, one would expect to see a free callback in [NixCExternalValueDesc](https://hydra.nixos.org/build/289480061/download/1/html/structNixCExternalValueDesc.html#details)
, but no such function exists.
Additionally, there does not appear to be any general mechanism to detect when an external value is freed, meaning the user has no clear way to know when to clean up their allocated memory. This leads to the question:
Am I just meant to leak my void* v
?
Proposed solution
A free callback should be added to NixCExternalValueDesc
to allow proper cleanup of void* v
when an external value is garbage collected. This would ensure that resources are not leaked unnecessarily.
Implement a mechanism for registering finalizers in mkExternal
, so that destructors may be called.
Since Nix uses a conservative garbage collector, finalizers are not always guaranteed to run before process exit. Even so, adding a free callback would improve resource management in most cases. This should be documented.
To ensure correctness, a test utility should be introduced to force finalization, allowing unit tests to verify that the free callback is correctly handled.
Alternative solutions
- Document the current behavior explicitly to warn users about potential memory leaks.
Additional context
This issue was initially raised by sodiboo on Matrix. Investigation shows that while ExternalValueBase
has a virtual destructor, it is never called because Value
relies entirely on GC, and mkExternal
does not register a finalizer. This means that external values are never explicitly freed, leading to potential memory leaks.
If Nix were to introduce finalization in the future, it could start invoking code written by C API consumers that has never run before. If finalization is not fully implemented and tested, this could result in unexpected crashes when untested code starts executing. Ensuring that finalization is tested from the start would mitigate this risk.
Add 👍 to issues you find important.