Implement C23's free_sized and free_aligned_sized

[N2699 - Sized Memory Deallocation](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2699.htm)
introduced two new functions which were incorporated into the C23
standard, `free_sized` and `free_aligned_sized`. Both already have
analogues in Jemalloc, all we are doing here is adding the appropriate
wrappers.
This commit is contained in:
Kevin Svetlitski 2023-07-14 13:14:06 -07:00 committed by Qi Wang
parent 41e0b857be
commit cdb2c0e02f
5 changed files with 75 additions and 1 deletions

View File

@ -1105,7 +1105,7 @@ AC_ARG_WITH([export],
fi] fi]
) )
public_syms="aligned_alloc calloc dallocx free mallctl mallctlbymib mallctlnametomib malloc malloc_conf malloc_conf_2_conf_harder malloc_message malloc_stats_print malloc_usable_size mallocx smallocx_${jemalloc_version_gid} nallocx posix_memalign rallocx realloc sallocx sdallocx xallocx" public_syms="aligned_alloc calloc dallocx free free_sized free_aligned_sized mallctl mallctlbymib mallctlnametomib malloc malloc_conf malloc_conf_2_conf_harder malloc_message malloc_stats_print malloc_usable_size mallocx smallocx_${jemalloc_version_gid} nallocx posix_memalign rallocx realloc sallocx sdallocx xallocx"
dnl Check for additional platform-specific public API functions. dnl Check for additional platform-specific public API functions.
AC_CHECK_FUNC([memalign], AC_CHECK_FUNC([memalign],
[AC_DEFINE([JEMALLOC_OVERRIDE_MEMALIGN], [ ], [ ]) [AC_DEFINE([JEMALLOC_OVERRIDE_MEMALIGN], [ ], [ ])
@ -1129,6 +1129,16 @@ if test "x${JEMALLOC_PREFIX}" = "x" ; then
AC_CHECK_FUNC([__libc_free], AC_CHECK_FUNC([__libc_free],
[AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_FREE], [ ], [ ]) [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_FREE], [ ], [ ])
wrap_syms="${wrap_syms} __libc_free"]) wrap_syms="${wrap_syms} __libc_free"])
dnl __libc_free_sized and __libc_free_aligned_sized are here speculatively
dnl under the assumption that glibc will eventually define symbols with these
dnl names. In the event glibc chooses different names for these symbols,
dnl these will need to be amended to match.
AC_CHECK_FUNC([__libc_free_sized],
[AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_FREE_SIZED], [ ], [ ])
wrap_syms="${wrap_syms} __libc_free_sized"])
AC_CHECK_FUNC([__libc_free_aligned_sized],
[AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_FREE_ALIGNED_SIZED], [ ], [ ])
wrap_syms="${wrap_syms} __libc_free_aligned_sized"])
AC_CHECK_FUNC([__libc_malloc], AC_CHECK_FUNC([__libc_malloc],
[AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_MALLOC], [ ], [ ]) [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_MALLOC], [ ], [ ])
wrap_syms="${wrap_syms} __libc_malloc"]) wrap_syms="${wrap_syms} __libc_malloc"])

View File

