-
Notifications
You must be signed in to change notification settings - Fork 106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
__builtin_dynamic_object_size and snmalloc #531
Comments
I'm not a huge fan of the I don't think
This does not generate any kind of library call, it simply evaluates to -1 unconditionally. We could provide a library call that the compiler can lower this to but I suspect that the perf overhead would be too high (my first prototype did exactly this). There are basically three approaches:
Note that the last approach composes with a We provide our own |
I think both of the comments were about expanding the behaviour of
rather than its current behaviour. I could easily imagine a "stronger"/"enhanced" version that would call I guess the bit that is most appealing is getting checks statically eliminated.
If the compiler can eliminate sufficiently many checks, then for some instances, the cost of the checks being an additional function call could be mitigated, but we would have to measure. @davidchisnall Could you post a link to your FreeBSD experiments here? |
Currently, LLVM can elide these only for stack allocations, so we'd still be inserting the extra call(s - two if we're checking the source as well as the destination) for things that are not statically provable to be stack allocations. Not sure if GCC does better here.
The current version is here, it doesn't include the hardening for non-memcpy functions - I have an old version of that locally but it needs updating / rewriting for the newer snmalloc and newer libc. |
I'm not an expert, but here are some considerations... There are a few issues with this:
In the end, you don't need to change the behaviour of |
Address Sanitizer already supports such object size checks and has an interface for them, but it does not provide ABI stability. One complication is that you cannot assume that an arbitrary pointer points into the (And it's true that |
Interesting, so could you point me at the documentation or some use cases of this? I wasn't aware that ASAN could determine the size of an object from an interior pointer without a linear scan.
So the snmalloc functionality overapproximates the size to the whole address range if it is not backed by an snmalloc allocation. So it will only report actual errors, but if it is allocated elsewhere then it will not report a problem. |
The use case is the ASAN crash reporter. But I was mistaken: there is no unified API to get the size information directly, the crash reporter in https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/asan/asan_descriptions.cpp open-codes it. The regular overflow checking happens differently in ASAN (using shadow memory).
The ASAN heap allocator has
Right, that should work for size checking, it's how |
IIUC, the idea behind the But the allocator already has that information on its internal structures. If the allocator provides an API to do that without additional shadow data structures, then runtime checks become very cheap. WRT API stability, sanitizers don't even have that stability guarantee on the same release, across different architectures, or different OSs, different word sizes. Some things exist in one and not others, some things are reasonably fast in some and ridiculously slow in others. In contrast, asking the allocator what is the size of an object is a table lookup in most cases, but of course, it can't know about other types of allocations like It could be possible (though reasonably pedestrian and frail) to add another call for non-snmalloc allocations so that snmalloc knows about them but not necessarily manages them. If users are willing to part the beaten path with builtin calls, then they could also be happy to manually comlement their None of that helps with the stack, but the stack has a more controlled temporal usage pattern. For the cases where you want to use the builtin, you could use the static builtin (on the same frame), or propagate the |
@rengolin, a few comments:
I believe the idea is to have an API that determines the memory size. You could implement this as something like:
If the compiler can statically determine the size of the object then this compiles to the SSA register containing the size, otherwise it compiles to a call. We get better code generation in the snmalloc versions by expressing this as an explicit bounds-check API. We'd probably want something like (ignoring error messages):
This won't actually work because
The current checks are also not used directly on
We're exploring integrating snmalloc with libc in several contexts and I think requiring modifications to libc and libc headers is fine (in particular, the
We don't want to add instrumentation on
If you're doing static linking with LTO, the first one of these is fine. In general, it's too expensive. We've (mostly @mjp41) done a lot of work in the |
On twitter @richfelker has said we should consider providing
__builtin_dynamic_object_size
as a more comprehensive way to provide guarded memcpy like features:and
I'm raising this issue to build a discussion of what this should mean with snmalloc.
The Clang documentation is here:
https://clang.llvm.org/docs/LanguageExtensions.html#evaluating-object-size-dynamically
Here is the LLVM review adding it
https://reviews.llvm.org/D56760
It doesn't seem it works from an offset into an object. But I think this is worth experimenting with, as it would allow the compiler to remove some checks, and then what is left to be passed to the snmalloc routine.
I think we could define
__builtin_dynamic_object_size
as justremaining_bytes
from snmalloc.@davidchisnall thoughts? Is there something sensible that could be experimented with here?
The text was updated successfully, but these errors were encountered: