Description
Summary
I want to create a new crate that can be used as a global allocator, but I don't want anything within my crate using my own allocator, nor do I want anything that my crate is depending on to rely on my allocator.
Background
I'm sketching out the design for a new crate that will help analyze other crate's allocation behavior, kind of like valgrind
, but for places where valgrind
doesn't work. My plan is to use backtrace, counter, and dipstick within my allocator crate. So far, so good, since my allocator is only for instrumentation, I can just use the system allocator as my global allocator, and everything works as expected.
The problem comes in when someone else wants to use my crate to instrument their own code. Per the documentation for the #[global_allocator]
attribute:
This attribute allows configuring the choice of global allocator. You can use this to implement a completely custom global allocator to route all default allocation requests to a custom object.
and
The #[global_allocator] can only be used once in a crate or its recursive dependencies.
At this point, I'm kind of stuck; I can't define #[global_allocator]
in my own crate, as that would prevent end users from using it. When end users define it so that they can use my crate, they will force my crate to use itself in the allocation process, which could lead to recursive headaches.
Potential solutions
New attributes
Create a new attribute (#[local_allocator]
?) that overrides the setting for the global allocator that gets applied to a crate and its recursive dependencies.
The main issue with this is the intersection of the crates that both my instrumentation crate and the user crate need to use; in that case, we need to either have two independent copies of the same code, or have some way of distinguishing which allocator to use when.
Binary-only distribution
Compile my instrumentation crate separately (and statically) from the user crate, forcing them to link in the binary.
This may be the best solution right now, but it may cause unforeseen toolchain issues (e.g., did the user remember to compile in debug symbols for both the user crate and my separately compiled crate?). In short, it doesn't feel very ergonomic.
Other, better solutions?
I feel like that there should be a better way than these solutions which don't break any guarantees that rust is currently providing. However, I can't think of any. Thoughts/ideas anyone?