@ -33,6 +33,8 @@
<refname>aligned_alloc</refname> <refname>aligned_alloc</refname>
<refname>realloc</refname> <refname>realloc</refname>
<refname>free</refname> <refname>free</refname>
<refname>free_sized</refname>
<refname>free_aligned_sized</refname>
<refname>mallocx</refname> <refname>mallocx</refname>
<refname>rallocx</refname> <refname>rallocx</refname>
<refname>xallocx</refname> <refname>xallocx</refname>
@ -89,6 +91,17 @@
<funcdef>void <function>free</function></funcdef> <funcdef>void <function>free</function></funcdef>
<paramdef>void *<parameter>ptr</parameter></paramdef> <paramdef>void *<parameter>ptr</parameter></paramdef>
</funcprototype> </funcprototype>
<funcprototype>
<funcdef>void <function>free_sized</function></funcdef>
<paramdef>void *<parameter>ptr</parameter></paramdef>
<paramdef>size_t <parameter>size</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>void <function>free_aligned_sized</function></funcdef>
<paramdef>void *<parameter>ptr</parameter></paramdef>
<paramdef>size_t <parameter>alignment</parameter></paramdef>
<paramdef>size_t <parameter>size</parameter></paramdef>
</funcprototype>
</refsect2> </refsect2>
<refsect2> <refsect2>
<title>Non-standard API</title> <title>Non-standard API</title>
@ -227,6 +240,17 @@
allocated memory referenced by <parameter>ptr</parameter> to be made allocated memory referenced by <parameter>ptr</parameter> to be made
available for future allocations. If <parameter>ptr</parameter> is available for future allocations. If <parameter>ptr</parameter> is
<constant>NULL</constant>, no action occurs.</para> <constant>NULL</constant>, no action occurs.</para>
<para>The <function>free_sized()</function> function is an extension of
<function>free()</function> with a <parameter>size</parameter> parameter
to allow the caller to pass in the allocation size as an optimization.
</para>
<para>The <function>free_aligned_sized()</function> function accepts a
<parameter>ptr</parameter> which was allocated with a requested
<parameter>size</parameter> and <parameter>alignment</parameter>, causing
the allocated memory referenced by <parameter>ptr</parameter> to be made
available for future allocations.</para>
</refsect2> </refsect2>
<refsect2> <refsect2>
<title>Non-standard API</title> <title>Non-standard API</title>
@ -451,6 +475,24 @@ for (i = 0; i < nbins; i++) {
depended on, since such behavior is entirely implementation-dependent. depended on, since such behavior is entirely implementation-dependent.
</para> </para>
</refsect2> </refsect2>
<refsect2>
<title>Interactions Between the Standard and Non-standard APIs</title>
<para>Generally speaking it is permissible to pass pointers obtained from
the standard API to the non-standard API and vice versa (e.g. calling
<function>free()</function> with a pointer returned by a call to
<function>mallocx()</function>, calling <function>sdallocx()</function>
with a pointer returned by a call to <function>calloc()</function>).
There are however a few exceptions. In keeping with the C23 standard
which forbids calling <function>free_sized()</function> on a pointer
returned by <function>aligned_alloc()</function>, mandating that either
<function>free_aligned_sized()</function> or <function>free()</function>
be used instead using any combination of the standard and non-standard
APIs in an equivalent fashion (i.e. taking a pointer which was allocated
with an explicitly requested alignment and attempting to free it via an
API that accepts a size hint, without also providing the alignment hint)
is likewise forbidden.
</para>
</refsect2>
</refsect1> </refsect1>
<refsect1 id="tuning"> <refsect1 id="tuning">
<title>TUNING</title> <title>TUNING</title>

View File

@ -14,6 +14,8 @@
*/ */
#undef JEMALLOC_OVERRIDE___LIBC_CALLOC #undef JEMALLOC_OVERRIDE___LIBC_CALLOC
#undef JEMALLOC_OVERRIDE___LIBC_FREE #undef JEMALLOC_OVERRIDE___LIBC_FREE
#undef JEMALLOC_OVERRIDE___LIBC_FREE_SIZED
#undef JEMALLOC_OVERRIDE___LIBC_FREE_ALIGNED_SIZED
#undef JEMALLOC_OVERRIDE___LIBC_MALLOC #undef JEMALLOC_OVERRIDE___LIBC_MALLOC
#undef JEMALLOC_OVERRIDE___LIBC_MEMALIGN #undef JEMALLOC_OVERRIDE___LIBC_MEMALIGN
#undef JEMALLOC_OVERRIDE___LIBC_REALLOC #undef JEMALLOC_OVERRIDE___LIBC_REALLOC

View File

@ -28,6 +28,9 @@ JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
JEMALLOC_CXX_THROW JEMALLOC_ALLOC_SIZE(2); JEMALLOC_CXX_THROW JEMALLOC_ALLOC_SIZE(2);
JEMALLOC_EXPORT void JEMALLOC_SYS_NOTHROW @je_@free(void *ptr) JEMALLOC_EXPORT void JEMALLOC_SYS_NOTHROW @je_@free(void *ptr)
JEMALLOC_CXX_THROW; JEMALLOC_CXX_THROW;
JEMALLOC_EXPORT void JEMALLOC_NOTHROW @je_@free_sized(void *ptr, size_t size);
JEMALLOC_EXPORT void JEMALLOC_NOTHROW @je_@free_aligned_sized(
void *ptr, size_t alignment, size_t size);
JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
void JEMALLOC_NOTHROW *@je_@mallocx(size_t size, int flags) void JEMALLOC_NOTHROW *@je_@mallocx(size_t size, int flags)

View File

@ -2990,6 +2990,16 @@ je_free(void *ptr) {
LOG("core.free.exit", ""); LOG("core.free.exit", "");
} }
JEMALLOC_EXPORT void JEMALLOC_NOTHROW
je_free_sized(void *ptr, size_t size) {
return je_sdallocx_noflags(ptr, size);
}
JEMALLOC_EXPORT void JEMALLOC_NOTHROW
je_free_aligned_sized(void *ptr, size_t alignment, size_t size) {
return je_sdallocx(ptr, size, /* flags */ MALLOCX_ALIGN(alignment));
}
/* /*
* End malloc(3)-compatible functions. * End malloc(3)-compatible functions.
*/ */
@ -3153,6 +3163,13 @@ void *__libc_calloc(size_t n, size_t size) PREALIAS(je_calloc);
# ifdef JEMALLOC_OVERRIDE___LIBC_FREE # ifdef JEMALLOC_OVERRIDE___LIBC_FREE
void __libc_free(void* ptr) PREALIAS(je_free); void __libc_free(void* ptr) PREALIAS(je_free);
# endif # endif
# ifdef JEMALLOC_OVERRIDE___LIBC_FREE_SIZED
void __libc_free_sized(void* ptr, size_t size) PREALIAS(je_free_sized);
# endif
# ifdef JEMALLOC_OVERRIDE___LIBC_FREE_ALIGNED_SIZED
void __libc_free_aligned_sized(
void* ptr, size_t alignment, size_t size) PREALIAS(je_free_aligned_sized);
# endif
# ifdef JEMALLOC_OVERRIDE___LIBC_MALLOC # ifdef JEMALLOC_OVERRIDE___LIBC_MALLOC
void *__libc_malloc(size_t size) PREALIAS(je_malloc); void *__libc_malloc(size_t size) PREALIAS(je_malloc);
# endif # endif