[Bug ipa/96503] attribute alloc_size effect lost after inlining
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 nrk at disroot dot org changed: What|Removed |Added CC||nrk at disroot dot org --- Comment #9 from nrk at disroot dot org --- This bug is particularly nasty when you have `alloc` and `resize` and the `alloc` call retains the `alloc_size` information but the `resize` call gets inlined (thus losing the new `alloc_size`) and now you're left with a pointer that GCC thinks has the *old* size. Here's a minimal demo: static int *arena; __attribute(( malloc, alloc_size(1), noinline )) static void *alloc(int size) { return arena++; } //__attribute((noinline)) __attribute(( alloc_size(2) )) static void *extend(void *oldptr, int newsize) { ++arena; return oldptr; } #include int main(void) { arena = malloc(4 * sizeof(int)); if (!arena) abort(); int *a = alloc(sizeof *a); a[0] = 4; a = extend(a, sizeof *a * 2); a[1] = 8; return a[1]; } (The `alloc` and `resize` function in practice is more sophisticated, but the above suffices for demo purposes). Compile with `gcc -O2 -fsanitize=address,undefined` and the `a[1]` will trigger UBSan because it's still operating on the old size information. Uncommenting the `noinline` from extend() "fixes" the issue. But littering the allocation routines with `noinline` is not really a good idea since it'd regress performance for custom allocators that have trivial logic (e.g bump allocators). This bug unfortunately makes the `alloc_size` attribute unusable for my purposes.
[Bug ipa/96503] attribute alloc_size effect lost after inlining
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 uecker at gcc dot gnu.org changed: What|Removed |Added CC||uecker at gcc dot gnu.org Status|UNCONFIRMED |NEW Ever confirmed|0 |1 Last reconfirmed||2023-11-03
[Bug ipa/96503] attribute alloc_size effect lost after inlining
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 --- Comment #8 from Siddhesh Poyarekar --- (In reply to Martin Uecker from comment #7) > For __builtin_with_access we probably only want to allow > reducing the object size, while the 'extend_size' workaround > used by systemd (cf comment #4) would need to extend it. > Maybe we need another flag? I've been thinking of a new __object_size__ attribute to annotate functions that behave like __builtin_object_size so that calls to it override (and not just reduce) sizes returned by allocations. I can then use it to annotate a supported malloc_usable_size replacement (say, malloc_size_estimate) that actually works like __builtin_object_size and can then be used by systemd.
[Bug ipa/96503] attribute alloc_size effect lost after inlining
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 --- Comment #7 from Martin Uecker --- Am Mittwoch, dem 25.10.2023 um 11:08 + schrieb siddhesh at gcc dot gnu.org: > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 > > --- Comment #6 from Siddhesh Poyarekar --- > So basically, > > __builtin_with_access(void *ptr, size_t size, int access) > > where access == > > -1: Unknown access semantics > 0: none > 1: read_only > 2: write_only > 3: read_write > > should address both access and alloc_size and even counted_by. Yes, sounds good. > We would need > to emit the builtin in the caller as well as callee of the function that has > the access attribute while for alloc_size, we only need to emit this in the > caller. Yes, makes sense, although I guess caller part for "access" is only for warning and not relevant for BDOS, so could potentially stay as it is for now. For __builtin_with_access we probably only want to allow reducing the object size, while the 'extend_size' workaround used by systemd (cf comment #4) would need to extend it. Maybe we need another flag? Martin
[Bug ipa/96503] attribute alloc_size effect lost after inlining
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 --- Comment #6 from Siddhesh Poyarekar --- So basically, __builtin_with_access(void *ptr, size_t size, int access) where access == -1: Unknown access semantics 0: none 1: read_only 2: write_only 3: read_write should address both access and alloc_size and even counted_by. We would need to emit the builtin in the caller as well as callee of the function that has the access attribute while for alloc_size, we only need to emit this in the caller.
[Bug ipa/96503] attribute alloc_size effect lost after inlining
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 --- Comment #5 from Siddhesh Poyarekar --- This could work for alloc_size, but not quite for access. pointer_with_size (or __builtin_with_size as you suggested in that thread) would need to express access semantics too, to be able to express everything that access does.
[Bug ipa/96503] attribute alloc_size effect lost after inlining
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 Sam James changed: What|Removed |Added See Also||https://github.com/systemd/ ||systemd/issues/22801, ||https://github.com/systemd/ ||systemd/pull/25688 --- Comment #4 from Sam James --- This came up in the wild at https://github.com/systemd/systemd/issues/22801 and https://github.com/systemd/systemd/pull/25688.
[Bug ipa/96503] attribute alloc_size effect lost after inlining
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 Martin Uecker changed: What|Removed |Added CC||muecker at gwdg dot de --- Comment #3 from Martin Uecker --- Was just to file this bug... Note that the access attribute could be translated into the same builtin suggested for counted_by in https://gcc.gnu.org/pipermail/gcc-patches/2023-October/634177.html and then this could work. This would also simply the BDOS path I think because special code for the access attribute could go. Example: https://godbolt.org/z/1TTePn7hn static #if 0 char *propagate(char *p, int s) [[gnu::access(read_only, 1, 2)]] #else char *propagate(char *p; int s; char p[(p = pointer_with_size(p, s), s)], int s) #endif { printf("%ld\n", __builtin_dynamic_object_size(p, 0)); return p; }
[Bug ipa/96503] attribute alloc_size effect lost after inlining
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 PaX Team changed: What|Removed |Added CC||pageexec at gmail dot com --- Comment #2 from Siddhesh Poyarekar --- (In reply to Kees Cook from comment #1) > Created attachment 53643 [details] > PoC showing unexpected __bdos results across inlines > > Fixing this is needed for the Linux kernel to do much useful with > alloc_size. Most of the allocators are inline wrappers, for example. For cases where the size doesn't really change across the inlines, it ought to be sufficient to annotate the non-inlined implementation function, e.g. in case of kvmalloc, annotate kvmalloc_node as __alloc_size(1). For other cases it may be less trivial, e.g.: /* Some padding the wrapper adds to the actual allocation. */ size_t metadata_size; __attribute__ ((alloc_size (1))) void *alloc_wrapper (size_t sz) { return real_alloc (size + metadata_size); } extern void *real_alloc (size_t) __attribute__ ((alloc_size(1))); here the compiler will end up seeing the padded size, which may not be correct. To fix this we'll have to store the alloc_size info somewhere (ptr_info seems to be aliasing-specific, so maybe a new member to tree_ssa_name) during inlining and then teach the tree-object-size pass to access it.
[Bug ipa/96503] attribute alloc_size effect lost after inlining
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 Kees Cook changed: What|Removed |Added CC||kees at outflux dot net --- Comment #1 from Kees Cook --- Created attachment 53643 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=53643&action=edit PoC showing unexpected __bdos results across inlines Fixing this is needed for the Linux kernel to do much useful with alloc_size. Most of the allocators are inline wrappers, for example. This can be additionally shown to break __builtin_dynamic_object_size(), which means all FORTIFY_SOURCE of alloc_size-marked inlines is broken. :( https://godbolt.org/z/jTKjY3s1j