]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
basic/alloc-util: make realloc0 non-inline
authorZbigniew Jędrzejewski-Szmek <zbyszek@amutable.com>
Tue, 3 Mar 2026 08:55:09 +0000 (09:55 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@amutable.com>
Fri, 6 Mar 2026 16:46:59 +0000 (17:46 +0100)
It's actually only used in one place in libsystemd and moving it even makes
libsystemd smaller (in a non-optimized build):

$ ls -l build/libsystemd.so.0.43.0*
-rwxr-xr-x 1 zbyszek zbyszek 5763336 Mar  3 09:54 build/libsystemd.so.0.43.0-old
-rwxr-xr-x 1 zbyszek zbyszek 5763216 Mar  3 09:54 build/libsystemd.so.0.43.0

Also, move the definitions in the .h file so that similar functions are
grouped together and then move the definitions around in the .c file so
that they are in the same order as in the header.

src/basic/alloc-util.c
src/basic/alloc-util.h

index 94102dd430c0436954806d6f16c17a39ececfebc..1eb98c1199d290d9e3bf96edf8a2c8214f5b742a 100644 (file)
@@ -34,6 +34,44 @@ void* memdup_suffix0(const void *p, size_t l) {
         return memcpy_safe(ret, p, l);
 }
 
+size_t malloc_sizeof_safe(void **xp) {
+        if (_unlikely_(!xp || !*xp))
+                return 0;
+
+        size_t sz = malloc_usable_size(*xp);
+        *xp = expand_to_usable(*xp, sz);
+        /* GCC doesn't see the _returns_nonnull_ when built with ubsan, so yet another hint to make it doubly
+         * clear that expand_to_usable won't return NULL.
+         * See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79265 */
+        if (!*xp)
+                assert_not_reached();
+        return sz;
+}
+
+void* expand_to_usable(void *ptr, size_t newsize _unused_) {
+        return ptr;
+}
+
+void* realloc0(void *p, size_t new_size) {
+        size_t old_size;
+        void *q;
+
+        /* Like realloc(), but initializes anything appended to zero */
+
+        old_size = MALLOC_SIZEOF_SAFE(p);
+
+        q = realloc(p, new_size);
+        if (!q)
+                return NULL;
+
+        new_size = MALLOC_SIZEOF_SAFE(q); /* Update with actually allocated space */
+
+        if (new_size > old_size)
+                memset((uint8_t*) q + old_size, 0, new_size - old_size);
+
+        return q;
+}
+
 void* greedy_realloc(
                 void **p,
                 size_t need,
@@ -125,24 +163,6 @@ void* greedy_realloc_append(
         return q;
 }
 
-void *expand_to_usable(void *ptr, size_t newsize _unused_) {
-        return ptr;
-}
-
-size_t malloc_sizeof_safe(void **xp) {
-        if (_unlikely_(!xp || !*xp))
-                return 0;
-
-        size_t sz = malloc_usable_size(*xp);
-        *xp = expand_to_usable(*xp, sz);
-        /* GCC doesn't see the _returns_nonnull_ when built with ubsan, so yet another hint to make it doubly
-         * clear that expand_to_usable won't return NULL.
-         * See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79265 */
-        if (!*xp)
-                assert_not_reached();
-        return sz;
-}
-
 void free_many(void **p, size_t n) {
         assert(p || n == 0);
 
index 7d5c1da61f2ddeccc9e02b384984bc52b20d9054..2c40c4771cdc3b289b365c2828e5001c46f03ead 100644 (file)
@@ -108,6 +108,34 @@ static inline void *memdup_suffix0_multiply(const void *p, size_t need, size_t s
         return memdup_suffix0(p, size * need);
 }
 
+size_t malloc_sizeof_safe(void **xp);
+
+/* This returns the number of usable bytes in a malloc()ed region as per malloc_usable_size(), which may
+ * return a value larger than the size that was actually allocated. Access to that additional memory is
+ * discouraged because it violates the C standard; a compiler cannot see that this as valid. To help the
+ * compiler out, the MALLOC_SIZEOF_SAFE macro 'allocates' the usable size using a dummy allocator function
+ * expand_to_usable. There is a possibility of malloc_usable_size() returning different values during the
+ * lifetime of an object, which may cause problems, but the glibc allocator does not do that at the moment. */
+#define MALLOC_SIZEOF_SAFE(x) \
+        malloc_sizeof_safe((void**) &__builtin_choose_expr(__builtin_constant_p(x), (void*) { NULL }, (x)))
+
+/* Inspired by ELEMENTSOF() but operates on malloc()'ed memory areas: typesafely returns the number of items
+ * that fit into the specified memory block */
+#define MALLOC_ELEMENTSOF(x) \
+        (__builtin_choose_expr(                                         \
+                __builtin_types_compatible_p(typeof(x), typeof(&*(x))), \
+                MALLOC_SIZEOF_SAFE(x)/sizeof((x)[0]),                   \
+                VOID_0))
+
+/* Dummy allocator to tell the compiler that the new size of p is newsize. The implementation returns the
+ * pointer as is; the only reason for its existence is as a conduit for the _alloc_ attribute.  This must not
+ * be inlined (hence a non-static function with _noinline_ because LTO otherwise tries to inline it) because
+ * gcc then loses the attributes on the function.
+ * See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 */
+void *expand_to_usable(void *p, size_t newsize) _alloc_(2) _returns_nonnull_ _noinline_;
+
+void* realloc0(void *p, size_t new_size) _alloc_(2);
+
 static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) {
         size_t m;
 
@@ -179,32 +207,6 @@ void* greedy_realloc_append(void **p, size_t *n_p, const void *from, size_t n_fr
 #  define msan_unpoison(r, s)
 #endif
 
-/* Dummy allocator to tell the compiler that the new size of p is newsize. The implementation returns the
- * pointer as is; the only reason for its existence is as a conduit for the _alloc_ attribute.  This must not
- * be inlined (hence a non-static function with _noinline_ because LTO otherwise tries to inline it) because
- * gcc then loses the attributes on the function.
- * See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 */
-void *expand_to_usable(void *p, size_t newsize) _alloc_(2) _returns_nonnull_ _noinline_;
-
-size_t malloc_sizeof_safe(void **xp);
-
-/* This returns the number of usable bytes in a malloc()ed region as per malloc_usable_size(), which may
- * return a value larger than the size that was actually allocated. Access to that additional memory is
- * discouraged because it violates the C standard; a compiler cannot see that this as valid. To help the
- * compiler out, the MALLOC_SIZEOF_SAFE macro 'allocates' the usable size using a dummy allocator function
- * expand_to_usable. There is a possibility of malloc_usable_size() returning different values during the
- * lifetime of an object, which may cause problems, but the glibc allocator does not do that at the moment. */
-#define MALLOC_SIZEOF_SAFE(x) \
-        malloc_sizeof_safe((void**) &__builtin_choose_expr(__builtin_constant_p(x), (void*) { NULL }, (x)))
-
-/* Inspired by ELEMENTSOF() but operates on malloc()'ed memory areas: typesafely returns the number of items
- * that fit into the specified memory block */
-#define MALLOC_ELEMENTSOF(x) \
-        (__builtin_choose_expr(                                         \
-                __builtin_types_compatible_p(typeof(x), typeof(&*(x))), \
-                MALLOC_SIZEOF_SAFE(x)/sizeof((x)[0]),                   \
-                VOID_0))
-
 /* Free every element of the array. */
 void free_many(void **p, size_t n);
 
@@ -212,23 +214,3 @@ void free_many(void **p, size_t n);
 static inline void free_many_charp(char **c, size_t n) {
         free_many((void**) c, n);
 }
-
-_alloc_(2) static inline void *realloc0(void *p, size_t new_size) {
-        size_t old_size;
-        void *q;
-
-        /* Like realloc(), but initializes anything appended to zero */
-
-        old_size = MALLOC_SIZEOF_SAFE(p);
-
-        q = realloc(p, new_size);
-        if (!q)
-                return NULL;
-
-        new_size = MALLOC_SIZEOF_SAFE(q); /* Update with actually allocated space */
-
-        if (new_size > old_size)
-                memset((uint8_t*) q + old_size, 0, new_size - old_size);
-
-        return q;
-}