[v7,1/3] Add [v]aprintf(3)

Message ID f78192ebc9ce979ea3121960dac7492a2d62f5dc.1780138566.git.alx@kernel.org (mailing list archive)
State Changes Requested
Headers
Series Add [v]aprintf(3) |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent
linaro-tcwg-bot/tcwg_glibc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_glibc_check--master-arm fail Test failed
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 fail Test failed

Commit Message

Alejandro Colomar May 30, 2026, 10:59 a.m. UTC
  This function is fundamentally the same as asprintf(3) --which was
standardized in POSIX.1-2024--.

However, it has a key difference, which makes it a much better design.
Instead of returning the newly allocated pointer through a char**
parameter, it returns the pointer (like strdup(3)).  The API is as
simple as it can be:

	char *aprintf(const char *restrict fmt, ...);
	char *vaprintf(const char *restrict fmt, va_list ap);

This difference has several benefits:

-  One less parameter.  This means less source code for using this API,
   which implicitly means less chances of making mistakes.  It is also
   less noise while reading code, which increases readability.

   Especially, we get rid of a pointer-to-pointer parameter, which are
   especially weird.

-  The function has an prototype that resembles strdup(3).  This
   functionality is commonly paired with strdup(3) calls, because
   they're very related.  By having a similar prototype, the code is
   more naturally paired with

   Compare:

	if (cond) {
		p = strdup("foo");
		if (p == NULL)
			goto fail;
	} else {
		if (asprintf(&p, "foo %d", 42) < 0)
			goto fail;
	}
   vs
	p = cond ? strdup("foo") : aprintf("foo %d", 42);
	if (p == NULL)
		goto fail;

-  We don't need to fail with EOVERFLOW.  This initial implementation
   still fails with EOVERFLOW, because it would require a lot of work
   implementing it in a way that doesn't have such a failure point, but
   the API has no inherent reasons to fail with EOVERFLOW.

-  This API returns a pointer, which makes it possible to use
   __attribute__((__malloc__(free))).  This would allow static analysers
   to know that these APIs allocate memory, which would prevent memory
   leaks, use-after-free errors, and other common issues of handling
   memory.

The name is similar to asprintf(3), removing the 's'.  This is the same
name that gnulib has used for their implementation.  It also matches the
name of the n3750 (alx-0007) proposal for ISO C2y.

The C Committee was worried that such a non-reserved name might be
unlikely to be viable, as some existing code already uses it.  However:

-  Most code using this name, uses it with the same exact semantics.
   In those cases, it's not a problem.

-  In the remaining cases, the prototype is different, so they'll
   eventually get a compiler error for the clash.  This is entirely
   safe.  And by hiding the name under _GNU_SOURCE, we make that clash
   less likely.  Once/if this is eventually standard, I expect people
   will adapt their code, which is entirely reasonable.  Still, then the
   APIs will be hidden under _ISOC2Y_SOURCE et al., so this will only
   affect users when they opt-in to such a version.

Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3750.txt>
Cc: Joseph Myers <josmyers@redhat.com>
Cc: Paul Eggert <eggert@cs.ucla.edu>
Cc: Bruno Haible <bruno@clisp.org>
Cc: Adhemerval Zanella Netto <adhemerval.zanella@linaro.org>
Cc: Florian Weimer <fweimer@redhat.com>
Cc: "Dmitry V. Levin" <ldv@altlinux.org>
Cc: Archie Cobbs <archie.cobbs@gmail.com>
Cc: Solar Designer <solar@openwall.com>
Cc: Sam James <sam@gentoo.org>
Cc: Andreas Schwab <schwab@suse.de>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 debug/Makefile                                |  4 +
 debug/Versions                                |  3 +
 debug/aprintf_chk.c                           | 51 +++++++++++++
 debug/vaprintf_chk.c                          | 39 ++++++++++
 include/stdio.h                               |  8 ++
 libio/Makefile                                |  4 +-
 libio/Versions                                |  3 +
 libio/bits/stdio-ldbl.h                       |  5 ++
 libio/bits/stdio2-decl.h                      |  8 ++
 libio/bits/stdio2.h                           | 42 +++++++++++
 libio/stdio.h                                 | 13 ++++
 libio/tst-aprintf.c                           | 73 +++++++++++++++++++
 libio/vaprintf.c                              | 39 ++++++++++
 manual/stdio.texi                             | 26 +++++++
 stdio-common/Makefile                         |  2 +
 stdio-common/Versions                         |  3 +
 stdio-common/aprintf.c                        | 40 ++++++++++
 sysdeps/ieee754/ldbl-128ibm-compat/Makefile   |  8 +-
 sysdeps/ieee754/ldbl-128ibm-compat/Versions   |  6 ++
 .../ldbl-128ibm-compat/ieee128-aprintf.c      | 36 +++++++++
 .../ldbl-128ibm-compat/ieee128-aprintf_chk.c  | 40 ++++++++++
 .../ldbl-128ibm-compat/ieee128-vaprintf.c     | 29 ++++++++
 .../ldbl-128ibm-compat/ieee128-vaprintf_chk.c | 31 ++++++++
 .../test-printf-chk-ldbl-compat.c             | 31 +++++++-
 .../test-printf-ldbl-compat.c                 | 31 +++++++-
 sysdeps/ieee754/ldbl-opt/Makefile             |  6 ++
 sysdeps/ieee754/ldbl-opt/Versions             | 10 +++
 sysdeps/ieee754/ldbl-opt/nldbl-aprintf.c      | 17 +++++
 sysdeps/ieee754/ldbl-opt/nldbl-aprintf_chk.c  | 15 ++++
 sysdeps/ieee754/ldbl-opt/nldbl-compat.c       | 59 +++++++++++++++
 sysdeps/ieee754/ldbl-opt/nldbl-compat.h       |  5 ++
 sysdeps/ieee754/ldbl-opt/nldbl-vaprintf.c     |  9 +++
 sysdeps/ieee754/ldbl-opt/nldbl-vaprintf_chk.c |  8 ++
 sysdeps/mach/hurd/i386/libc.abilist           |  5 ++
 sysdeps/mach/hurd/x86_64/libc.abilist         |  5 ++
 sysdeps/unix/sysv/linux/aarch64/libc.abilist  |  5 ++
 sysdeps/unix/sysv/linux/alpha/libc.abilist    |  5 ++
 sysdeps/unix/sysv/linux/arc/libc.abilist      |  5 ++
 sysdeps/unix/sysv/linux/arm/be/libc.abilist   |  5 ++
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |  5 ++
 sysdeps/unix/sysv/linux/csky/libc.abilist     |  5 ++
 sysdeps/unix/sysv/linux/hppa/libc.abilist     |  5 ++
 sysdeps/unix/sysv/linux/i386/libc.abilist     |  5 ++
 .../sysv/linux/loongarch/lp64/libc.abilist    |  5 ++
 .../sysv/linux/m68k/coldfire/libc.abilist     |  5 ++
 .../unix/sysv/linux/m68k/m680x0/libc.abilist  |  5 ++
 .../sysv/linux/microblaze/be/libc.abilist     |  5 ++
 .../sysv/linux/microblaze/le/libc.abilist     |  5 ++
 .../sysv/linux/mips/mips32/fpu/libc.abilist   |  5 ++
 .../sysv/linux/mips/mips32/nofpu/libc.abilist |  5 ++
 .../sysv/linux/mips/mips64/n32/libc.abilist   |  5 ++
 .../sysv/linux/mips/mips64/n64/libc.abilist   |  5 ++
 sysdeps/unix/sysv/linux/or1k/libc.abilist     |  5 ++
 .../linux/powerpc/powerpc32/fpu/libc.abilist  |  5 ++
 .../powerpc/powerpc32/nofpu/libc.abilist      |  5 ++
 .../linux/powerpc/powerpc64/be/libc.abilist   |  5 ++
 .../linux/powerpc/powerpc64/le/libc.abilist   |  5 ++
 .../unix/sysv/linux/riscv/rv32/libc.abilist   |  5 ++
 .../unix/sysv/linux/riscv/rv64/libc.abilist   |  5 ++
 sysdeps/unix/sysv/linux/s390/libc.abilist     |  5 ++
 sysdeps/unix/sysv/linux/sh/be/libc.abilist    |  5 ++
 sysdeps/unix/sysv/linux/sh/le/libc.abilist    |  5 ++
 .../sysv/linux/sparc/sparc32/libc.abilist     |  5 ++
 .../sysv/linux/sparc/sparc64/libc.abilist     |  5 ++
 .../unix/sysv/linux/x86_64/64/libc.abilist    |  5 ++
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |  5 ++
 66 files changed, 863 insertions(+), 6 deletions(-)
 create mode 100644 debug/aprintf_chk.c
 create mode 100644 debug/vaprintf_chk.c
 create mode 100644 libio/tst-aprintf.c
 create mode 100644 libio/vaprintf.c
 create mode 100644 stdio-common/aprintf.c
 create mode 100644 sysdeps/ieee754/ldbl-128ibm-compat/ieee128-aprintf.c
 create mode 100644 sysdeps/ieee754/ldbl-128ibm-compat/ieee128-aprintf_chk.c
 create mode 100644 sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vaprintf.c
 create mode 100644 sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vaprintf_chk.c
 create mode 100644 sysdeps/ieee754/ldbl-opt/nldbl-aprintf.c
 create mode 100644 sysdeps/ieee754/ldbl-opt/nldbl-aprintf_chk.c
 create mode 100644 sysdeps/ieee754/ldbl-opt/nldbl-vaprintf.c
 create mode 100644 sysdeps/ieee754/ldbl-opt/nldbl-vaprintf_chk.c
  

Comments

Adhemerval Zanella Netto June 3, 2026, 4:45 p.m. UTC | #1
On 30/05/26 07:59, Alejandro Colomar wrote:
> This function is fundamentally the same as asprintf(3) --which was
> standardized in POSIX.1-2024--.
> 
> However, it has a key difference, which makes it a much better design.
> Instead of returning the newly allocated pointer through a char**
> parameter, it returns the pointer (like strdup(3)).  The API is as
> simple as it can be:
> 
> 	char *aprintf(const char *restrict fmt, ...);
> 	char *vaprintf(const char *restrict fmt, va_list ap);
> 
> This difference has several benefits:
> 
> -  One less parameter.  This means less source code for using this API,
>    which implicitly means less chances of making mistakes.  It is also
>    less noise while reading code, which increases readability.
> 
>    Especially, we get rid of a pointer-to-pointer parameter, which are
>    especially weird.
> 
> -  The function has an prototype that resembles strdup(3).  This
>    functionality is commonly paired with strdup(3) calls, because
>    they're very related.  By having a similar prototype, the code is
>    more naturally paired with
> 
>    Compare:
> 
> 	if (cond) {
> 		p = strdup("foo");
> 		if (p == NULL)
> 			goto fail;
> 	} else {
> 		if (asprintf(&p, "foo %d", 42) < 0)
> 			goto fail;
> 	}
>    vs
> 	p = cond ? strdup("foo") : aprintf("foo %d", 42);
> 	if (p == NULL)
> 		goto fail;
> 
> -  We don't need to fail with EOVERFLOW.  This initial implementation
>    still fails with EOVERFLOW, because it would require a lot of work
>    implementing it in a way that doesn't have such a failure point, but
>    the API has no inherent reasons to fail with EOVERFLOW.

I think it should be disable by either extending __vasprintf_internal 
(with a flag that returns -1/EOVERFLOW to use on the current interface or 
functions where it should return int) or adding a new 
__vasprintf_internal_ex that:

1. Calls a new function simila to __printf_buffer_done (include/printf_buffer.h:195) 
   that return ptrdiff_t (or int64_).

2. Calls a new __printf_buffer_flush_asprintf (libio/vasprintf.c) that does 
   not bails early with EOVERFLOW once current_pos >= INT_MAX.

But I do not think this is a hard requirement, nor a blocker for this patch 
(I am not sure if Florian agrees, so I would check with him). But at the same 
time I think it would be worth exploring whether we can avoid this limitation.

For the overflow case, I think we should properly document this in the manual
entry.

> 
> -  This API returns a pointer, which makes it possible to use
>    __attribute__((__malloc__(free))).  This would allow static analysers
>    to know that these APIs allocate memory, which would prevent memory
>    leaks, use-after-free errors, and other common issues of handling
>    memory.
> 
> The name is similar to asprintf(3), removing the 's'.  This is the same
> name that gnulib has used for their implementation.  It also matches the
> name of the n3750 (alx-0007) proposal for ISO C2y.
> 
> The C Committee was worried that such a non-reserved name might be
> unlikely to be viable, as some existing code already uses it.  However:
> 
> -  Most code using this name, uses it with the same exact semantics.
>    In those cases, it's not a problem.
> 
> -  In the remaining cases, the prototype is different, so they'll
>    eventually get a compiler error for the clash.  This is entirely
>    safe.  And by hiding the name under _GNU_SOURCE, we make that clash
>    less likely.  Once/if this is eventually standard, I expect people
>    will adapt their code, which is entirely reasonable.  Still, then the
>    APIs will be hidden under _ISOC2Y_SOURCE et al., so this will only
>    affect users when they opt-in to such a version.
> 
> Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3750.txt>

Let's try to disintagle this patch.  I saw a build failure for alpha,
powerpc (ppc64, ppc64le, ppc32), s390x, and sparcv9:

$ alpha-glibc-linux-gnu-gcc ../sysdeps/ieee754/ldbl-opt/nldbl-compat.c [...]
../sysdeps/ieee754/ldbl-opt/nldbl-compat.c:60:1: error: conflicting types for ‘__nldbl___aprintf’; have ‘int(const char *, ...)’
   60 | __nldbl___aprintf (const char *fmt, ...)
      | ^~~~~~~~~~~~~~~~~
In file included from ../sysdeps/ieee754/ldbl-opt/nldbl-compat.c:38:
../sysdeps/ieee754/ldbl-opt/nldbl-compat.h:43:49: note: previous declaration of ‘__nldbl___aprintf’ with type ‘char *(const char *, ...)’
   43 | #define NLDBL_DECL(name) extern __typeof (name) __nldbl_##name
      |                                                 ^~~~~~~~
../sysdeps/ieee754/ldbl-opt/nldbl-compat.h:61:1: note: in expansion of macro ‘NLDBL_DECL’
   61 | NLDBL_DECL (__aprintf);
      | ^~~~~~~~~~
../sysdeps/ieee754/ldbl-opt/nldbl-compat.c: In function ‘__nldbl___aprintf’:
../sysdeps/ieee754/ldbl-opt/nldbl-compat.c:70:10: error: returning ‘char *’ from a function with return type ‘int’ makes integer from pointer without a cast [-Wint-conversion]
   70 |   return p;
      |          ^
In file included from <command-line>:
../sysdeps/ieee754/ldbl-opt/nldbl-compat.c: At top level:
../sysdeps/ieee754/ldbl-opt/nldbl-compat.c:72:32: error: conflicting types for ‘__nldbl_aprintf’; have ‘int(const char *, ...)’
   72 | weak_alias (__nldbl___aprintf, __nldbl_aprintf)
      |                                ^~~~~~~~~~~~~~~
./../include/libc-symbols.h:157:26: note: in definition of macro ‘_weak_alias’
  157 |   extern __typeof (name) aliasname __attribute__ ((weak, alias (#name))) \
      |                          ^~~~~~~~~
../sysdeps/ieee754/ldbl-opt/nldbl-compat.c:72:1: note: in expansion of macro ‘weak_alias’
   72 | weak_alias (__nldbl___aprintf, __nldbl_aprintf)
      | ^~~~~~~~~~
../sysdeps/ieee754/ldbl-opt/nldbl-compat.h:43:49: note: previous declaration of ‘__nldbl_aprintf’ with type ‘char *(const char *, ...)’
   43 | #define NLDBL_DECL(name) extern __typeof (name) __nldbl_##name
      |                                                 ^~~~~~~~
../sysdeps/ieee754/ldbl-opt/nldbl-compat.h:62:1: note: in expansion of macro ‘NLDBL_DECL’
   62 | NLDBL_DECL (aprintf);
      | ^~~~~~~~~~

The __nldbl___aprintf has the wrong return type — int instead of char *.


> Cc: Joseph Myers <josmyers@redhat.com>
> Cc: Paul Eggert <eggert@cs.ucla.edu>
> Cc: Bruno Haible <bruno@clisp.org>
> Cc: Adhemerval Zanella Netto <adhemerval.zanella@linaro.org>
> Cc: Florian Weimer <fweimer@redhat.com>
> Cc: "Dmitry V. Levin" <ldv@altlinux.org>
> Cc: Archie Cobbs <archie.cobbs@gmail.com>
> Cc: Solar Designer <solar@openwall.com>
> Cc: Sam James <sam@gentoo.org>
> Cc: Andreas Schwab <schwab@suse.de>
> Signed-off-by: Alejandro Colomar <alx@kernel.org>
> ---
>  debug/Makefile                                |  4 +
>  debug/Versions                                |  3 +
>  debug/aprintf_chk.c                           | 51 +++++++++++++
>  debug/vaprintf_chk.c                          | 39 ++++++++++
>  include/stdio.h                               |  8 ++
>  libio/Makefile                                |  4 +-
>  libio/Versions                                |  3 +
>  libio/bits/stdio-ldbl.h                       |  5 ++
>  libio/bits/stdio2-decl.h                      |  8 ++
>  libio/bits/stdio2.h                           | 42 +++++++++++
>  libio/stdio.h                                 | 13 ++++
>  libio/tst-aprintf.c                           | 73 +++++++++++++++++++
>  libio/vaprintf.c                              | 39 ++++++++++
>  manual/stdio.texi                             | 26 +++++++
>  stdio-common/Makefile                         |  2 +
>  stdio-common/Versions                         |  3 +
>  stdio-common/aprintf.c                        | 40 ++++++++++
>  sysdeps/ieee754/ldbl-128ibm-compat/Makefile   |  8 +-
>  sysdeps/ieee754/ldbl-128ibm-compat/Versions   |  6 ++
>  .../ldbl-128ibm-compat/ieee128-aprintf.c      | 36 +++++++++
>  .../ldbl-128ibm-compat/ieee128-aprintf_chk.c  | 40 ++++++++++
>  .../ldbl-128ibm-compat/ieee128-vaprintf.c     | 29 ++++++++
>  .../ldbl-128ibm-compat/ieee128-vaprintf_chk.c | 31 ++++++++
>  .../test-printf-chk-ldbl-compat.c             | 31 +++++++-
>  .../test-printf-ldbl-compat.c                 | 31 +++++++-
>  sysdeps/ieee754/ldbl-opt/Makefile             |  6 ++
>  sysdeps/ieee754/ldbl-opt/Versions             | 10 +++
>  sysdeps/ieee754/ldbl-opt/nldbl-aprintf.c      | 17 +++++
>  sysdeps/ieee754/ldbl-opt/nldbl-aprintf_chk.c  | 15 ++++
>  sysdeps/ieee754/ldbl-opt/nldbl-compat.c       | 59 +++++++++++++++
>  sysdeps/ieee754/ldbl-opt/nldbl-compat.h       |  5 ++
>  sysdeps/ieee754/ldbl-opt/nldbl-vaprintf.c     |  9 +++
>  sysdeps/ieee754/ldbl-opt/nldbl-vaprintf_chk.c |  8 ++
>  sysdeps/mach/hurd/i386/libc.abilist           |  5 ++
>  sysdeps/mach/hurd/x86_64/libc.abilist         |  5 ++
>  sysdeps/unix/sysv/linux/aarch64/libc.abilist  |  5 ++
>  sysdeps/unix/sysv/linux/alpha/libc.abilist    |  5 ++
>  sysdeps/unix/sysv/linux/arc/libc.abilist      |  5 ++
>  sysdeps/unix/sysv/linux/arm/be/libc.abilist   |  5 ++
>  sysdeps/unix/sysv/linux/arm/le/libc.abilist   |  5 ++
>  sysdeps/unix/sysv/linux/csky/libc.abilist     |  5 ++
>  sysdeps/unix/sysv/linux/hppa/libc.abilist     |  5 ++
>  sysdeps/unix/sysv/linux/i386/libc.abilist     |  5 ++
>  .../sysv/linux/loongarch/lp64/libc.abilist    |  5 ++
>  .../sysv/linux/m68k/coldfire/libc.abilist     |  5 ++
>  .../unix/sysv/linux/m68k/m680x0/libc.abilist  |  5 ++
>  .../sysv/linux/microblaze/be/libc.abilist     |  5 ++
>  .../sysv/linux/microblaze/le/libc.abilist     |  5 ++
>  .../sysv/linux/mips/mips32/fpu/libc.abilist   |  5 ++
>  .../sysv/linux/mips/mips32/nofpu/libc.abilist |  5 ++
>  .../sysv/linux/mips/mips64/n32/libc.abilist   |  5 ++
>  .../sysv/linux/mips/mips64/n64/libc.abilist   |  5 ++
>  sysdeps/unix/sysv/linux/or1k/libc.abilist     |  5 ++
>  .../linux/powerpc/powerpc32/fpu/libc.abilist  |  5 ++
>  .../powerpc/powerpc32/nofpu/libc.abilist      |  5 ++
>  .../linux/powerpc/powerpc64/be/libc.abilist   |  5 ++
>  .../linux/powerpc/powerpc64/le/libc.abilist   |  5 ++
>  .../unix/sysv/linux/riscv/rv32/libc.abilist   |  5 ++
>  .../unix/sysv/linux/riscv/rv64/libc.abilist   |  5 ++
>  sysdeps/unix/sysv/linux/s390/libc.abilist     |  5 ++
>  sysdeps/unix/sysv/linux/sh/be/libc.abilist    |  5 ++
>  sysdeps/unix/sysv/linux/sh/le/libc.abilist    |  5 ++
>  .../sysv/linux/sparc/sparc32/libc.abilist     |  5 ++
>  .../sysv/linux/sparc/sparc64/libc.abilist     |  5 ++
>  .../unix/sysv/linux/x86_64/64/libc.abilist    |  5 ++
>  .../unix/sysv/linux/x86_64/x32/libc.abilist   |  5 ++
>  66 files changed, 863 insertions(+), 6 deletions(-)
>  create mode 100644 debug/aprintf_chk.c
>  create mode 100644 debug/vaprintf_chk.c
>  create mode 100644 libio/tst-aprintf.c
>  create mode 100644 libio/vaprintf.c
>  create mode 100644 stdio-common/aprintf.c
>  create mode 100644 sysdeps/ieee754/ldbl-128ibm-compat/ieee128-aprintf.c
>  create mode 100644 sysdeps/ieee754/ldbl-128ibm-compat/ieee128-aprintf_chk.c
>  create mode 100644 sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vaprintf.c
>  create mode 100644 sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vaprintf_chk.c
>  create mode 100644 sysdeps/ieee754/ldbl-opt/nldbl-aprintf.c
>  create mode 100644 sysdeps/ieee754/ldbl-opt/nldbl-aprintf_chk.c
>  create mode 100644 sysdeps/ieee754/ldbl-opt/nldbl-vaprintf.c
>  create mode 100644 sysdeps/ieee754/ldbl-opt/nldbl-vaprintf_chk.c
> 
> diff --git a/debug/Makefile b/debug/Makefile
> index c6c1069b405a..765720a14083 100644
> --- a/debug/Makefile
> +++ b/debug/Makefile
> @@ -31,6 +31,7 @@ headers	:= execinfo.h
>  routines = \
>    $(static-only-routines) \
>    ____longjmp_chk \
> +  aprintf_chk \
>    asprintf_chk \
>    backtrace \
>    backtracesyms \
> @@ -94,6 +95,7 @@ routines = \
>    strncpy_chk \
>    swprintf_chk \
>    ttyname_r_chk \
> +  vaprintf_chk \
>    vasprintf_chk \
>    vdprintf_chk \
>    vfprintf_chk \
> @@ -143,6 +145,8 @@ CFLAGS-sprintf_chk.c += $(libio-mtsafe)
>  CFLAGS-snprintf_chk.c += $(libio-mtsafe)
>  CFLAGS-vsprintf_chk.c += $(libio-mtsafe)
>  CFLAGS-vsnprintf_chk.c += $(libio-mtsafe)
> +CFLAGS-aprintf_chk.c += $(libio-mtsafe)
> +CFLAGS-vaprintf_chk.c += $(libio-mtsafe)
>  CFLAGS-asprintf_chk.c += $(libio-mtsafe)
>  CFLAGS-vasprintf_chk.c += $(libio-mtsafe)
>  CFLAGS-obprintf_chk.c += $(libio-mtsafe)
> diff --git a/debug/Versions b/debug/Versions
> index fc818d29aa75..d87148f5a30f 100644
> --- a/debug/Versions
> +++ b/debug/Versions
> @@ -71,6 +71,9 @@ libc {
>    GLIBC_2.43 {
>      __memset_explicit_chk;
>    }
> +  GLIBC_2.44 {
> +    __aprintf_chk; __vaprintf_chk;
> +  }
>    GLIBC_PRIVATE {
>      __fortify_fail;
>    }
> diff --git a/debug/aprintf_chk.c b/debug/aprintf_chk.c
> new file mode 100644
> index 000000000000..30f7811f20da
> --- /dev/null
> +++ b/debug/aprintf_chk.c
> @@ -0,0 +1,51 @@
> +/* Copyright (C) 2026 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <stdarg.h>
> +#include <libio/libioP.h>
> +
> +
> +/* Write formatted output from FORMAT to a string allocated with malloc.  */
> +char *
> +___aprintf_chk (int flag, const char *fmt, ...)
> +{
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +     can only come from read-only format strings.  */
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
> +  va_list ap;
> +  char *p;
> +
> +  va_start (ap, fmt);
> +  if (__vasprintf_internal (&p, fmt, ap, mode) < 0)
> +    p = NULL;
> +  va_end (ap);
> +
> +  return p;
> +}

Adds some tests on debug/tst-fortify.c.

> +#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
> +/* This is needed since <bits/stdio-lbdl.h> is included in this case, leading to
> + * multiple asm redirection of the same symbol
> + */
> +ldbl_hidden_def (___aprintf_chk, __aprintf_chk)
> +ldbl_strong_alias (___aprintf_chk, __aprintf_chk)
> +#else
> +/* On some systems introduction of ldbl_* macros lead to ABI breakage due to the
> + * long_double_symbol aliasing.
> + */
> +strong_alias (___aprintf_chk, __aprintf_chk)
> +libc_hidden_def (__aprintf_chk)
> +#endif
> diff --git a/debug/vaprintf_chk.c b/debug/vaprintf_chk.c
> new file mode 100644
> index 000000000000..1ca966337d11
> --- /dev/null
> +++ b/debug/vaprintf_chk.c
> @@ -0,0 +1,39 @@
> +/* Copyright (C) 2026 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.
> +
> +   As a special exception, if you link the code in this file with
> +   files compiled with a GNU compiler to produce an executable,
> +   that does not cause the resulting executable to be covered by
> +   the GNU Lesser General Public License.  This exception does not
> +   however invalidate any other reasons why the executable file
> +   might be covered by the GNU Lesser General Public License.
> +   This exception applies to code released by its copyright holders
> +   in files containing the exception.  */
> +
> +#include <libio/libioP.h>
> +
> +char *
> +__vaprintf_chk (int flag, const char *fmt, va_list ap)
> +{
> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> +     can only come from read-only format strings.  */
> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
> +  char *p;
> +
> +  return __vasprintf_internal (&p, fmt, ap, mode) < 0 ? NULL : p;
> +}
> +libc_hidden_def (__vaprintf_chk)
> diff --git a/include/stdio.h b/include/stdio.h
> index 88166993dd95..cfdec3681d51 100644
> --- a/include/stdio.h
> +++ b/include/stdio.h
> @@ -77,6 +77,11 @@ extern int __vfprintf_chk (FILE *, int, const char *, __gnuc_va_list);
>  stdio_hidden_ldbl_proto (__, vfprintf_chk)
>  extern char *__fgets_unlocked_chk (char *buf, size_t size, int n, FILE *fp);
>  extern char *__fgets_chk (char *buf, size_t size, int n, FILE *fp);
> +extern char *__aprintf_chk (int, const char *, ...)
> +     __THROW __attribute_malloc__;
> +extern char *__vaprintf_chk (int, const char *, __gnuc_va_list)
> +     __THROW __attribute_malloc__;
> +stdio_hidden_ldbl_proto (__, vaprintf_chk)
>  extern int __asprintf_chk (char **, int, const char *, ...) __THROW;
>  extern int __vasprintf_chk (char **, int, const char *, __gnuc_va_list) __THROW;
>  stdio_hidden_ldbl_proto (__, vasprintf_chk)
> @@ -239,6 +244,7 @@ extern const size_t _sys_errlist_internal_len attribute_hidden;
>  extern const char *__get_errlist (int) attribute_hidden;
>  extern const char *__get_errname (int) attribute_hidden;
>  
> +libc_hidden_ldbl_proto (__aprintf)
>  libc_hidden_ldbl_proto (__asprintf)
>  
>  #  if IS_IN (libc)
> @@ -317,8 +323,10 @@ rtld_hidden_proto (__libc_fatal)
>  libc_hidden_proto (__fgets_unlocked_chk)
>  
>  #if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
> +libc_hidden_ldbl_proto (__aprintf_chk)
>  libc_hidden_ldbl_proto (__asprintf_chk)
>  #else
> +libc_hidden_proto (__aprintf_chk)
>  libc_hidden_proto (__asprintf_chk)
>  #endif
>  
> diff --git a/libio/Makefile b/libio/Makefile
> index a8011a7f0d76..c50a96df1879 100644
> --- a/libio/Makefile
> +++ b/libio/Makefile
> @@ -43,7 +43,7 @@ routines	:=							      \
>  									      \
>  	clearerr feof ferror fileno fputc freopen fseek getc getchar	      \
>  	memstream pclose putc putchar rewind setbuf setlinebuf vasprintf      \
> -	iovdprintf vscanf vsnprintf obprintf fcloseall fseeko ftello	      \
> +	vaprintf iovdprintf vscanf vsnprintf obprintf fcloseall fseeko ftello \
>  	freopen64 fseeko64 ftello64					      \
>  									      \
>  	__fbufsize __freading __fwriting __freadable __fwritable __flbf	      \
> @@ -62,6 +62,7 @@ routines_no_fortify += \
>    iofgetws_u \
>    iovdprintf \
>    swprintf \
> +  vaprintf \
>    vasprintf \
>    vsnprintf \
>    vswprintf \
> @@ -91,6 +92,7 @@ tests = \
>    test-fmemopen \
>    test-fputs-unbuffered-full \
>    test-fputws-unbuffered-full \
> +  tst-aprintf \
>    tst-asprintf-null \
>    tst-atime \
>    tst-bz22415 \
> diff --git a/libio/Versions b/libio/Versions
> index b91a7bc914ae..48ffe3d3161f 100644
> --- a/libio/Versions
> +++ b/libio/Versions
> @@ -155,6 +155,9 @@ libc {
>      # f*
>      fmemopen;
>    }
> +  GLIBC_2.44 {
> +    vaprintf;
> +  }
>    GLIBC_PRIVATE {
>      # Used by NPTL and librt
>      __libc_fatal;
> diff --git a/libio/bits/stdio-ldbl.h b/libio/bits/stdio-ldbl.h
> index 3cbff14ec959..3b805b3ee3e3 100644
> --- a/libio/bits/stdio-ldbl.h
> +++ b/libio/bits/stdio-ldbl.h
> @@ -99,6 +99,9 @@ __LDBL_REDIR_DECL (dprintf)
>  #endif
>  
>  #ifdef __USE_GNU
> +__LDBL_REDIR_DECL (vaprintf)
> +__LDBL_REDIR2_DECL (aprintf)
> +__LDBL_REDIR_DECL (aprintf)
>  __LDBL_REDIR_DECL (vasprintf)
>  __LDBL_REDIR2_DECL (asprintf)
>  __LDBL_REDIR_DECL (asprintf)
> @@ -123,6 +126,8 @@ __LDBL_REDIR2_DECL (dprintf_chk)
>  __LDBL_REDIR2_DECL (vdprintf_chk)
>  #  endif
>  #  ifdef __USE_GNU
> +__LDBL_REDIR2_DECL (aprintf_chk)
> +__LDBL_REDIR2_DECL (vaprintf_chk)
>  __LDBL_REDIR2_DECL (asprintf_chk)
>  __LDBL_REDIR2_DECL (vasprintf_chk)
>  __LDBL_REDIR2_DECL (obstack_printf_chk)
> diff --git a/libio/bits/stdio2-decl.h b/libio/bits/stdio2-decl.h
> index ada092eab2b4..cf52c46c31f6 100644
> --- a/libio/bits/stdio2-decl.h
> +++ b/libio/bits/stdio2-decl.h
> @@ -66,6 +66,14 @@ extern int __vdprintf_chk (int __fd, int __flag,
>  
>  # ifdef __USE_GNU
>  
> +extern char *__aprintf_chk (int __flag,
> +			   const char *__restrict __fmt, ...)
> +     __THROW __attribute__ ((__format__ (__printf__, 2, 3)))
> +     __attribute_malloc__;
> +extern char *__vaprintf_chk (int __flag,
> +			    const char *__restrict __fmt, __gnuc_va_list __ap)
> +     __THROW __attribute__ ((__format__ (__printf__, 2, 0)))
> +     __attribute_malloc__;
>  extern int __asprintf_chk (char **__restrict __ptr, int __flag,
>  			   const char *__restrict __fmt, ...)
>       __THROW __attribute__ ((__format__ (__printf__, 3, 4))) __wur;
> diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h
> index 193494db2787..b9fed67eac59 100644
> --- a/libio/bits/stdio2.h
> +++ b/libio/bits/stdio2.h
> @@ -200,6 +200,18 @@ vdprintf (int __fd, const char *__restrict __fmt, __gnuc_va_list __ap)
>  
>  # ifdef __USE_GNU
>  #  ifdef __va_arg_pack
> +__fortify_function char *
> +__NTH (aprintf (const char *__restrict __fmt, ...))
> +{
> +  return __aprintf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __va_arg_pack ());
> +}
> +
> +__fortify_function char *
> +__NTH (__aprintf (const char *__restrict __fmt, ...))
> +{
> +  return __aprintf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __va_arg_pack ());
> +}
> +
>  __fortify_function int
>  __NTH (asprintf (char **__restrict __ptr, const char *__restrict __fmt, ...))
>  {
> @@ -223,6 +235,26 @@ __NTH (obstack_printf (struct obstack *__restrict __obstack,
>  			       __va_arg_pack ());
>  }
>  #  elif __fortify_use_clang
> +__fortify_function char *
> +__NTH (aprintf (const char *__restrict __fmt, ...))
> +{
> +  __gnuc_va_list __fortify_ap;
> +  __builtin_va_start (__fortify_ap, __fmt);
> +  char * __p = __vaprintf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __fortify_ap);
> +  __builtin_va_end (__fortify_ap);
> +  return __p;
> +}
> +
> +__fortify_function char *
> +__NTH (__aprintf (const char *__restrict __fmt, ...))
> +{
> +  __gnuc_va_list __fortify_ap;
> +  __builtin_va_start (__fortify_ap, __fmt);
> +  char *__p = __vaprintf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __fortify_ap);
> +  __builtin_va_end (__fortify_ap);
> +  return __p;
> +}
> +
>  __fortify_function_error_function __attribute_overloadable__ int
>  __NTH (asprintf (__fortify_clang_overload_arg (char **, __restrict, __ptr),
>  		 const char *__restrict __fmt, ...))
> @@ -260,6 +292,10 @@ __NTH (obstack_printf (__fortify_clang_overload_arg (struct obstack *,
>    return __r;
>  }
>  #  elif !defined __cplusplus
> +#   define aprintf(...) \
> +  __aprintf_chk (__USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
> +#   define __aprintf(...) \
> +  __aprintf_chk (__USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
>  #   define asprintf(ptr, ...) \
>    __asprintf_chk (ptr, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
>  #   define __asprintf(ptr, ...) \
> @@ -268,6 +304,12 @@ __NTH (obstack_printf (__fortify_clang_overload_arg (struct obstack *,
>    __obstack_printf_chk (obstack, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
>  #  endif
>  
> +__fortify_function char *
> +__NTH (vaprintf (const char *__restrict __fmt, __gnuc_va_list __ap))
> +{
> +  return __vaprintf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __ap);
> +}
> +
>  __fortify_function int
>  __NTH (vasprintf (char **__restrict __ptr, const char *__restrict __fmt,
>  		  __gnuc_va_list __ap))
> diff --git a/libio/stdio.h b/libio/stdio.h
> index 3bf6a1f63203..81d7176c4535 100644
> --- a/libio/stdio.h
> +++ b/libio/stdio.h
> @@ -412,6 +412,19 @@ extern int asprintf (char **__restrict __ptr,
>       __THROWNL __attribute__ ((__format__ (__printf__, 2, 3))) __wur;
>  #endif
>  
> +#ifdef __USE_GNU
> +/* Write formatted output to a string dynamically allocated with `malloc'.  */
> +extern char *vaprintf (const char *__restrict __fmt, __gnuc_va_list __ap)
> +     __THROWNL __attribute__ ((__format__ (__printf__, 1, 0)))
> +     __attribute_malloc__;

I think we should add __attr_dealloc_free, that one of the main advertises for
this symbol. Smae for asprintf and the __chk variants.

> +extern char *__aprintf (const char *__restrict __fmt, ...)
> +     __THROWNL __attribute__ ((__format__ (__printf__, 1, 2)))
> +     __attribute_malloc__;

I think there is no need to export the __aprintf for a new symbol, we did it
on other symbols (like scanf) we can asm alias depending of the C standard
being used. Since this is a new symbol, we can just use the aprintf.

> +extern char *aprintf (const char *__restrict __fmt, ...)
> +     __THROWNL __attribute__ ((__format__ (__printf__, 1, 2)))
> +     __attribute_malloc__;
> +#endif
> +
>  #ifdef __USE_XOPEN2K8
>  /* Write formatted output to a file descriptor.  */
>  extern int vdprintf (int __fd, const char *__restrict __fmt,
> diff --git a/libio/tst-aprintf.c b/libio/tst-aprintf.c
> new file mode 100644
> index 000000000000..0c7d7a8024c3
> --- /dev/null
> +++ b/libio/tst-aprintf.c
> @@ -0,0 +1,73 @@
> +/* Test aprintf.
> +   Copyright (C) 2026 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <support/check.h>
> +#include <sys/resource.h>
> +#include <libc-diag.h>
> +
> +static int
> +do_test (void)
> +{
> +  char *buf;
> +
> +  /* Success */
> +  buf = aprintf ("foo %d", 42);
> +  TEST_COMPARE_STRING (buf, "foo 42");
> +  free(buf);
> +
> +  {
> +    /* -Wformat-overflow warns that the format would produce more than
> +       INT_MAX bytes; however, this function does not share this
> +       inherent limitation of other printf-like functions.  The current
> +       implementation fails with EOVERFLOW, because it's a trivial
> +       wrapper; however, in the future we should improve the function so
> +       that this doesn't fail anymore with EOVERFLOW.  When that is
> +       implemented, this test will stop failing.  */
> +    DIAG_PUSH_NEEDS_COMMENT;
> +    DIAG_IGNORE_NEEDS_COMMENT (8, "-Wformat-overflow=");
> +    buf = aprintf ("%2000000000d %2000000000d", 1, 2);

Does it work on ILP32 ABIs (x32 and mips64-n32)?

> +    DIAG_POP_NEEDS_COMMENT;
> +#if 0
> +    if (buf == NULL)
> +      TEST_VERIFY (errno == ENOMEM);
> +#else

Plase remove the '#if 0' path here.

> +    /* We should eventually not fail with EOVERFLOW from aprintf.  When
> +       that happens, this test will fail.  Just remove it and enable the
> +       test under '#if 0'.  */
> +    TEST_VERIFY (buf == NULL);
> +    TEST_VERIFY (errno == EOVERFLOW);
> +#endif
> +  }
> +
> +  /* Force ENOMEM in the test below.  */
> +  struct rlimit rl;
> +  TEST_COMPARE (getrlimit (RLIMIT_AS, &rl), 0);
> +  rl.rlim_cur = 10 * 1024 * 1024;
> +  TEST_COMPARE (setrlimit (RLIMIT_AS, &rl), 0);
> +
> +  buf = aprintf ("%20000000d", 1);
> +  TEST_VERIFY (buf == NULL);
> +  TEST_COMPARE (errno, ENOMEM);
> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/libio/vaprintf.c b/libio/vaprintf.c
> new file mode 100644
> index 000000000000..157f783d30b1
> --- /dev/null
> +++ b/libio/vaprintf.c
> @@ -0,0 +1,39 @@
> +/* Copyright (C) 2026 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.
> +
> +   As a special exception, if you link the code in this file with
> +   files compiled with a GNU compiler to produce an executable,
> +   that does not cause the resulting executable to be covered by
> +   the GNU Lesser General Public License.  This exception does not
> +   however invalidate any other reasons why the executable file
> +   might be covered by the GNU Lesser General Public License.
> +   This exception applies to code released by its copyright holders
> +   in files containing the exception.  */
> +
> +#include <libioP.h>
> +#include <stdarg.h>
> +#include <stddef.h>
> +#include <stdio.h>
> +
> +char *
> +__vaprintf (const char *fmt, va_list ap)
> +{
> +  char *p;
> +
> +  return __vasprintf_internal (&p, fmt, ap, 0) < 0 ? NULL : p;
> +}
> +ldbl_weak_alias (__vaprintf, vaprintf)
> diff --git a/manual/stdio.texi b/manual/stdio.texi
> index c01feaed7d59..e7deca78fd53 100644
> --- a/manual/stdio.texi
> +++ b/manual/stdio.texi
> @@ -2578,6 +2578,32 @@ other systems offer this function as an async-signal-safe alternative to
>  The functions in this section do formatted output and place the results
>  in dynamically allocated memory.
>  
> +@deftypefun {char *} aprintf (const char *@var{template}, @dots{})
> +@standards{GNU, stdio.h}
> +@safety{@prelim{}@mtsafe{@mtslocale{}}@asunsafe{@ascuheap{}}@acunsafe{@acsmem{}}}
> +This function is similar to @code{sprintf},
> +except that it dynamically allocates a string
> +(as with @code{malloc}; @pxref{Unconstrained Allocation})
> +to hold the output,
> +instead of putting the output in a buffer you allocate in advance.
> +A successful call to @code{aprintf} returns
> +a pointer to the newly allocated string.
> +
> +Here is how to use @code{aprintf}
> +to get the same result as the @code{snprintf} example,
> +but more easily:
> +
> +@smallexample
> +/* @r{Construct a message describing the value of a variable}
> +   @r{whose name is @var{name} and whose value is @var{value}.} */
> +char *
> +make_message (char *name, char *value)
> +@{
> +  return aprintf ("value of %s is %s", name, value);
> +@}
> +@end smallexample
> +@end deftypefun
> +
>  @deftypefun int asprintf (char **@var{ptr}, const char *@var{template}, @dots{})
>  @standards{GNU, stdio.h}
>  @safety{@prelim{}@mtsafe{@mtslocale{}}@asunsafe{@ascuheap{}}@acunsafe{@acsmem{}}}
> diff --git a/stdio-common/Makefile b/stdio-common/Makefile
> index 0c0085e60763..2d829accbc16 100644
> --- a/stdio-common/Makefile
> +++ b/stdio-common/Makefile
> @@ -89,6 +89,7 @@ routines := \
>    _fitoa_word \
>    _itoa \
>    _itowa \
> +  aprintf \
>    asprintf \
>    ctermid \
>    cuserid \
> @@ -177,6 +178,7 @@ routines := \
>  
>  # Exclude fortified routines from being built with _FORTIFY_SOURCE
>  routines_no_fortify += \
> +  aprintf \
>    asprintf \
>    dprintf \
>    fprintf \
> diff --git a/stdio-common/Versions b/stdio-common/Versions
> index 8e1cbf85590c..93d635ff865c 100644
> --- a/stdio-common/Versions
> +++ b/stdio-common/Versions
> @@ -71,6 +71,9 @@ libc {
>      __isoc23_sscanf;
>      __isoc23_vsscanf;
>    }
> +  GLIBC_2.44 {
> +    aprintf;
> +  }
>    GLIBC_PRIVATE {
>      # global variables
>      _itoa_lower_digits;
> diff --git a/stdio-common/aprintf.c b/stdio-common/aprintf.c
> new file mode 100644
> index 000000000000..bee4966707ae
> --- /dev/null
> +++ b/stdio-common/aprintf.c
> @@ -0,0 +1,40 @@
> +/* Copyright (C) 2026 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */

Should we add a LGPL linking-exception clause, as other printf symbols?

> +
> +#include <stdarg.h>
> +#include <libioP.h>
> +
> +/* Write formatted output from FORMAT to a string which is
> +   allocated with malloc.  */
> +/* VARARGS1 */
> +char *
> +___aprintf (const char *fmt, ...)
> +{
> +  char *p;
> +  va_list ap;
> +
> +  va_start (ap, fmt);
> +  if (__vasprintf_internal (&p, fmt, ap, 0) < 0)
> +    p = NULL;
> +  va_end (ap);
> +
> +  return p;
> +}
> +ldbl_hidden_def (___aprintf, __aprintf)
> +
> +ldbl_strong_alias (___aprintf, __aprintf)
> +ldbl_weak_alias (___aprintf, aprintf)
> diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
> index 10ae73dba1b5..e0989a5147fc 100644
> --- a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
> +++ b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
> @@ -5,6 +5,7 @@ ldbl-extra-routines += fwscanf \
>  		       swscanf \
>  		       swprintf \
>  		       wscanf \
> +		       vaprintf \
>  		       vasprintf \
>  		       vdprintf \
>  		       vscanf \
> @@ -40,6 +41,7 @@ endif
>  
>  ifeq ($(subdir),stdio-common)
>  ldbl-extra-routines += printf_size \
> +		       aprintf \
>  		       asprintf \
>  		       dprintf \
>  		       fprintf \
> @@ -250,12 +252,14 @@ $(objpfx)test-printf-size-ibm128.out: \
>  endif
>  
>  ifeq ($(subdir),debug)
> -ldbl-extra-routines += asprintf_chk \
> +ldbl-extra-routines += aprintf_chk \
> +		       asprintf_chk \
>  		       dprintf_chk \
>  		       fprintf_chk \
>  		       printf_chk \
>  		       snprintf_chk \
>  		       sprintf_chk \
> +		       vaprintf_chk \
>  		       vasprintf_chk \
>  		       vdprintf_chk \
>  		       vfprintf_chk \
> @@ -480,6 +484,7 @@ endif
>  routines += $(foreach r,$(ldbl-extra-routines),ieee128-$(r))
>  
>  routines_no_fortify += \
> +  ieee128-aprintf \
>    ieee128-asprintf \
>    ieee128-dprintf \
>    ieee128-fprintf \
> @@ -490,6 +495,7 @@ routines_no_fortify += \
>    ieee128-sprintf \
>    ieee128-swprintf \
>    ieee128-syslog \
> +  ieee128-vaprintf \
>    ieee128-vasprintf \
>    ieee128-vdprintf \
>    ieee128-vfprintf \
> diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Versions b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
> index 00c0b445cda1..ae341658d11c 100644
> --- a/sysdeps/ieee754/ldbl-128ibm-compat/Versions
> +++ b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
> @@ -301,4 +301,10 @@ libc {
>      __isoc23_vswscanfieee128;
>      __isoc23_vwscanfieee128;
>    }
> +  GLIBC_2.44 {
> +    __aprintfieee128;
> +    __vaprintfieee128;
> +    __aprintf_chkieee128;
> +    __vaprintf_chkieee128;
> +  }
>  }
> diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-aprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-aprintf.c
> new file mode 100644
> index 000000000000..041ebc01b3f6
> --- /dev/null
> +++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-aprintf.c
> @@ -0,0 +1,36 @@
> +/* Wrapper for aprintf.  IEEE128 version.
> +   Copyright (C) 2026 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <stdarg.h>
> +#include <libio/libioP.h>
> +
> +extern char *
> +___ieee128___aprintf (const char *fmt, ...)
> +{
> +  va_list ap;
> +  char *p;
> +
> +  va_start (ap, fmt);
> +  if (__vasprintf_internal (&p, fmt, ap, PRINTF_LDBL_USES_FLOAT128) < 0)
> +    p = NULL;
> +  va_end (ap);
> +
> +  return p;
> +}
> +hidden_def (___ieee128___aprintf)
> +strong_alias (___ieee128___aprintf, __aprintfieee128)
> diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-aprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-aprintf_chk.c
> new file mode 100644
> index 000000000000..0e1e395db76e
> --- /dev/null
> +++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-aprintf_chk.c
> @@ -0,0 +1,40 @@
> +/* Wrapper for __aprintf_chk.  IEEE128 version.
> +   Copyright (C) 2026 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <stdarg.h>
> +#include <libio/libioP.h>
> +
> +extern char *
> +___ieee128___aprintf_chk (int flag, const char *fmt, ...)
> +{
> +  va_list ap;
> +  char *p;
> +
> +  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
> +
> +  va_start (ap, fmt);
> +  if (__vasprintf_internal (&p, fmt, ap, mode) < 0)
> +    p = NULL;
> +  va_end (ap);
> +
> +  return p;
> +}
> +hidden_def (___ieee128___aprintf_chk)
> +strong_alias (___ieee128___aprintf_chk, __aprintf_chkieee128)
> diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vaprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vaprintf.c
> new file mode 100644
> index 000000000000..6157f3060764
> --- /dev/null
> +++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vaprintf.c
> @@ -0,0 +1,29 @@
> +/* Wrapper for vaprintf.  IEEE128 version.
> +   Copyright (C) 2026 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <libio/libioP.h>
> +
> +extern char *
> +___ieee128_vaprintf (const char *fmt, va_list ap)
> +{
> +  char *p;
> +  if (__vasprintf_internal (&p, fmt, ap, PRINTF_LDBL_USES_FLOAT128) < 0)
> +    p = NULL;
> +  return p;
> +}
> +strong_alias (___ieee128_vaprintf, __vaprintfieee128)
> diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vaprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vaprintf_chk.c
> new file mode 100644
> index 000000000000..4fd0ca8caa0a
> --- /dev/null
> +++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vaprintf_chk.c
> @@ -0,0 +1,31 @@
> +/* Wrapper for __vaprintf_chk.  IEEE128 version.
> +   Copyright (C) 2026 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <libio/libioP.h>
> +
> +extern char *
> +___ieee128___vaprintf_chk (int flag, const char *fmt, va_list ap)
> +{
> +  char *p;
> +  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
> +
> +  return __vasprintf_internal (&p, fmt, ap, mode) < 0 ? NULL : p;
> +}
> +strong_alias (___ieee128___vaprintf_chk, __vaprintf_chkieee128)
> diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.c
> index 597e782e1d6c..92cdafd31978 100644
> --- a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.c
> +++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.c
> @@ -29,12 +29,24 @@
>  static void
>  do_test_call_varg (FILE *stream, const char *format, ...)
>  {
> -  char *buffer = NULL;
> +  char *buffer;
>    char string[128];
>    int res;
>    va_list args;
>  
> +  printf ("%20s", "__vaprintf_chk: ");
> +  va_start (args, format);
> +  buffer = __vaprintf_chk (1, format, args);
> +  va_end (args);
> +  if (buffer == NULL)
> +    printf ("Error using vaprintf\n");
> +  else
> +    printf ("%s", buffer);
> +  free (buffer);
> +  printf ("\n");
> +
>    printf ("%20s", "__vasprintf_chk: ");
> +  buffer = NULL;
>    va_start (args, format);
>    res = __vasprintf_chk (&buffer, 1, format, args);
>    va_end (args);
> @@ -86,11 +98,21 @@ static void
>  do_test_call_rarg (FILE *stream, const char *format, long double ld,
>  		   double d)
>  {
> -  char *buffer = NULL;
> +  char *buffer;
>    char string[128];
>    int res;
>  
> +  printf ("%20s", "__aprintf_chk: ");
> +  buffer = __aprintf_chk (1, format, ld, d);
> +  if (buffer == NULL)
> +    printf ("Error using aprintf\n");
> +  else
> +    printf ("%s", buffer);
> +  free (buffer);
> +  printf ("\n");
> +
>    printf ("%20s", "__asprintf_chk: ");
> +  buffer = NULL;
>    res = __asprintf_chk (&buffer, 1, format, ld, d);
>    if (res == -1)
>      printf ("Error using vasprintf\n");
> @@ -153,30 +175,35 @@ do_test (void)
>  
>    /* Compare against the expected output.  */
>    const char *expected =
> +    "     __aprintf_chk: -1.0000000000, -1.0000000000\n"
>      "    __asprintf_chk: -1.0000000000, -1.0000000000\n"
>      "     __dprintf_chk: -1.0000000000, -1.0000000000\n"
>      "     __fprintf_chk: -1.0000000000, -1.0000000000\n"
>      "      __printf_chk: -1.0000000000, -1.0000000000\n"
>      "    __snprintf_chk: -1.0000000000, -1.0000000000\n"
>      "     __sprintf_chk: -1.0000000000, -1.0000000000\n"
> +    "    __vaprintf_chk: -1.0000000000, -1.0000000000\n"
>      "   __vasprintf_chk: -1.0000000000, -1.0000000000\n"
>      "    __vdprintf_chk: -1.0000000000, -1.0000000000\n"
>      "    __vfprintf_chk: -1.0000000000, -1.0000000000\n"
>      "     __vprintf_chk: -1.0000000000, -1.0000000000\n"
>      "   __vsnprintf_chk: -1.0000000000, -1.0000000000\n"
>      "    __vsprintf_chk: -1.0000000000, -1.0000000000\n"
> +    "     __aprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "    __asprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "     __dprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "     __fprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "      __printf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "    __snprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "     __sprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
> +    "    __vaprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "   __vasprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "    __vdprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "    __vfprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "     __vprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "   __vsnprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "    __vsprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
> +    "    __vaprintf_chk: 3.000000, 2.000000, 1.000000\n"
>      "   __vasprintf_chk: 3.000000, 2.000000, 1.000000\n"
>      "    __vdprintf_chk: 3.000000, 2.000000, 1.000000\n"
>      "    __vfprintf_chk: 3.000000, 2.000000, 1.000000\n"
> diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c
> index e762e962e189..7629ee7b6bfd 100644
> --- a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c
> +++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c
> @@ -27,12 +27,24 @@
>  static void
>  do_test_call_varg (FILE *stream, const char *format, ...)
>  {
> -  char *buffer = NULL;
> +  char *buffer;
>    char string[128];
>    va_list args;
>    int ret;
>  
> +  printf ("%15s", "vaprintf: ");
> +  va_start (args, format);
> +  buffer = vaprintf (format, args);
> +  va_end (args);
> +  if (buffer == NULL)
> +    printf ("Error using vaprintf\n");
> +  else
> +    printf ("%s", buffer);
> +  free (buffer);
> +  printf ("\n");
> +
>    printf ("%15s", "vasprintf: ");
> +  buffer = NULL;
>    va_start (args, format);
>    ret = vasprintf (&buffer, format, args);
>    va_end (args);
> @@ -81,11 +93,21 @@ do_test_call_varg (FILE *stream, const char *format, ...)
>  static void
>  do_test_call_rarg (FILE *stream, const char *format, long double ld, double d)
>  {
> -  char *buffer = NULL;
> +  char *buffer;
>    char string[128];
>    int ret;
>  
> +  printf ("%15s", "aprintf: ");
> +  buffer = aprintf (format, ld, d);
> +  if (buffer == NULL)
> +    printf ("Error using aprintf\n");
> +  else
> +    printf ("%s", buffer);
> +  free (buffer);
> +  printf ("\n");
> +
>    printf ("%15s", "asprintf: ");
> +  buffer = NULL;
>    ret = asprintf (&buffer, format, ld, d);
>    if (ret == -1 || buffer == NULL)
>      printf ("Error using asprintf\n");
> @@ -146,30 +168,35 @@ do_test (void)
>  
>    /* Compare against the expected output.  */
>    const char *expected =
> +    "      aprintf: -1.0000000000, -1.0000000000\n"
>      "     asprintf: -1.0000000000, -1.0000000000\n"
>      "      dprintf: -1.0000000000, -1.0000000000\n"
>      "      fprintf: -1.0000000000, -1.0000000000\n"
>      "       printf: -1.0000000000, -1.0000000000\n"
>      "     snprintf: -1.0000000000, -1.0000000000\n"
>      "      sprintf: -1.0000000000, -1.0000000000\n"
> +    "     vaprintf: -1.0000000000, -1.0000000000\n"
>      "    vasprintf: -1.0000000000, -1.0000000000\n"
>      "     vdprintf: -1.0000000000, -1.0000000000\n"
>      "     vfprintf: -1.0000000000, -1.0000000000\n"
>      "      vprintf: -1.0000000000, -1.0000000000\n"
>      "    vsnprintf: -1.0000000000, -1.0000000000\n"
>      "     vsprintf: -1.0000000000, -1.0000000000\n"
> +    "      aprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "     asprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "      dprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "      fprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "       printf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "     snprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "      sprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
> +    "     vaprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "    vasprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "     vdprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "     vfprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "      vprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "    vsnprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
>      "     vsprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
> +    "     vaprintf: 3.000000, 2.000000, 1.000000\n"
>      "    vasprintf: 3.000000, 2.000000, 1.000000\n"
>      "     vdprintf: 3.000000, 2.000000, 1.000000\n"
>      "     vfprintf: 3.000000, 2.000000, 1.000000\n"
> diff --git a/sysdeps/ieee754/ldbl-opt/Makefile b/sysdeps/ieee754/ldbl-opt/Makefile
> index ef7da1f83038..3effc4ef3921 100644
> --- a/sysdeps/ieee754/ldbl-opt/Makefile
> +++ b/sysdeps/ieee754/ldbl-opt/Makefile
> @@ -15,6 +15,8 @@ libnldbl-calls = \
>    acos \
>    acosh \
>    acospi \
> +  aprintf \
> +  aprintf_chk \
>    asin \
>    asinh \
>    asinpi \
> @@ -223,6 +225,8 @@ libnldbl-calls = \
>    trunc \
>    ufromfp \
>    ufromfpx \
> +  vaprintf \
> +  vaprintf_chk \
>    vasprintf \
>    vasprintf_chk \
>    vdprintf \
> @@ -556,6 +560,7 @@ CFLAGS-tst-nldbl-wscanf-binary-gnu89.c += -mlong-double-64 -std=gnu89 \
>  endif
>  
>  routines_no_fortify += \
> +  nldbl-aprintf \
>    nldbl-asprintf \
>    nldbl-dprintf \
>    nldbl-fprintf \
> @@ -567,6 +572,7 @@ routines_no_fortify += \
>    nldbl-sprintf \
>    nldbl-swprintf \
>    nldbl-syslog \
> +  nldbl-vaprintf \
>    nldbl-vasprintf \
>    nldbl-vdprintf \
>    nldbl-vfprintf \
> diff --git a/sysdeps/ieee754/ldbl-opt/Versions b/sysdeps/ieee754/ldbl-opt/Versions
> index 5345f1c68379..f7dec42d189e 100644
> --- a/sysdeps/ieee754/ldbl-opt/Versions
> +++ b/sysdeps/ieee754/ldbl-opt/Versions
> @@ -98,6 +98,16 @@ libc {
>      __nldbl___isoc23_vfwscanf;
>      __nldbl___isoc23_vswscanf;
>    }
> +  GLIBC_2.44 {
> +    __aprintf;
> +    aprintf;
> +    vaprintf;
> +    __nldbl___aprintf;
> +    __nldbl_aprintf;
> +    __nldbl_vaprintf;
> +    __nldbl___aprintf_chk;
> +    __nldbl___vaprintf_chk;
> +  }
>  }
>  libm {
>    NLDBL_VERSION {
> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-aprintf.c b/sysdeps/ieee754/ldbl-opt/nldbl-aprintf.c
> new file mode 100644
> index 000000000000..fe250c039904
> --- /dev/null
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-aprintf.c
> @@ -0,0 +1,17 @@
> +#include "nldbl-compat.h"
> +
> +attribute_hidden
> +char *
> +__aprintf (const char *fmt, ...)
> +{
> +  va_list ap;
> +  char *p;
> +
> +  va_start (ap, fmt);
> +  p = __nldbl_vaprintf (fmt, ap);
> +  va_end (ap);
> +
> +  return p;
> +}
> +extern __typeof (__aprintf) aprintf attribute_hidden;
> +weak_alias (__aprintf, aprintf)
> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-aprintf_chk.c b/sysdeps/ieee754/ldbl-opt/nldbl-aprintf_chk.c
> new file mode 100644
> index 000000000000..77b1d221bda1
> --- /dev/null
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-aprintf_chk.c
> @@ -0,0 +1,15 @@
> +#include "nldbl-compat.h"
> +
> +attribute_hidden
> +char *
> +__aprintf_chk (int flag, const char *fmt, ...)
> +{
> +  va_list ap;
> +  char *p;
> +
> +  va_start (ap, fmt);
> +  p = __nldbl___vaprintf_chk (flag, fmt, ap);
> +  va_end (ap);
> +
> +  return p;
> +}
> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> index e239cd5bc5c4..f5c69f7ff4d5 100644
> --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> @@ -55,6 +55,22 @@ libc_hidden_proto (__nldbl___isoc23_vfwscanf)
>     we don't need to split this into one file per function for the
>     sake of statically linked programs.  */
>  
> +int
> +attribute_compat_text_section
> +__nldbl___aprintf (const char *fmt, ...)
> +{
> +  va_list ap;
> +  char *p;
> +
> +  va_start (ap, fmt);
> +  if (__vasprintf_internal (&p, fmt, ap, PRINTF_LDBL_IS_DBL) < 0)
> +    p = NULL;
> +  va_end (ap);
> +
> +  return p;
> +}
> +weak_alias (__nldbl___aprintf, __nldbl_aprintf)
> +
>  int
>  attribute_compat_text_section
>  __nldbl___asprintf (char **string_ptr, const char *fmt, ...)
> @@ -208,6 +224,14 @@ __nldbl_swprintf (wchar_t *s, size_t n, const wchar_t *fmt, ...)
>    return ret;
>  }
>  
> +char *
> +attribute_compat_text_section weak_function
> +__nldbl_vaprintf (const char *fmt, va_list ap)
> +{
> +  char *p;
> +  return __vasprintf_internal (&p, fmt, ap, PRINTF_LDBL_IS_DBL) < 0 ? NULL : p;
> +}
> +
>  int
>  attribute_compat_text_section weak_function
>  __nldbl_vasprintf (char **result_ptr, const char *fmt, va_list ap)
> @@ -651,6 +675,36 @@ __nldbl___wprintf_chk (int flag, const wchar_t *fmt, ...)
>    return ret;
>  }
>  
> +char *
> +attribute_compat_text_section
> +__nldbl___vaprintf_chk (int flag, const char *fmt, va_list ap)
> +{
> +  char *p;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
> +
> +  return __vasprintf_internal (&p, fmt, ap, mode) < 0 ? NULL : p;
> +}
> +
> +char *
> +attribute_compat_text_section
> +__nldbl___aprintf_chk (int flag, const char *fmt, ...)
> +{
> +  va_list ap;
> +  char *p;
> +  unsigned int mode = PRINTF_LDBL_IS_DBL;
> +  if (flag > 0)
> +    mode |= PRINTF_FORTIFY;
> +
> +  va_start (ap, fmt);
> +  if (__vasprintf_internal (&p, fmt, ap, mode) < 0)
> +    p = NULL;
> +  va_end (ap);
> +
> +  return p;
> +}
> +
>  int
>  attribute_compat_text_section
>  __nldbl___vasprintf_chk (char **ptr, int flag, const char *fmt, va_list ap)
> @@ -1342,3 +1396,8 @@ compat_symbol (libc, __nldbl___fprintf_chk, __fprintf_chk, GLIBC_2_3_4);
>  compat_symbol (libc, __nldbl___vprintf_chk, __vprintf_chk, GLIBC_2_3_4);
>  compat_symbol (libc, __nldbl___vfprintf_chk, __vfprintf_chk, GLIBC_2_3_4);
>  #endif
> +#if LONG_DOUBLE_COMPAT(libc, GLIBC_2_4_4)
> +compat_symbol (libc, __nldbl_aprintf, aprintf, GLIBC_2_4_4);
> +compat_symbol (libc, __nldbl_vaprintf, vaprintf, GLIBC_2_4_4);
> +compat_symbol (libc, __nldbl___aprintf, __aprintf, GLIBC_2_4_4);
> +#endif

I think you meant *2_44* here. But this whole block should not be required,
aprintf is a new symbol, so it has no historic ldbl == double ABI to be 
compatible with. 

New symbols do not get a compat_symbol at an older version (and compat_symbol 
at the current dev version is illegal anyway). Check the __isoc23_* additions, 
which use libc_hidden_def + the normal versioned export.

> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
> index f22177892846..9da1c2d241b4 100644
> --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
> @@ -46,6 +46,7 @@ NLDBL_DECL (_IO_vfscanf);
>  NLDBL_DECL (vfscanf);
>  NLDBL_DECL (vfwscanf);
>  NLDBL_DECL (obstack_vprintf);
> +NLDBL_DECL (vaprintf);
>  NLDBL_DECL (vasprintf);
>  NLDBL_DECL (dprintf);
>  NLDBL_DECL (vdprintf);
> @@ -57,6 +58,8 @@ NLDBL_DECL (vsprintf);
>  NLDBL_DECL (vsscanf);
>  NLDBL_DECL (vswprintf);
>  NLDBL_DECL (vswscanf);
> +NLDBL_DECL (__aprintf);
> +NLDBL_DECL (aprintf);
>  NLDBL_DECL (__asprintf);
>  NLDBL_DECL (asprintf);
>  NLDBL_DECL (__printf_fp);
> @@ -126,6 +129,8 @@ extern int __nldbl___vsnprintf_chk (char *__restrict, size_t, int, size_t,
>  extern int __nldbl___vswprintf_chk (wchar_t *__restrict, size_t, int, size_t,
>  				    const wchar_t *__restrict, __gnuc_va_list)
>    __THROW;
> +extern char *__nldbl___vaprintf_chk (int, const char *, __gnuc_va_list)
> +  __THROW __attribute_malloc__;
>  extern int __nldbl___vasprintf_chk (char **, int, const char *, __gnuc_va_list)
>    __THROW;
>  extern int __nldbl___vdprintf_chk (int, int, const char *, __gnuc_va_list);
> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-vaprintf.c b/sysdeps/ieee754/ldbl-opt/nldbl-vaprintf.c
> new file mode 100644
> index 000000000000..6ba7789c0063
> --- /dev/null
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-vaprintf.c
> @@ -0,0 +1,9 @@
> +#include "nldbl-compat.h"
> +
> +attribute_hidden
> +weak_function
> +char *
> +vaprintf (const char *fmt, va_list ap)
> +{
> +  return __nldbl_vaprintf (fmt, ap);
> +}
> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-vaprintf_chk.c b/sysdeps/ieee754/ldbl-opt/nldbl-vaprintf_chk.c
> new file mode 100644
> index 000000000000..72e4fca7964d
> --- /dev/null
> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-vaprintf_chk.c
> @@ -0,0 +1,8 @@
> +#include "nldbl-compat.h"
> +
> +attribute_hidden
> +char *
> +__vaprintf_chk (int flag, const char *fmt, va_list ap)
> +{
> +  return __nldbl___vaprintf_chk (flag, fmt, ap);
> +}
> diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
> index 0166703bdb38..19849ec9e388 100644
> --- a/sysdeps/mach/hurd/i386/libc.abilist
> +++ b/sysdeps/mach/hurd/i386/libc.abilist
> @@ -2798,7 +2798,10 @@ GLIBC_2.43 tss_delete F
>  GLIBC_2.43 tss_get F
>  GLIBC_2.43 tss_set F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
>  GLIBC_2.44 __mq_open_2 F
> +GLIBC_2.44 __vaprintf_chk F
>  GLIBC_2.44 aio_cancel F
>  GLIBC_2.44 aio_cancel64 F
>  GLIBC_2.44 aio_error F
> @@ -2814,6 +2817,7 @@ GLIBC_2.44 aio_suspend F
>  GLIBC_2.44 aio_suspend64 F
>  GLIBC_2.44 aio_write F
>  GLIBC_2.44 aio_write64 F
> +GLIBC_2.44 aprintf F
>  GLIBC_2.44 gai_cancel F
>  GLIBC_2.44 gai_error F
>  GLIBC_2.44 gai_suspend F
> @@ -2835,6 +2839,7 @@ GLIBC_2.44 timer_delete F
>  GLIBC_2.44 timer_getoverrun F
>  GLIBC_2.44 timer_gettime F
>  GLIBC_2.44 timer_settime F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/mach/hurd/x86_64/libc.abilist b/sysdeps/mach/hurd/x86_64/libc.abilist
> index 0262a079aa83..75f4ee9ba7f1 100644
> --- a/sysdeps/mach/hurd/x86_64/libc.abilist
> +++ b/sysdeps/mach/hurd/x86_64/libc.abilist
> @@ -2474,7 +2474,10 @@ GLIBC_2.43 tss_delete F
>  GLIBC_2.43 tss_get F
>  GLIBC_2.43 tss_set F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
>  GLIBC_2.44 __mq_open_2 F
> +GLIBC_2.44 __vaprintf_chk F
>  GLIBC_2.44 aio_cancel F
>  GLIBC_2.44 aio_cancel64 F
>  GLIBC_2.44 aio_error F
> @@ -2490,6 +2493,7 @@ GLIBC_2.44 aio_suspend F
>  GLIBC_2.44 aio_suspend64 F
>  GLIBC_2.44 aio_write F
>  GLIBC_2.44 aio_write64 F
> +GLIBC_2.44 aprintf F
>  GLIBC_2.44 gai_cancel F
>  GLIBC_2.44 gai_error F
>  GLIBC_2.44 gai_suspend F
> @@ -2511,6 +2515,7 @@ GLIBC_2.44 timer_delete F
>  GLIBC_2.44 timer_getoverrun F
>  GLIBC_2.44 timer_gettime F
>  GLIBC_2.44 timer_settime F
> +GLIBC_2.44 vaprintf F
>  HURD_CTHREADS_0.3 __mutex_init F
>  HURD_CTHREADS_0.3 __mutex_lock F
>  HURD_CTHREADS_0.3 __mutex_trylock F
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> index 3156688addba..1dfc4868fcf3 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -2775,3 +2775,8 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index 8af5b0b58188..bd8456cb535e 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -3122,6 +3122,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
> index 35fcef2cc4c1..cc608a70e2dc 100644
> --- a/sysdeps/unix/sysv/linux/arc/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
> @@ -2536,3 +2536,8 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
> diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> index a6c6b951bfa7..8bb4c76c0c82 100644
> --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> @@ -2828,6 +2828,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> index e76015fe666a..84ce598df7ec 100644
> --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> @@ -2825,6 +2825,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
> index 1fb7cdcad5de..a431ad7d2a92 100644
> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
> @@ -2812,3 +2812,8 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> index 0710ccecf9d6..cec2ae38bf03 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> @@ -2849,6 +2849,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index 3afe3a88eb42..443b553c9f36 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -3032,6 +3032,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> index c2b3a66d3a1d..69119490a49d 100644
> --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> @@ -2296,3 +2296,8 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index d6855131e8b8..b57426dea5c9 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -2808,6 +2808,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index 4e3fe9c42f28..d0630627ce09 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -2975,6 +2975,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> index 29f0c5f954b5..cf9b9feee6ca 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> @@ -2861,3 +2861,8 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> index 2ef62838f75c..5699f65a8c3f 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> @@ -2858,3 +2858,8 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index 031e8961acce..3dd7985954b1 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -2938,6 +2938,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index 8dc99d81b4bb..4acff6b710dc 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -2936,6 +2936,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index 054c5b6391b9..c0ae4197c6be 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -2944,6 +2944,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index 13f0148bc000..63c62110045c 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -2846,6 +2846,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> index e7ffe07dd8d5..a3b89d620f09 100644
> --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> @@ -2286,3 +2286,8 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index dea4b20f05c1..fa44aa466688 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -3165,6 +3165,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> index b45e12746368..5657ea762da0 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> @@ -3210,6 +3210,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> index 942cf6a02763..233c5f0bea73 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> @@ -2919,6 +2919,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> index 65d78e50760b..c48eb3ed85d3 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> @@ -2995,3 +2995,8 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> index dcab30d72eec..ae677eb8da7f 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> @@ -2539,3 +2539,8 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> index 796ef35e26e5..734e540902d4 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> @@ -2739,3 +2739,8 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
> diff --git a/sysdeps/unix/sysv/linux/s390/libc.abilist b/sysdeps/unix/sysv/linux/s390/libc.abilist
> index 8f2350ee0b64..f6f9c998a111 100644
> --- a/sysdeps/unix/sysv/linux/s390/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/libc.abilist
> @@ -2956,6 +2956,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> index 7aa98c5aede5..100b5de75e94 100644
> --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> @@ -2855,6 +2855,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> index 6bd4f8f63a1a..f16c9e83fd79 100644
> --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> @@ -2852,6 +2852,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index b52cab2a3515..fa79c7b9918b 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -3186,6 +3186,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index ff99cd4f219a..becd745b1ab2 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -2822,6 +2822,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index 306cd627fd82..a3fefbc56330 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -2771,6 +2771,11 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
>  GLIBC_2.5 inet6_opt_find F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index 8b9c448742ed..659654d97665 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2790,3 +2790,8 @@ GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
>  GLIBC_2.43 umaxabs F
> +GLIBC_2.44 __aprintf F
> +GLIBC_2.44 __aprintf_chk F
> +GLIBC_2.44 __vaprintf_chk F
> +GLIBC_2.44 aprintf F
> +GLIBC_2.44 vaprintf F
  
Alejandro Colomar June 3, 2026, 8:37 p.m. UTC | #2
Hi Adhemerval,

On 2026-06-03T13:45:44-0300, Adhemerval Zanella Netto wrote:
> > -  We don't need to fail with EOVERFLOW.  This initial implementation
> >    still fails with EOVERFLOW, because it would require a lot of work
> >    implementing it in a way that doesn't have such a failure point, but
> >    the API has no inherent reasons to fail with EOVERFLOW.
> 
> I think it should be disable by either extending __vasprintf_internal 
> (with a flag that returns -1/EOVERFLOW to use on the current interface or 
> functions where it should return int) or adding a new 
> __vasprintf_internal_ex that:
> 
> 1. Calls a new function simila to __printf_buffer_done (include/printf_buffer.h:195) 
>    that return ptrdiff_t (or int64_).
> 
> 2. Calls a new __printf_buffer_flush_asprintf (libio/vasprintf.c) that does 
>    not bails early with EOVERFLOW once current_pos >= INT_MAX.
> 
> But I do not think this is a hard requirement, nor a blocker for this patch 
> (I am not sure if Florian agrees, so I would check with him).

He recently said he wants to block it for this, IIUC.  I'll work on
a patch that applies on top of this one, after this one looks good to
you.

> But at the same 
> time I think it would be worth exploring whether we can avoid this limitation.
> 
> For the overflow case, I think we should properly document this in the manual
> entry.

[...]

> Let's try to disintagle this patch.

Thanks for the review!

>  I saw a build failure for alpha,
> powerpc (ppc64, ppc64le, ppc32), s390x, and sparcv9:
> 
> $ alpha-glibc-linux-gnu-gcc ../sysdeps/ieee754/ldbl-opt/nldbl-compat.c [...]
> ../sysdeps/ieee754/ldbl-opt/nldbl-compat.c:60:1: error: conflicting types for ‘__nldbl___aprintf’; have ‘int(const char *, ...)’
>    60 | __nldbl___aprintf (const char *fmt, ...)
>       | ^~~~~~~~~~~~~~~~~
[...]
> 
> The __nldbl___aprintf has the wrong return type — int instead of char *.

Ok.

	diff --git c/sysdeps/ieee754/ldbl-opt/nldbl-compat.c i/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
	index f5c69f7ff4d5..bfa0514b18f1 100644
	--- c/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
	+++ i/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
	@@ -55,7 +55,7 @@ libc_hidden_proto (__nldbl___isoc23_vfwscanf)
	    we don't need to split this into one file per function for the
	    sake of statically linked programs.  */
	 
	-int
	+char *
	 attribute_compat_text_section
	 __nldbl___aprintf (const char *fmt, ...)
	 {

[...]
> > diff --git a/debug/aprintf_chk.c b/debug/aprintf_chk.c
> > new file mode 100644
> > index 000000000000..30f7811f20da
> > --- /dev/null
> > +++ b/debug/aprintf_chk.c
> > @@ -0,0 +1,51 @@
[...]
> > +/* Write formatted output from FORMAT to a string allocated with malloc.  */
> > +char *
> > +___aprintf_chk (int flag, const char *fmt, ...)
> > +{
> > +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
> > +     can only come from read-only format strings.  */
> > +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
> > +  va_list ap;
> > +  char *p;
> > +
> > +  va_start (ap, fmt);
> > +  if (__vasprintf_internal (&p, fmt, ap, mode) < 0)
> > +    p = NULL;
> > +  va_end (ap);
> > +
> > +  return p;
> > +}
> 
> Adds some tests on debug/tst-fortify.c.

Ok.  Does this look good to you?

	diff --git c/debug/tst-fortify.c i/debug/tst-fortify.c
	index ee83fca22467..2bc3e5eb1c47 100644
	--- c/debug/tst-fortify.c
	+++ i/debug/tst-fortify.c
	@@ -1026,34 +1026,48 @@ do_test (void)
	   strcpy (buf2 + 2, "%n%s%n");
	   /* When the format string is writable and contains %n,
	      with -D_FORTIFY_SOURCE=2 it causes __chk_fail.  */
	   CHK_FAIL2_START
	   if (asprintf (&my_ptr, buf2, str4, &n1, str5, &n1) != 14)
	     FAIL ();
	   else
	     free (my_ptr);
	   CHK_FAIL2_END
	 
	+  CHK_FAIL2_START
	+  my_ptr = aprintf (buf2, str4, &n1, str5, &n1);
	+  if (my_ptr == NULL)
	+    FAIL ();
	+  else
	+    free (my_ptr);
	+  CHK_FAIL2_END
	+
	   struct obstack obs;
	   obstack_init (&obs);
	   CHK_FAIL2_START
	   if (obstack_printf (&obs, buf2, str4, &n1, str5, &n1) != 14)
	     FAIL ();
	   CHK_FAIL2_END
	   obstack_free (&obs, NULL);
	 
	   my_ptr = NULL;
	   if (asprintf (&my_ptr, "%s%n%s%n", str4, &n1, str5, &n1) != 14)
	     FAIL ();
	   else
	     free (my_ptr);
	 
	+  my_ptr = aprintf ("%s%n%s%n", str4, &n1, str5, &n1);
	+  if (my_ptr == NULL)
	+    FAIL ();
	+  else
	+    free (my_ptr);
	+
	   obstack_init (&obs);
	   if (obstack_printf (&obs, "%s%n%s%n", str4, &n1, str5, &n1) != 14)
	     FAIL ();
	   obstack_free (&obs, NULL);
	 #endif
	 
	   if (freopen (temp_filename, "r", stdin) == NULL)
	     {
	       puts ("could not open temporary file");
	       exit (1);

[...]
> > diff --git a/libio/stdio.h b/libio/stdio.h
> > index 3bf6a1f63203..81d7176c4535 100644
> > --- a/libio/stdio.h
> > +++ b/libio/stdio.h
> > @@ -412,6 +412,19 @@ extern int asprintf (char **__restrict __ptr,
> >       __THROWNL __attribute__ ((__format__ (__printf__, 2, 3))) __wur;
> >  #endif
> >  
> > +#ifdef __USE_GNU
> > +/* Write formatted output to a string dynamically allocated with `malloc'.  */
> > +extern char *vaprintf (const char *__restrict __fmt, __gnuc_va_list __ap)
> > +     __THROWNL __attribute__ ((__format__ (__printf__, 1, 0)))
> > +     __attribute_malloc__;
> 
> I think we should add __attr_dealloc_free, that one of the main advertises for
> this symbol. Smae for asprintf and the __chk variants.

Agree.  I probably looked at strdup(3) for imitating it, and it seems it
is lacking it.  Should we also add it to strdup(3) in string/string.h?

Anyway, here's a diff for aprintf(3):

	diff --git i/include/stdio.h w/include/stdio.h
	index cfdec3681d51..721101a3ad04 100644
	--- i/include/stdio.h
	+++ w/include/stdio.h
	@@ -78,9 +78,9 @@ stdio_hidden_ldbl_proto (__, vfprintf_chk)
	 extern char *__fgets_unlocked_chk (char *buf, size_t size, int n, FILE *fp);
	 extern char *__fgets_chk (char *buf, size_t size, int n, FILE *fp);
	 extern char *__aprintf_chk (int, const char *, ...)
	-     __THROW __attribute_malloc__;
	+     __THROW __attribute_malloc__ __attr_dealloc_free;
	 extern char *__vaprintf_chk (int, const char *, __gnuc_va_list)
	-     __THROW __attribute_malloc__;
	+     __THROW __attribute_malloc__ __attr_dealloc_free;
	 stdio_hidden_ldbl_proto (__, vaprintf_chk)
	 extern int __asprintf_chk (char **, int, const char *, ...) __THROW;
	 extern int __vasprintf_chk (char **, int, const char *, __gnuc_va_list) __THROW;
	diff --git i/libio/bits/stdio2-decl.h w/libio/bits/stdio2-decl.h
	index cf52c46c31f6..d8d99fa1a9f3 100644
	--- i/libio/bits/stdio2-decl.h
	+++ w/libio/bits/stdio2-decl.h
	@@ -69,11 +69,11 @@ extern int __vdprintf_chk (int __fd, int __flag,
	 extern char *__aprintf_chk (int __flag,
				   const char *__restrict __fmt, ...)
	      __THROW __attribute__ ((__format__ (__printf__, 2, 3)))
	-     __attribute_malloc__;
	+     __attribute_malloc__ __attr_dealloc_free;
	 extern char *__vaprintf_chk (int __flag,
				    const char *__restrict __fmt, __gnuc_va_list __ap)
	      __THROW __attribute__ ((__format__ (__printf__, 2, 0)))
	-     __attribute_malloc__;
	+     __attribute_malloc__ __attr_dealloc_free;
	 extern int __asprintf_chk (char **__restrict __ptr, int __flag,
				   const char *__restrict __fmt, ...)
	      __THROW __attribute__ ((__format__ (__printf__, 3, 4))) __wur;
	diff --git i/libio/stdio.h w/libio/stdio.h
	index 81d7176c4535..8aa583eff8d5 100644
	--- i/libio/stdio.h
	+++ w/libio/stdio.h
	@@ -416,13 +416,13 @@ extern int asprintf (char **__restrict __ptr,
	 /* Write formatted output to a string dynamically allocated with `malloc'.  */
	 extern char *vaprintf (const char *__restrict __fmt, __gnuc_va_list __ap)
	      __THROWNL __attribute__ ((__format__ (__printf__, 1, 0)))
	-     __attribute_malloc__;
	+     __attribute_malloc__ __attr_dealloc_free;
	 extern char *__aprintf (const char *__restrict __fmt, ...)
	      __THROWNL __attribute__ ((__format__ (__printf__, 1, 2)))
	-     __attribute_malloc__;
	+     __attribute_malloc__ __attr_dealloc_free;
	 extern char *aprintf (const char *__restrict __fmt, ...)
	      __THROWNL __attribute__ ((__format__ (__printf__, 1, 2)))
	-     __attribute_malloc__;
	+     __attribute_malloc__ __attr_dealloc_free;
	 #endif
	 
	 #ifdef __USE_XOPEN2K8
	diff --git i/sysdeps/ieee754/ldbl-opt/nldbl-compat.h w/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
	index 9da1c2d241b4..3a3c7baf0e21 100644
	--- i/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
	+++ w/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
	@@ -130,7 +130,7 @@ extern int __nldbl___vswprintf_chk (wchar_t *__restrict, size_t, int, size_t,
					    const wchar_t *__restrict, __gnuc_va_list)
	   __THROW;
	 extern char *__nldbl___vaprintf_chk (int, const char *, __gnuc_va_list)
	-  __THROW __attribute_malloc__;
	+  __THROW __attribute_malloc__ __attr_dealloc_free;
	 extern int __nldbl___vasprintf_chk (char **, int, const char *, __gnuc_va_list)
	   __THROW;
	 extern int __nldbl___vdprintf_chk (int, int, const char *, __gnuc_va_list);

> 
> > +extern char *__aprintf (const char *__restrict __fmt, ...)
> > +     __THROWNL __attribute__ ((__format__ (__printf__, 1, 2)))
> > +     __attribute_malloc__;
> 
> I think there is no need to export the __aprintf for a new symbol, we did it
> on other symbols (like scanf) we can asm alias depending of the C standard
> being used. Since this is a new symbol, we can just use the aprintf.

Can we use aprintf(3) internally within glibc?  Users might have
defined aprintf() themselves, since it's non-standard.

> 
> > +extern char *aprintf (const char *__restrict __fmt, ...)
> > +     __THROWNL __attribute__ ((__format__ (__printf__, 1, 2)))
> > +     __attribute_malloc__;
> > +#endif
> > +
> >  #ifdef __USE_XOPEN2K8
> >  /* Write formatted output to a file descriptor.  */
> >  extern int vdprintf (int __fd, const char *__restrict __fmt,
> > diff --git a/libio/tst-aprintf.c b/libio/tst-aprintf.c
> > new file mode 100644
> > index 000000000000..0c7d7a8024c3
> > --- /dev/null
> > +++ b/libio/tst-aprintf.c
> > @@ -0,0 +1,73 @@
> > +/* Test aprintf.
> > +   Copyright (C) 2026 Free Software Foundation, Inc.
> > +   This file is part of the GNU C Library.
> > +
> > +   The GNU C Library is free software; you can redistribute it and/or
> > +   modify it under the terms of the GNU Lesser General Public
> > +   License as published by the Free Software Foundation; either
> > +   version 2.1 of the License, or (at your option) any later version.
> > +
> > +   The GNU C Library is distributed in the hope that it will be useful,
> > +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > +   Lesser General Public License for more details.
> > +
> > +   You should have received a copy of the GNU Lesser General Public
> > +   License along with the GNU C Library; if not, see
> > +   <https://www.gnu.org/licenses/>.  */
> > +
> > +#include <errno.h>
> > +#include <stdlib.h>
> > +#include <stdio.h>
> > +#include <support/check.h>
> > +#include <sys/resource.h>
> > +#include <libc-diag.h>
> > +
> > +static int
> > +do_test (void)
> > +{
> > +  char *buf;
> > +
> > +  /* Success */
> > +  buf = aprintf ("foo %d", 42);
> > +  TEST_COMPARE_STRING (buf, "foo 42");
> > +  free(buf);
> > +
> > +  {
> > +    /* -Wformat-overflow warns that the format would produce more than
> > +       INT_MAX bytes; however, this function does not share this
> > +       inherent limitation of other printf-like functions.  The current
> > +       implementation fails with EOVERFLOW, because it's a trivial
> > +       wrapper; however, in the future we should improve the function so
> > +       that this doesn't fail anymore with EOVERFLOW.  When that is
> > +       implemented, this test will stop failing.  */
> > +    DIAG_PUSH_NEEDS_COMMENT;
> > +    DIAG_IGNORE_NEEDS_COMMENT (8, "-Wformat-overflow=");
> > +    buf = aprintf ("%2000000000d %2000000000d", 1, 2);
> 
> Does it work on ILP32 ABIs (x32 and mips64-n32)?

It would probably ENOMEM instead of EOVERFLOW, I suspect.

I've done

	diff --git i/libio/tst-aprintf.c w/libio/tst-aprintf.c
	index 0c7d7a8024c3..1db26505ee03 100644
	--- i/libio/tst-aprintf.c
	+++ w/libio/tst-aprintf.c
	@@ -53,7 +53,8 @@ do_test (void)
		that happens, this test will fail.  Just remove it and enable the
		test under '#if 0'.  */
	     TEST_VERIFY (buf == NULL);
	-    TEST_VERIFY (errno == EOVERFLOW);
	+    if (errno != ENOMEM)
	+      TEST_VERIFY (errno == EOVERFLOW);
	 #endif
	   }

(as is done is the asprintf(3) tests.)

> > +    DIAG_POP_NEEDS_COMMENT;
> > +#if 0
> > +    if (buf == NULL)
> > +      TEST_VERIFY (errno == ENOMEM);
> > +#else
> 
> Plase remove the '#if 0' path here.

Hmmm, okay.

> > +    /* We should eventually not fail with EOVERFLOW from aprintf.  When
> > +       that happens, this test will fail.  Just remove it and enable the
> > +       test under '#if 0'.  */
> > +    TEST_VERIFY (buf == NULL);
> > +    TEST_VERIFY (errno == EOVERFLOW);
> > +#endif

[...]
> > diff --git a/stdio-common/aprintf.c b/stdio-common/aprintf.c
> > new file mode 100644
> > index 000000000000..bee4966707ae
> > --- /dev/null
> > +++ b/stdio-common/aprintf.c
> > @@ -0,0 +1,40 @@
> > +/* Copyright (C) 2026 Free Software Foundation, Inc.
> > +   This file is part of the GNU C Library.
> > +
> > +   The GNU C Library is free software; you can redistribute it and/or
> > +   modify it under the terms of the GNU Lesser General Public
> > +   License as published by the Free Software Foundation; either
> > +   version 2.1 of the License, or (at your option) any later version.
> > +
> > +   The GNU C Library is distributed in the hope that it will be useful,
> > +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > +   Lesser General Public License for more details.
> > +
> > +   You should have received a copy of the GNU Lesser General Public
> > +   License along with the GNU C Library; if not, see
> > +   <https://www.gnu.org/licenses/>.  */
> 
> Should we add a LGPL linking-exception clause, as other printf symbols?

I copied this from stdio-common/asprintf.c, IIRC.  I don't see the
exception in the other files:

	$ find stdio-common/ -type f \
		| grep printf \
		| xargs grep -i exception;
	$

The only file within stdio-common/ where I can see the exception is this
one:

	$ find stdio-common/ -type f \
		| grep -v Makefile \
		| xargs grep -i exception;
	stdio-common/isoc99_vsscanf.c:   As a special exception, if you link the code in this file with
	stdio-common/isoc99_vsscanf.c:   the GNU Lesser General Public License.  This exception does not
	stdio-common/isoc99_vsscanf.c:   This exception applies to code released by its copyright holders
	stdio-common/isoc99_vsscanf.c:   in files containing the exception.  */

[...]
> > diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> > index e239cd5bc5c4..f5c69f7ff4d5 100644
> > --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> > +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
[...]
> > @@ -1342,3 +1396,8 @@ compat_symbol (libc, __nldbl___fprintf_chk, __fprintf_chk, GLIBC_2_3_4);
> >  compat_symbol (libc, __nldbl___vprintf_chk, __vprintf_chk, GLIBC_2_3_4);
> >  compat_symbol (libc, __nldbl___vfprintf_chk, __vfprintf_chk, GLIBC_2_3_4);
> >  #endif
> > +#if LONG_DOUBLE_COMPAT(libc, GLIBC_2_4_4)
> > +compat_symbol (libc, __nldbl_aprintf, aprintf, GLIBC_2_4_4);
> > +compat_symbol (libc, __nldbl_vaprintf, vaprintf, GLIBC_2_4_4);
> > +compat_symbol (libc, __nldbl___aprintf, __aprintf, GLIBC_2_4_4);
> > +#endif
> 
> I think you meant *2_44* here. But this whole block should not be required,
> aprintf is a new symbol, so it has no historic ldbl == double ABI to be 
> compatible with. 

So, should I drop all changes to
sysdeps/ieee754/ldbl-opt/nldbl-compat.c?

> New symbols do not get a compat_symbol at an older version (and compat_symbol 
> at the current dev version is illegal anyway). Check the __isoc23_* additions, 
> which use libc_hidden_def + the normal versioned export.

Would you mind naming a few __isoc23_* names?  I don't know those
functions.


Have a lovely night!
Alex
  
Adhemerval Zanella Netto June 5, 2026, 6:42 p.m. UTC | #3
On 03/06/26 17:37, Alejandro Colomar wrote:
> Hi Adhemerval,
> 
> On 2026-06-03T13:45:44-0300, Adhemerval Zanella Netto wrote:
>>> -  We don't need to fail with EOVERFLOW.  This initial implementation
>>>    still fails with EOVERFLOW, because it would require a lot of work
>>>    implementing it in a way that doesn't have such a failure point, but
>>>    the API has no inherent reasons to fail with EOVERFLOW.
>>
>> I think it should be disable by either extending __vasprintf_internal 
>> (with a flag that returns -1/EOVERFLOW to use on the current interface or 
>> functions where it should return int) or adding a new 
>> __vasprintf_internal_ex that:
>>
>> 1. Calls a new function simila to __printf_buffer_done (include/printf_buffer.h:195) 
>>    that return ptrdiff_t (or int64_).
>>
>> 2. Calls a new __printf_buffer_flush_asprintf (libio/vasprintf.c) that does 
>>    not bails early with EOVERFLOW once current_pos >= INT_MAX.
>>
>> But I do not think this is a hard requirement, nor a blocker for this patch 
>> (I am not sure if Florian agrees, so I would check with him).
> 
> He recently said he wants to block it for this, IIUC.  I'll work on
> a patch that applies on top of this one, after this one looks good to
> you.

Indeed, it seems Florian does want to get this fixed [1].

[1] https://inbox.sourceware.org/libc-alpha/87h5nmo5cz.fsf@oldenburg.str.redhat.com/

> 
>> But at the same 
>> time I think it would be worth exploring whether we can avoid this limitation.
>>
>> For the overflow case, I think we should properly document this in the manual
>> entry.
> 
> [...]
> 
>> Let's try to disintagle this patch.
> 
> Thanks for the review!
> 
>>  I saw a build failure for alpha,
>> powerpc (ppc64, ppc64le, ppc32), s390x, and sparcv9:
>>
>> $ alpha-glibc-linux-gnu-gcc ../sysdeps/ieee754/ldbl-opt/nldbl-compat.c [...]
>> ../sysdeps/ieee754/ldbl-opt/nldbl-compat.c:60:1: error: conflicting types for ‘__nldbl___aprintf’; have ‘int(const char *, ...)’
>>    60 | __nldbl___aprintf (const char *fmt, ...)
>>       | ^~~~~~~~~~~~~~~~~
> [...]
>>
>> The __nldbl___aprintf has the wrong return type — int instead of char *.
> 
> Ok.
> 
> 	diff --git c/sysdeps/ieee754/ldbl-opt/nldbl-compat.c i/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> 	index f5c69f7ff4d5..bfa0514b18f1 100644
> 	--- c/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> 	+++ i/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> 	@@ -55,7 +55,7 @@ libc_hidden_proto (__nldbl___isoc23_vfwscanf)
> 	    we don't need to split this into one file per function for the
> 	    sake of statically linked programs.  */
> 	 
> 	-int
> 	+char *
> 	 attribute_compat_text_section
> 	 __nldbl___aprintf (const char *fmt, ...)
> 	 {
> 
> [...]
>>> diff --git a/debug/aprintf_chk.c b/debug/aprintf_chk.c
>>> new file mode 100644
>>> index 000000000000..30f7811f20da
>>> --- /dev/null
>>> +++ b/debug/aprintf_chk.c
>>> @@ -0,0 +1,51 @@
> [...]
>>> +/* Write formatted output from FORMAT to a string allocated with malloc.  */
>>> +char *
>>> +___aprintf_chk (int flag, const char *fmt, ...)
>>> +{
>>> +  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
>>> +     can only come from read-only format strings.  */
>>> +  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
>>> +  va_list ap;
>>> +  char *p;
>>> +
>>> +  va_start (ap, fmt);
>>> +  if (__vasprintf_internal (&p, fmt, ap, mode) < 0)
>>> +    p = NULL;
>>> +  va_end (ap);
>>> +
>>> +  return p;
>>> +}
>>
>> Adds some tests on debug/tst-fortify.c.
> 
> Ok.  Does this look good to you?
> 
> 	diff --git c/debug/tst-fortify.c i/debug/tst-fortify.c
> 	index ee83fca22467..2bc3e5eb1c47 100644
> 	--- c/debug/tst-fortify.c
> 	+++ i/debug/tst-fortify.c
> 	@@ -1026,34 +1026,48 @@ do_test (void)
> 	   strcpy (buf2 + 2, "%n%s%n");
> 	   /* When the format string is writable and contains %n,
> 	      with -D_FORTIFY_SOURCE=2 it causes __chk_fail.  */
> 	   CHK_FAIL2_START
> 	   if (asprintf (&my_ptr, buf2, str4, &n1, str5, &n1) != 14)
> 	     FAIL ();
> 	   else
> 	     free (my_ptr);
> 	   CHK_FAIL2_END
> 	 
> 	+  CHK_FAIL2_START
> 	+  my_ptr = aprintf (buf2, str4, &n1, str5, &n1);
> 	+  if (my_ptr == NULL)
> 	+    FAIL ();
> 	+  else
> 	+    free (my_ptr);
> 	+  CHK_FAIL2_END
> 	+
> 	   struct obstack obs;
> 	   obstack_init (&obs);
> 	   CHK_FAIL2_START
> 	   if (obstack_printf (&obs, buf2, str4, &n1, str5, &n1) != 14)
> 	     FAIL ();
> 	   CHK_FAIL2_END
> 	   obstack_free (&obs, NULL);
> 	 
> 	   my_ptr = NULL;
> 	   if (asprintf (&my_ptr, "%s%n%s%n", str4, &n1, str5, &n1) != 14)
> 	     FAIL ();
> 	   else
> 	     free (my_ptr);
> 	 
> 	+  my_ptr = aprintf ("%s%n%s%n", str4, &n1, str5, &n1);
> 	+  if (my_ptr == NULL)
> 	+    FAIL ();
> 	+  else
> 	+    free (my_ptr);
> 	+
> 	   obstack_init (&obs);
> 	   if (obstack_printf (&obs, "%s%n%s%n", str4, &n1, str5, &n1) != 14)
> 	     FAIL ();
> 	   obstack_free (&obs, NULL);
> 	 #endif
> 	 
> 	   if (freopen (temp_filename, "r", stdin) == NULL)
> 	     {
> 	       puts ("could not open temporary file");
> 	       exit (1);
> 
> [...]

It should suffice.

>>> diff --git a/libio/stdio.h b/libio/stdio.h
>>> index 3bf6a1f63203..81d7176c4535 100644
>>> --- a/libio/stdio.h
>>> +++ b/libio/stdio.h
>>> @@ -412,6 +412,19 @@ extern int asprintf (char **__restrict __ptr,
>>>       __THROWNL __attribute__ ((__format__ (__printf__, 2, 3))) __wur;
>>>  #endif
>>>  
>>> +#ifdef __USE_GNU
>>> +/* Write formatted output to a string dynamically allocated with `malloc'.  */
>>> +extern char *vaprintf (const char *__restrict __fmt, __gnuc_va_list __ap)
>>> +     __THROWNL __attribute__ ((__format__ (__printf__, 1, 0)))
>>> +     __attribute_malloc__;
>>
>> I think we should add __attr_dealloc_free, that one of the main advertises for
>> this symbol. Smae for asprintf and the __chk variants.
> 
> Agree.  I probably looked at strdup(3) for imitating it, and it seems it
> is lacking it.  Should we also add it to strdup(3) in string/string.h?
> 
> Anyway, here's a diff for aprintf(3):
> 
> 	diff --git i/include/stdio.h w/include/stdio.h
> 	index cfdec3681d51..721101a3ad04 100644
> 	--- i/include/stdio.h
> 	+++ w/include/stdio.h
> 	@@ -78,9 +78,9 @@ stdio_hidden_ldbl_proto (__, vfprintf_chk)
> 	 extern char *__fgets_unlocked_chk (char *buf, size_t size, int n, FILE *fp);
> 	 extern char *__fgets_chk (char *buf, size_t size, int n, FILE *fp);
> 	 extern char *__aprintf_chk (int, const char *, ...)
> 	-     __THROW __attribute_malloc__;
> 	+     __THROW __attribute_malloc__ __attr_dealloc_free;
> 	 extern char *__vaprintf_chk (int, const char *, __gnuc_va_list)
> 	-     __THROW __attribute_malloc__;
> 	+     __THROW __attribute_malloc__ __attr_dealloc_free;
> 	 stdio_hidden_ldbl_proto (__, vaprintf_chk)
> 	 extern int __asprintf_chk (char **, int, const char *, ...) __THROW;
> 	 extern int __vasprintf_chk (char **, int, const char *, __gnuc_va_list) __THROW;
> 	diff --git i/libio/bits/stdio2-decl.h w/libio/bits/stdio2-decl.h
> 	index cf52c46c31f6..d8d99fa1a9f3 100644
> 	--- i/libio/bits/stdio2-decl.h
> 	+++ w/libio/bits/stdio2-decl.h
> 	@@ -69,11 +69,11 @@ extern int __vdprintf_chk (int __fd, int __flag,
> 	 extern char *__aprintf_chk (int __flag,
> 				   const char *__restrict __fmt, ...)
> 	      __THROW __attribute__ ((__format__ (__printf__, 2, 3)))
> 	-     __attribute_malloc__;
> 	+     __attribute_malloc__ __attr_dealloc_free;
> 	 extern char *__vaprintf_chk (int __flag,
> 				    const char *__restrict __fmt, __gnuc_va_list __ap)
> 	      __THROW __attribute__ ((__format__ (__printf__, 2, 0)))
> 	-     __attribute_malloc__;
> 	+     __attribute_malloc__ __attr_dealloc_free;
> 	 extern int __asprintf_chk (char **__restrict __ptr, int __flag,
> 				   const char *__restrict __fmt, ...)
> 	      __THROW __attribute__ ((__format__ (__printf__, 3, 4))) __wur;
> 	diff --git i/libio/stdio.h w/libio/stdio.h
> 	index 81d7176c4535..8aa583eff8d5 100644
> 	--- i/libio/stdio.h
> 	+++ w/libio/stdio.h
> 	@@ -416,13 +416,13 @@ extern int asprintf (char **__restrict __ptr,
> 	 /* Write formatted output to a string dynamically allocated with `malloc'.  */
> 	 extern char *vaprintf (const char *__restrict __fmt, __gnuc_va_list __ap)
> 	      __THROWNL __attribute__ ((__format__ (__printf__, 1, 0)))
> 	-     __attribute_malloc__;
> 	+     __attribute_malloc__ __attr_dealloc_free;
> 	 extern char *__aprintf (const char *__restrict __fmt, ...)
> 	      __THROWNL __attribute__ ((__format__ (__printf__, 1, 2)))
> 	-     __attribute_malloc__;
> 	+     __attribute_malloc__ __attr_dealloc_free;
> 	 extern char *aprintf (const char *__restrict __fmt, ...)
> 	      __THROWNL __attribute__ ((__format__ (__printf__, 1, 2)))
> 	-     __attribute_malloc__;
> 	+     __attribute_malloc__ __attr_dealloc_free;
> 	 #endif
> 	 
> 	 #ifdef __USE_XOPEN2K8
> 	diff --git i/sysdeps/ieee754/ldbl-opt/nldbl-compat.h w/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
> 	index 9da1c2d241b4..3a3c7baf0e21 100644
> 	--- i/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
> 	+++ w/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
> 	@@ -130,7 +130,7 @@ extern int __nldbl___vswprintf_chk (wchar_t *__restrict, size_t, int, size_t,
> 					    const wchar_t *__restrict, __gnuc_va_list)
> 	   __THROW;
> 	 extern char *__nldbl___vaprintf_chk (int, const char *, __gnuc_va_list)
> 	-  __THROW __attribute_malloc__;
> 	+  __THROW __attribute_malloc__ __attr_dealloc_free;
> 	 extern int __nldbl___vasprintf_chk (char **, int, const char *, __gnuc_va_list)
> 	   __THROW;
> 	 extern int __nldbl___vdprintf_chk (int, int, const char *, __gnuc_va_list);
> 

Looks ok.

>>
>>> +extern char *__aprintf (const char *__restrict __fmt, ...)
>>> +     __THROWNL __attribute__ ((__format__ (__printf__, 1, 2)))
>>> +     __attribute_malloc__;
>>
>> I think there is no need to export the __aprintf for a new symbol, we did it
>> on other symbols (like scanf) we can asm alias depending of the C standard
>> being used. Since this is a new symbol, we can just use the aprintf.
> 
> Can we use aprintf(3) internally within glibc?  Users might have
> defined aprintf() themselves, since it's non-standard.

Yes, but in this case there is also no need to export it on the installed headers.
We can do in on the internal one instead (at include/) and use a libc_hidden_{proto,def}
to avoid PLTs.

But I would only add it if/when we actually use it.

> 
>>
>>> +extern char *aprintf (const char *__restrict __fmt, ...)
>>> +     __THROWNL __attribute__ ((__format__ (__printf__, 1, 2)))
>>> +     __attribute_malloc__;
>>> +#endif
>>> +
>>>  #ifdef __USE_XOPEN2K8
>>>  /* Write formatted output to a file descriptor.  */
>>>  extern int vdprintf (int __fd, const char *__restrict __fmt,
>>> diff --git a/libio/tst-aprintf.c b/libio/tst-aprintf.c
>>> new file mode 100644
>>> index 000000000000..0c7d7a8024c3
>>> --- /dev/null
>>> +++ b/libio/tst-aprintf.c
>>> @@ -0,0 +1,73 @@
>>> +/* Test aprintf.
>>> +   Copyright (C) 2026 Free Software Foundation, Inc.
>>> +   This file is part of the GNU C Library.
>>> +
>>> +   The GNU C Library is free software; you can redistribute it and/or
>>> +   modify it under the terms of the GNU Lesser General Public
>>> +   License as published by the Free Software Foundation; either
>>> +   version 2.1 of the License, or (at your option) any later version.
>>> +
>>> +   The GNU C Library is distributed in the hope that it will be useful,
>>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>> +   Lesser General Public License for more details.
>>> +
>>> +   You should have received a copy of the GNU Lesser General Public
>>> +   License along with the GNU C Library; if not, see
>>> +   <https://www.gnu.org/licenses/>.  */
>>> +
>>> +#include <errno.h>
>>> +#include <stdlib.h>
>>> +#include <stdio.h>
>>> +#include <support/check.h>
>>> +#include <sys/resource.h>
>>> +#include <libc-diag.h>
>>> +
>>> +static int
>>> +do_test (void)
>>> +{
>>> +  char *buf;
>>> +
>>> +  /* Success */
>>> +  buf = aprintf ("foo %d", 42);
>>> +  TEST_COMPARE_STRING (buf, "foo 42");
>>> +  free(buf);
>>> +
>>> +  {
>>> +    /* -Wformat-overflow warns that the format would produce more than
>>> +       INT_MAX bytes; however, this function does not share this
>>> +       inherent limitation of other printf-like functions.  The current
>>> +       implementation fails with EOVERFLOW, because it's a trivial
>>> +       wrapper; however, in the future we should improve the function so
>>> +       that this doesn't fail anymore with EOVERFLOW.  When that is
>>> +       implemented, this test will stop failing.  */
>>> +    DIAG_PUSH_NEEDS_COMMENT;
>>> +    DIAG_IGNORE_NEEDS_COMMENT (8, "-Wformat-overflow=");
>>> +    buf = aprintf ("%2000000000d %2000000000d", 1, 2);
>>
>> Does it work on ILP32 ABIs (x32 and mips64-n32)?
> 
> It would probably ENOMEM instead of EOVERFLOW, I suspect.
> 
> I've done
> 
> 	diff --git i/libio/tst-aprintf.c w/libio/tst-aprintf.c
> 	index 0c7d7a8024c3..1db26505ee03 100644
> 	--- i/libio/tst-aprintf.c
> 	+++ w/libio/tst-aprintf.c
> 	@@ -53,7 +53,8 @@ do_test (void)
> 		that happens, this test will fail.  Just remove it and enable the
> 		test under '#if 0'.  */
> 	     TEST_VERIFY (buf == NULL);
> 	-    TEST_VERIFY (errno == EOVERFLOW);
> 	+    if (errno != ENOMEM)
> 	+      TEST_VERIFY (errno == EOVERFLOW);
> 	 #endif
> 	   }
> 
> (as is done is the asprintf(3) tests.)
> 

Ok.

>>> +    DIAG_POP_NEEDS_COMMENT;
>>> +#if 0
>>> +    if (buf == NULL)
>>> +      TEST_VERIFY (errno == ENOMEM);
>>> +#else
>>
>> Plase remove the '#if 0' path here.
> 
> Hmmm, okay.
> 
>>> +    /* We should eventually not fail with EOVERFLOW from aprintf.  When
>>> +       that happens, this test will fail.  Just remove it and enable the
>>> +       test under '#if 0'.  */
>>> +    TEST_VERIFY (buf == NULL);
>>> +    TEST_VERIFY (errno == EOVERFLOW);
>>> +#endif
> 
> [...]
>>> diff --git a/stdio-common/aprintf.c b/stdio-common/aprintf.c
>>> new file mode 100644
>>> index 000000000000..bee4966707ae
>>> --- /dev/null
>>> +++ b/stdio-common/aprintf.c
>>> @@ -0,0 +1,40 @@
>>> +/* Copyright (C) 2026 Free Software Foundation, Inc.
>>> +   This file is part of the GNU C Library.
>>> +
>>> +   The GNU C Library is free software; you can redistribute it and/or
>>> +   modify it under the terms of the GNU Lesser General Public
>>> +   License as published by the Free Software Foundation; either
>>> +   version 2.1 of the License, or (at your option) any later version.
>>> +
>>> +   The GNU C Library is distributed in the hope that it will be useful,
>>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>> +   Lesser General Public License for more details.
>>> +
>>> +   You should have received a copy of the GNU Lesser General Public
>>> +   License along with the GNU C Library; if not, see
>>> +   <https://www.gnu.org/licenses/>.  */
>>
>> Should we add a LGPL linking-exception clause, as other printf symbols?
> 
> I copied this from stdio-common/asprintf.c, IIRC.  I don't see the
> exception in the other files:
> 
> 	$ find stdio-common/ -type f \
> 		| grep printf \
> 		| xargs grep -i exception;
> 	$
> 
> The only file within stdio-common/ where I can see the exception is this
> one:
> 
> 	$ find stdio-common/ -type f \
> 		| grep -v Makefile \
> 		| xargs grep -i exception;
> 	stdio-common/isoc99_vsscanf.c:   As a special exception, if you link the code in this file with
> 	stdio-common/isoc99_vsscanf.c:   the GNU Lesser General Public License.  This exception does not
> 	stdio-common/isoc99_vsscanf.c:   This exception applies to code released by its copyright holders
> 	stdio-common/isoc99_vsscanf.c:   in files containing the exception.  */
> 
> [...]

Right, I am not sure why there are added on isoc99_vsscanf.c in first
place.

>>> diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
>>> index e239cd5bc5c4..f5c69f7ff4d5 100644
>>> --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
>>> +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
> [...]
>>> @@ -1342,3 +1396,8 @@ compat_symbol (libc, __nldbl___fprintf_chk, __fprintf_chk, GLIBC_2_3_4);
>>>  compat_symbol (libc, __nldbl___vprintf_chk, __vprintf_chk, GLIBC_2_3_4);
>>>  compat_symbol (libc, __nldbl___vfprintf_chk, __vfprintf_chk, GLIBC_2_3_4);
>>>  #endif
>>> +#if LONG_DOUBLE_COMPAT(libc, GLIBC_2_4_4)
>>> +compat_symbol (libc, __nldbl_aprintf, aprintf, GLIBC_2_4_4);
>>> +compat_symbol (libc, __nldbl_vaprintf, vaprintf, GLIBC_2_4_4);
>>> +compat_symbol (libc, __nldbl___aprintf, __aprintf, GLIBC_2_4_4);
>>> +#endif
>>
>> I think you meant *2_44* here. But this whole block should not be required,
>> aprintf is a new symbol, so it has no historic ldbl == double ABI to be 
>> compatible with. 
> 
> So, should I drop all changes to
> sysdeps/ieee754/ldbl-opt/nldbl-compat.c?

I think so.  There is no need for compat symbol, although there is the need
to handle ABI that defined double == long double (I recall this is done by
other file in sysdeps/ieee754/ldbl-opt).

> 
>> New symbols do not get a compat_symbol at an older version (and compat_symbol 
>> at the current dev version is illegal anyway). Check the __isoc23_* additions, 
>> which use libc_hidden_def + the normal versioned export.
> 
> Would you mind naming a few __isoc23_* names?  I don't know those
> functions.

For instance __isoc23_vfscanf.  It is only declared at the installed header if
there is no REDIRECT support (asm alias).  Since for __asprintf there is no need
for alias at this moment, there is no need to add such symbol.
  
Alejandro Colomar June 5, 2026, 8:42 p.m. UTC | #4
Hi Adhemerval,

On 2026-06-05T15:42:30-0300, Adhemerval Zanella Netto wrote:
[...]
> >> But I do not think this is a hard requirement, nor a blocker for this patch 
> >> (I am not sure if Florian agrees, so I would check with him).
> > 
> > He recently said he wants to block it for this, IIUC.  I'll work on
> > a patch that applies on top of this one, after this one looks good to
> > you.
> 
> Indeed, it seems Florian does want to get this fixed [1].
> 
> [1] https://inbox.sourceware.org/libc-alpha/87h5nmo5cz.fsf@oldenburg.str.redhat.com/

No problem.  Once we finish reviewing this patch, I'll start working on
another patch that applies on top of this one, and send the full patch
set.  However, I want to get this one done first (even if we don't apply
it yet).

[...]
> >> Adds some tests on debug/tst-fortify.c.
> > 
> > Ok.  Does this look good to you?
[...]
> 
> It should suffice.

Thanks!  Amended.

[...]
> >> I think we should add __attr_dealloc_free, that one of the main advertises for
> >> this symbol. Smae for asprintf and the __chk variants.
> > 
> > Agree.  I probably looked at strdup(3) for imitating it, and it seems it
> > is lacking it.  Should we also add it to strdup(3) in string/string.h?
> > 
> > Anyway, here's a diff for aprintf(3):
> > 
> > 	diff --git i/include/stdio.h w/include/stdio.h
[...]
> > 
> 
> Looks ok.

Amended.

> >>> +extern char *__aprintf (const char *__restrict __fmt, ...)
> >>> +     __THROWNL __attribute__ ((__format__ (__printf__, 1, 2)))
> >>> +     __attribute_malloc__;
> >>
> >> I think there is no need to export the __aprintf for a new symbol, we did it
> >> on other symbols (like scanf) we can asm alias depending of the C standard
> >> being used. Since this is a new symbol, we can just use the aprintf.
> > 
> > Can we use aprintf(3) internally within glibc?  Users might have
> > defined aprintf() themselves, since it's non-standard.
> 
> Yes, but in this case there is also no need to export it on the installed headers.
> We can do in on the internal one instead (at include/) and use a libc_hidden_{proto,def}
> to avoid PLTs.

Hmmmm, my head explodes when trying to understand all those declarations
and which ones are exported and not.

I'll try to do what you suggested, but I'll probably get it wrong.  On
Monday I'll get back home (I don't have a copy of the patches in this
computer) and will work on this, and send patches on Monday or Tuesday.
I'll probably need help to fix that, since I'll get it wrong.  :)

> But I would only add it if/when we actually use it.

Makes sense.  That will simplify the initial patch.

[...]
> >>> +    buf = aprintf ("%2000000000d %2000000000d", 1, 2);
> >>
> >> Does it work on ILP32 ABIs (x32 and mips64-n32)?
> > 
> > It would probably ENOMEM instead of EOVERFLOW, I suspect.
> > 
> > I've done
> > 
[...]
> > 
> > (as is done is the asprintf(3) tests.)
> > 
> 
> Ok.

Amended.

[...]
> >> Should we add a LGPL linking-exception clause, as other printf symbols?
> > 
> > I copied this from stdio-common/asprintf.c, IIRC.  I don't see the
> > exception in the other files:
> > 
> > 	$ find stdio-common/ -type f \
> > 		| grep printf \
> > 		| xargs grep -i exception;
> > 	$
> > 
> > The only file within stdio-common/ where I can see the exception is this
> > one:
> > 
> > 	$ find stdio-common/ -type f \
> > 		| grep -v Makefile \
> > 		| xargs grep -i exception;
> > 	stdio-common/isoc99_vsscanf.c:   As a special exception, if you link the code in this file with
> > 	stdio-common/isoc99_vsscanf.c:   the GNU Lesser General Public License.  This exception does not
> > 	stdio-common/isoc99_vsscanf.c:   This exception applies to code released by its copyright holders
> > 	stdio-common/isoc99_vsscanf.c:   in files containing the exception.  */
> > 
> > [...]
> 
> Right, I am not sure why there are added on isoc99_vsscanf.c in first
> place.

Okay; no changes then.

[...]
> > So, should I drop all changes to
> > sysdeps/ieee754/ldbl-opt/nldbl-compat.c?
> 
> I think so.  There is no need for compat symbol, although there is the need
> to handle ABI that defined double == long double (I recall this is done by
> other file in sysdeps/ieee754/ldbl-opt).

Thanks; I'll drop all changes to sysdeps/ieee754/ldbl-opt/nldbl-compat.c
and only those changes.  I hope that's enough.  If not, we'll see in the
next version of the patch set next week.

> > 
> >> New symbols do not get a compat_symbol at an older version (and compat_symbol 
> >> at the current dev version is illegal anyway). Check the __isoc23_* additions, 
> >> which use libc_hidden_def + the normal versioned export.
> > 
> > Would you mind naming a few __isoc23_* names?  I don't know those
> > functions.
> 
> For instance __isoc23_vfscanf.  It is only declared at the installed header if
> there is no REDIRECT support (asm alias).  Since for __asprintf there is no need
> for alias at this moment, there is no need to add such symbol.

Hmmmm.  Again, my head explodes with all this combination of symbols,
but I guess I'll eventually get it.  :)


Have a lovely day!
Alex
  

Patch

diff --git a/debug/Makefile b/debug/Makefile
index c6c1069b405a..765720a14083 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -31,6 +31,7 @@  headers	:= execinfo.h
 routines = \
   $(static-only-routines) \
   ____longjmp_chk \
+  aprintf_chk \
   asprintf_chk \
   backtrace \
   backtracesyms \
@@ -94,6 +95,7 @@  routines = \
   strncpy_chk \
   swprintf_chk \
   ttyname_r_chk \
+  vaprintf_chk \
   vasprintf_chk \
   vdprintf_chk \
   vfprintf_chk \
@@ -143,6 +145,8 @@  CFLAGS-sprintf_chk.c += $(libio-mtsafe)
 CFLAGS-snprintf_chk.c += $(libio-mtsafe)
 CFLAGS-vsprintf_chk.c += $(libio-mtsafe)
 CFLAGS-vsnprintf_chk.c += $(libio-mtsafe)
+CFLAGS-aprintf_chk.c += $(libio-mtsafe)
+CFLAGS-vaprintf_chk.c += $(libio-mtsafe)
 CFLAGS-asprintf_chk.c += $(libio-mtsafe)
 CFLAGS-vasprintf_chk.c += $(libio-mtsafe)
 CFLAGS-obprintf_chk.c += $(libio-mtsafe)
diff --git a/debug/Versions b/debug/Versions
index fc818d29aa75..d87148f5a30f 100644
--- a/debug/Versions
+++ b/debug/Versions
@@ -71,6 +71,9 @@  libc {
   GLIBC_2.43 {
     __memset_explicit_chk;
   }
+  GLIBC_2.44 {
+    __aprintf_chk; __vaprintf_chk;
+  }
   GLIBC_PRIVATE {
     __fortify_fail;
   }
diff --git a/debug/aprintf_chk.c b/debug/aprintf_chk.c
new file mode 100644
index 000000000000..30f7811f20da
--- /dev/null
+++ b/debug/aprintf_chk.c
@@ -0,0 +1,51 @@ 
+/* Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdarg.h>
+#include <libio/libioP.h>
+
+
+/* Write formatted output from FORMAT to a string allocated with malloc.  */
+char *
+___aprintf_chk (int flag, const char *fmt, ...)
+{
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+  va_list ap;
+  char *p;
+
+  va_start (ap, fmt);
+  if (__vasprintf_internal (&p, fmt, ap, mode) < 0)
+    p = NULL;
+  va_end (ap);
+
+  return p;
+}
+#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
+/* This is needed since <bits/stdio-lbdl.h> is included in this case, leading to
+ * multiple asm redirection of the same symbol
+ */
+ldbl_hidden_def (___aprintf_chk, __aprintf_chk)
+ldbl_strong_alias (___aprintf_chk, __aprintf_chk)
+#else
+/* On some systems introduction of ldbl_* macros lead to ABI breakage due to the
+ * long_double_symbol aliasing.
+ */
+strong_alias (___aprintf_chk, __aprintf_chk)
+libc_hidden_def (__aprintf_chk)
+#endif
diff --git a/debug/vaprintf_chk.c b/debug/vaprintf_chk.c
new file mode 100644
index 000000000000..1ca966337d11
--- /dev/null
+++ b/debug/vaprintf_chk.c
@@ -0,0 +1,39 @@ 
+/* Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.
+
+   As a special exception, if you link the code in this file with
+   files compiled with a GNU compiler to produce an executable,
+   that does not cause the resulting executable to be covered by
+   the GNU Lesser General Public License.  This exception does not
+   however invalidate any other reasons why the executable file
+   might be covered by the GNU Lesser General Public License.
+   This exception applies to code released by its copyright holders
+   in files containing the exception.  */
+
+#include <libio/libioP.h>
+
+char *
+__vaprintf_chk (int flag, const char *fmt, va_list ap)
+{
+  /* For flag > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
+     can only come from read-only format strings.  */
+  unsigned int mode = (flag > 0) ? PRINTF_FORTIFY : 0;
+  char *p;
+
+  return __vasprintf_internal (&p, fmt, ap, mode) < 0 ? NULL : p;
+}
+libc_hidden_def (__vaprintf_chk)
diff --git a/include/stdio.h b/include/stdio.h
index 88166993dd95..cfdec3681d51 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -77,6 +77,11 @@  extern int __vfprintf_chk (FILE *, int, const char *, __gnuc_va_list);
 stdio_hidden_ldbl_proto (__, vfprintf_chk)
 extern char *__fgets_unlocked_chk (char *buf, size_t size, int n, FILE *fp);
 extern char *__fgets_chk (char *buf, size_t size, int n, FILE *fp);
+extern char *__aprintf_chk (int, const char *, ...)
+     __THROW __attribute_malloc__;
+extern char *__vaprintf_chk (int, const char *, __gnuc_va_list)
+     __THROW __attribute_malloc__;
+stdio_hidden_ldbl_proto (__, vaprintf_chk)
 extern int __asprintf_chk (char **, int, const char *, ...) __THROW;
 extern int __vasprintf_chk (char **, int, const char *, __gnuc_va_list) __THROW;
 stdio_hidden_ldbl_proto (__, vasprintf_chk)
@@ -239,6 +244,7 @@  extern const size_t _sys_errlist_internal_len attribute_hidden;
 extern const char *__get_errlist (int) attribute_hidden;
 extern const char *__get_errname (int) attribute_hidden;
 
+libc_hidden_ldbl_proto (__aprintf)
 libc_hidden_ldbl_proto (__asprintf)
 
 #  if IS_IN (libc)
@@ -317,8 +323,10 @@  rtld_hidden_proto (__libc_fatal)
 libc_hidden_proto (__fgets_unlocked_chk)
 
 #if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
+libc_hidden_ldbl_proto (__aprintf_chk)
 libc_hidden_ldbl_proto (__asprintf_chk)
 #else
+libc_hidden_proto (__aprintf_chk)
 libc_hidden_proto (__asprintf_chk)
 #endif
 
diff --git a/libio/Makefile b/libio/Makefile
index a8011a7f0d76..c50a96df1879 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -43,7 +43,7 @@  routines	:=							      \
 									      \
 	clearerr feof ferror fileno fputc freopen fseek getc getchar	      \
 	memstream pclose putc putchar rewind setbuf setlinebuf vasprintf      \
-	iovdprintf vscanf vsnprintf obprintf fcloseall fseeko ftello	      \
+	vaprintf iovdprintf vscanf vsnprintf obprintf fcloseall fseeko ftello \
 	freopen64 fseeko64 ftello64					      \
 									      \
 	__fbufsize __freading __fwriting __freadable __fwritable __flbf	      \
@@ -62,6 +62,7 @@  routines_no_fortify += \
   iofgetws_u \
   iovdprintf \
   swprintf \
+  vaprintf \
   vasprintf \
   vsnprintf \
   vswprintf \
@@ -91,6 +92,7 @@  tests = \
   test-fmemopen \
   test-fputs-unbuffered-full \
   test-fputws-unbuffered-full \
+  tst-aprintf \
   tst-asprintf-null \
   tst-atime \
   tst-bz22415 \
diff --git a/libio/Versions b/libio/Versions
index b91a7bc914ae..48ffe3d3161f 100644
--- a/libio/Versions
+++ b/libio/Versions
@@ -155,6 +155,9 @@  libc {
     # f*
     fmemopen;
   }
+  GLIBC_2.44 {
+    vaprintf;
+  }
   GLIBC_PRIVATE {
     # Used by NPTL and librt
     __libc_fatal;
diff --git a/libio/bits/stdio-ldbl.h b/libio/bits/stdio-ldbl.h
index 3cbff14ec959..3b805b3ee3e3 100644
--- a/libio/bits/stdio-ldbl.h
+++ b/libio/bits/stdio-ldbl.h
@@ -99,6 +99,9 @@  __LDBL_REDIR_DECL (dprintf)
 #endif
 
 #ifdef __USE_GNU
+__LDBL_REDIR_DECL (vaprintf)
+__LDBL_REDIR2_DECL (aprintf)
+__LDBL_REDIR_DECL (aprintf)
 __LDBL_REDIR_DECL (vasprintf)
 __LDBL_REDIR2_DECL (asprintf)
 __LDBL_REDIR_DECL (asprintf)
@@ -123,6 +126,8 @@  __LDBL_REDIR2_DECL (dprintf_chk)
 __LDBL_REDIR2_DECL (vdprintf_chk)
 #  endif
 #  ifdef __USE_GNU
+__LDBL_REDIR2_DECL (aprintf_chk)
+__LDBL_REDIR2_DECL (vaprintf_chk)
 __LDBL_REDIR2_DECL (asprintf_chk)
 __LDBL_REDIR2_DECL (vasprintf_chk)
 __LDBL_REDIR2_DECL (obstack_printf_chk)
diff --git a/libio/bits/stdio2-decl.h b/libio/bits/stdio2-decl.h
index ada092eab2b4..cf52c46c31f6 100644
--- a/libio/bits/stdio2-decl.h
+++ b/libio/bits/stdio2-decl.h
@@ -66,6 +66,14 @@  extern int __vdprintf_chk (int __fd, int __flag,
 
 # ifdef __USE_GNU
 
+extern char *__aprintf_chk (int __flag,
+			   const char *__restrict __fmt, ...)
+     __THROW __attribute__ ((__format__ (__printf__, 2, 3)))
+     __attribute_malloc__;
+extern char *__vaprintf_chk (int __flag,
+			    const char *__restrict __fmt, __gnuc_va_list __ap)
+     __THROW __attribute__ ((__format__ (__printf__, 2, 0)))
+     __attribute_malloc__;
 extern int __asprintf_chk (char **__restrict __ptr, int __flag,
 			   const char *__restrict __fmt, ...)
      __THROW __attribute__ ((__format__ (__printf__, 3, 4))) __wur;
diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h
index 193494db2787..b9fed67eac59 100644
--- a/libio/bits/stdio2.h
+++ b/libio/bits/stdio2.h
@@ -200,6 +200,18 @@  vdprintf (int __fd, const char *__restrict __fmt, __gnuc_va_list __ap)
 
 # ifdef __USE_GNU
 #  ifdef __va_arg_pack
+__fortify_function char *
+__NTH (aprintf (const char *__restrict __fmt, ...))
+{
+  return __aprintf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __va_arg_pack ());
+}
+
+__fortify_function char *
+__NTH (__aprintf (const char *__restrict __fmt, ...))
+{
+  return __aprintf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __va_arg_pack ());
+}
+
 __fortify_function int
 __NTH (asprintf (char **__restrict __ptr, const char *__restrict __fmt, ...))
 {
@@ -223,6 +235,26 @@  __NTH (obstack_printf (struct obstack *__restrict __obstack,
 			       __va_arg_pack ());
 }
 #  elif __fortify_use_clang
+__fortify_function char *
+__NTH (aprintf (const char *__restrict __fmt, ...))
+{
+  __gnuc_va_list __fortify_ap;
+  __builtin_va_start (__fortify_ap, __fmt);
+  char * __p = __vaprintf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __fortify_ap);
+  __builtin_va_end (__fortify_ap);
+  return __p;
+}
+
+__fortify_function char *
+__NTH (__aprintf (const char *__restrict __fmt, ...))
+{
+  __gnuc_va_list __fortify_ap;
+  __builtin_va_start (__fortify_ap, __fmt);
+  char *__p = __vaprintf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __fortify_ap);
+  __builtin_va_end (__fortify_ap);
+  return __p;
+}
+
 __fortify_function_error_function __attribute_overloadable__ int
 __NTH (asprintf (__fortify_clang_overload_arg (char **, __restrict, __ptr),
 		 const char *__restrict __fmt, ...))
@@ -260,6 +292,10 @@  __NTH (obstack_printf (__fortify_clang_overload_arg (struct obstack *,
   return __r;
 }
 #  elif !defined __cplusplus
+#   define aprintf(...) \
+  __aprintf_chk (__USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
+#   define __aprintf(...) \
+  __aprintf_chk (__USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
 #   define asprintf(ptr, ...) \
   __asprintf_chk (ptr, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
 #   define __asprintf(ptr, ...) \
@@ -268,6 +304,12 @@  __NTH (obstack_printf (__fortify_clang_overload_arg (struct obstack *,
   __obstack_printf_chk (obstack, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
 #  endif
 
+__fortify_function char *
+__NTH (vaprintf (const char *__restrict __fmt, __gnuc_va_list __ap))
+{
+  return __vaprintf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __ap);
+}
+
 __fortify_function int
 __NTH (vasprintf (char **__restrict __ptr, const char *__restrict __fmt,
 		  __gnuc_va_list __ap))
diff --git a/libio/stdio.h b/libio/stdio.h
index 3bf6a1f63203..81d7176c4535 100644
--- a/libio/stdio.h
+++ b/libio/stdio.h
@@ -412,6 +412,19 @@  extern int asprintf (char **__restrict __ptr,
      __THROWNL __attribute__ ((__format__ (__printf__, 2, 3))) __wur;
 #endif
 
+#ifdef __USE_GNU
+/* Write formatted output to a string dynamically allocated with `malloc'.  */
+extern char *vaprintf (const char *__restrict __fmt, __gnuc_va_list __ap)
+     __THROWNL __attribute__ ((__format__ (__printf__, 1, 0)))
+     __attribute_malloc__;
+extern char *__aprintf (const char *__restrict __fmt, ...)
+     __THROWNL __attribute__ ((__format__ (__printf__, 1, 2)))
+     __attribute_malloc__;
+extern char *aprintf (const char *__restrict __fmt, ...)
+     __THROWNL __attribute__ ((__format__ (__printf__, 1, 2)))
+     __attribute_malloc__;
+#endif
+
 #ifdef __USE_XOPEN2K8
 /* Write formatted output to a file descriptor.  */
 extern int vdprintf (int __fd, const char *__restrict __fmt,
diff --git a/libio/tst-aprintf.c b/libio/tst-aprintf.c
new file mode 100644
index 000000000000..0c7d7a8024c3
--- /dev/null
+++ b/libio/tst-aprintf.c
@@ -0,0 +1,73 @@ 
+/* Test aprintf.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <support/check.h>
+#include <sys/resource.h>
+#include <libc-diag.h>
+
+static int
+do_test (void)
+{
+  char *buf;
+
+  /* Success */
+  buf = aprintf ("foo %d", 42);
+  TEST_COMPARE_STRING (buf, "foo 42");
+  free(buf);
+
+  {
+    /* -Wformat-overflow warns that the format would produce more than
+       INT_MAX bytes; however, this function does not share this
+       inherent limitation of other printf-like functions.  The current
+       implementation fails with EOVERFLOW, because it's a trivial
+       wrapper; however, in the future we should improve the function so
+       that this doesn't fail anymore with EOVERFLOW.  When that is
+       implemented, this test will stop failing.  */
+    DIAG_PUSH_NEEDS_COMMENT;
+    DIAG_IGNORE_NEEDS_COMMENT (8, "-Wformat-overflow=");
+    buf = aprintf ("%2000000000d %2000000000d", 1, 2);
+    DIAG_POP_NEEDS_COMMENT;
+#if 0
+    if (buf == NULL)
+      TEST_VERIFY (errno == ENOMEM);
+#else
+    /* We should eventually not fail with EOVERFLOW from aprintf.  When
+       that happens, this test will fail.  Just remove it and enable the
+       test under '#if 0'.  */
+    TEST_VERIFY (buf == NULL);
+    TEST_VERIFY (errno == EOVERFLOW);
+#endif
+  }
+
+  /* Force ENOMEM in the test below.  */
+  struct rlimit rl;
+  TEST_COMPARE (getrlimit (RLIMIT_AS, &rl), 0);
+  rl.rlim_cur = 10 * 1024 * 1024;
+  TEST_COMPARE (setrlimit (RLIMIT_AS, &rl), 0);
+
+  buf = aprintf ("%20000000d", 1);
+  TEST_VERIFY (buf == NULL);
+  TEST_COMPARE (errno, ENOMEM);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/libio/vaprintf.c b/libio/vaprintf.c
new file mode 100644
index 000000000000..157f783d30b1
--- /dev/null
+++ b/libio/vaprintf.c
@@ -0,0 +1,39 @@ 
+/* Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.
+
+   As a special exception, if you link the code in this file with
+   files compiled with a GNU compiler to produce an executable,
+   that does not cause the resulting executable to be covered by
+   the GNU Lesser General Public License.  This exception does not
+   however invalidate any other reasons why the executable file
+   might be covered by the GNU Lesser General Public License.
+   This exception applies to code released by its copyright holders
+   in files containing the exception.  */
+
+#include <libioP.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+
+char *
+__vaprintf (const char *fmt, va_list ap)
+{
+  char *p;
+
+  return __vasprintf_internal (&p, fmt, ap, 0) < 0 ? NULL : p;
+}
+ldbl_weak_alias (__vaprintf, vaprintf)
diff --git a/manual/stdio.texi b/manual/stdio.texi
index c01feaed7d59..e7deca78fd53 100644
--- a/manual/stdio.texi
+++ b/manual/stdio.texi
@@ -2578,6 +2578,32 @@  other systems offer this function as an async-signal-safe alternative to
 The functions in this section do formatted output and place the results
 in dynamically allocated memory.
 
+@deftypefun {char *} aprintf (const char *@var{template}, @dots{})
+@standards{GNU, stdio.h}
+@safety{@prelim{}@mtsafe{@mtslocale{}}@asunsafe{@ascuheap{}}@acunsafe{@acsmem{}}}
+This function is similar to @code{sprintf},
+except that it dynamically allocates a string
+(as with @code{malloc}; @pxref{Unconstrained Allocation})
+to hold the output,
+instead of putting the output in a buffer you allocate in advance.
+A successful call to @code{aprintf} returns
+a pointer to the newly allocated string.
+
+Here is how to use @code{aprintf}
+to get the same result as the @code{snprintf} example,
+but more easily:
+
+@smallexample
+/* @r{Construct a message describing the value of a variable}
+   @r{whose name is @var{name} and whose value is @var{value}.} */
+char *
+make_message (char *name, char *value)
+@{
+  return aprintf ("value of %s is %s", name, value);
+@}
+@end smallexample
+@end deftypefun
+
 @deftypefun int asprintf (char **@var{ptr}, const char *@var{template}, @dots{})
 @standards{GNU, stdio.h}
 @safety{@prelim{}@mtsafe{@mtslocale{}}@asunsafe{@ascuheap{}}@acunsafe{@acsmem{}}}
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 0c0085e60763..2d829accbc16 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -89,6 +89,7 @@  routines := \
   _fitoa_word \
   _itoa \
   _itowa \
+  aprintf \
   asprintf \
   ctermid \
   cuserid \
@@ -177,6 +178,7 @@  routines := \
 
 # Exclude fortified routines from being built with _FORTIFY_SOURCE
 routines_no_fortify += \
+  aprintf \
   asprintf \
   dprintf \
   fprintf \
diff --git a/stdio-common/Versions b/stdio-common/Versions
index 8e1cbf85590c..93d635ff865c 100644
--- a/stdio-common/Versions
+++ b/stdio-common/Versions
@@ -71,6 +71,9 @@  libc {
     __isoc23_sscanf;
     __isoc23_vsscanf;
   }
+  GLIBC_2.44 {
+    aprintf;
+  }
   GLIBC_PRIVATE {
     # global variables
     _itoa_lower_digits;
diff --git a/stdio-common/aprintf.c b/stdio-common/aprintf.c
new file mode 100644
index 000000000000..bee4966707ae
--- /dev/null
+++ b/stdio-common/aprintf.c
@@ -0,0 +1,40 @@ 
+/* Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdarg.h>
+#include <libioP.h>
+
+/* Write formatted output from FORMAT to a string which is
+   allocated with malloc.  */
+/* VARARGS1 */
+char *
+___aprintf (const char *fmt, ...)
+{
+  char *p;
+  va_list ap;
+
+  va_start (ap, fmt);
+  if (__vasprintf_internal (&p, fmt, ap, 0) < 0)
+    p = NULL;
+  va_end (ap);
+
+  return p;
+}
+ldbl_hidden_def (___aprintf, __aprintf)
+
+ldbl_strong_alias (___aprintf, __aprintf)
+ldbl_weak_alias (___aprintf, aprintf)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
index 10ae73dba1b5..e0989a5147fc 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Makefile
@@ -5,6 +5,7 @@  ldbl-extra-routines += fwscanf \
 		       swscanf \
 		       swprintf \
 		       wscanf \
+		       vaprintf \
 		       vasprintf \
 		       vdprintf \
 		       vscanf \
@@ -40,6 +41,7 @@  endif
 
 ifeq ($(subdir),stdio-common)
 ldbl-extra-routines += printf_size \
+		       aprintf \
 		       asprintf \
 		       dprintf \
 		       fprintf \
@@ -250,12 +252,14 @@  $(objpfx)test-printf-size-ibm128.out: \
 endif
 
 ifeq ($(subdir),debug)
-ldbl-extra-routines += asprintf_chk \
+ldbl-extra-routines += aprintf_chk \
+		       asprintf_chk \
 		       dprintf_chk \
 		       fprintf_chk \
 		       printf_chk \
 		       snprintf_chk \
 		       sprintf_chk \
+		       vaprintf_chk \
 		       vasprintf_chk \
 		       vdprintf_chk \
 		       vfprintf_chk \
@@ -480,6 +484,7 @@  endif
 routines += $(foreach r,$(ldbl-extra-routines),ieee128-$(r))
 
 routines_no_fortify += \
+  ieee128-aprintf \
   ieee128-asprintf \
   ieee128-dprintf \
   ieee128-fprintf \
@@ -490,6 +495,7 @@  routines_no_fortify += \
   ieee128-sprintf \
   ieee128-swprintf \
   ieee128-syslog \
+  ieee128-vaprintf \
   ieee128-vasprintf \
   ieee128-vdprintf \
   ieee128-vfprintf \
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/Versions b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
index 00c0b445cda1..ae341658d11c 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/Versions
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/Versions
@@ -301,4 +301,10 @@  libc {
     __isoc23_vswscanfieee128;
     __isoc23_vwscanfieee128;
   }
+  GLIBC_2.44 {
+    __aprintfieee128;
+    __vaprintfieee128;
+    __aprintf_chkieee128;
+    __vaprintf_chkieee128;
+  }
 }
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-aprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-aprintf.c
new file mode 100644
index 000000000000..041ebc01b3f6
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-aprintf.c
@@ -0,0 +1,36 @@ 
+/* Wrapper for aprintf.  IEEE128 version.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdarg.h>
+#include <libio/libioP.h>
+
+extern char *
+___ieee128___aprintf (const char *fmt, ...)
+{
+  va_list ap;
+  char *p;
+
+  va_start (ap, fmt);
+  if (__vasprintf_internal (&p, fmt, ap, PRINTF_LDBL_USES_FLOAT128) < 0)
+    p = NULL;
+  va_end (ap);
+
+  return p;
+}
+hidden_def (___ieee128___aprintf)
+strong_alias (___ieee128___aprintf, __aprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-aprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-aprintf_chk.c
new file mode 100644
index 000000000000..0e1e395db76e
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-aprintf_chk.c
@@ -0,0 +1,40 @@ 
+/* Wrapper for __aprintf_chk.  IEEE128 version.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdarg.h>
+#include <libio/libioP.h>
+
+extern char *
+___ieee128___aprintf_chk (int flag, const char *fmt, ...)
+{
+  va_list ap;
+  char *p;
+
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  va_start (ap, fmt);
+  if (__vasprintf_internal (&p, fmt, ap, mode) < 0)
+    p = NULL;
+  va_end (ap);
+
+  return p;
+}
+hidden_def (___ieee128___aprintf_chk)
+strong_alias (___ieee128___aprintf_chk, __aprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vaprintf.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vaprintf.c
new file mode 100644
index 000000000000..6157f3060764
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vaprintf.c
@@ -0,0 +1,29 @@ 
+/* Wrapper for vaprintf.  IEEE128 version.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <libio/libioP.h>
+
+extern char *
+___ieee128_vaprintf (const char *fmt, va_list ap)
+{
+  char *p;
+  if (__vasprintf_internal (&p, fmt, ap, PRINTF_LDBL_USES_FLOAT128) < 0)
+    p = NULL;
+  return p;
+}
+strong_alias (___ieee128_vaprintf, __vaprintfieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vaprintf_chk.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vaprintf_chk.c
new file mode 100644
index 000000000000..4fd0ca8caa0a
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-vaprintf_chk.c
@@ -0,0 +1,31 @@ 
+/* Wrapper for __vaprintf_chk.  IEEE128 version.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <libio/libioP.h>
+
+extern char *
+___ieee128___vaprintf_chk (int flag, const char *fmt, va_list ap)
+{
+  char *p;
+  unsigned int mode = PRINTF_LDBL_USES_FLOAT128;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vasprintf_internal (&p, fmt, ap, mode) < 0 ? NULL : p;
+}
+strong_alias (___ieee128___vaprintf_chk, __vaprintf_chkieee128)
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.c
index 597e782e1d6c..92cdafd31978 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.c
@@ -29,12 +29,24 @@ 
 static void
 do_test_call_varg (FILE *stream, const char *format, ...)
 {
-  char *buffer = NULL;
+  char *buffer;
   char string[128];
   int res;
   va_list args;
 
+  printf ("%20s", "__vaprintf_chk: ");
+  va_start (args, format);
+  buffer = __vaprintf_chk (1, format, args);
+  va_end (args);
+  if (buffer == NULL)
+    printf ("Error using vaprintf\n");
+  else
+    printf ("%s", buffer);
+  free (buffer);
+  printf ("\n");
+
   printf ("%20s", "__vasprintf_chk: ");
+  buffer = NULL;
   va_start (args, format);
   res = __vasprintf_chk (&buffer, 1, format, args);
   va_end (args);
@@ -86,11 +98,21 @@  static void
 do_test_call_rarg (FILE *stream, const char *format, long double ld,
 		   double d)
 {
-  char *buffer = NULL;
+  char *buffer;
   char string[128];
   int res;
 
+  printf ("%20s", "__aprintf_chk: ");
+  buffer = __aprintf_chk (1, format, ld, d);
+  if (buffer == NULL)
+    printf ("Error using aprintf\n");
+  else
+    printf ("%s", buffer);
+  free (buffer);
+  printf ("\n");
+
   printf ("%20s", "__asprintf_chk: ");
+  buffer = NULL;
   res = __asprintf_chk (&buffer, 1, format, ld, d);
   if (res == -1)
     printf ("Error using vasprintf\n");
@@ -153,30 +175,35 @@  do_test (void)
 
   /* Compare against the expected output.  */
   const char *expected =
+    "     __aprintf_chk: -1.0000000000, -1.0000000000\n"
     "    __asprintf_chk: -1.0000000000, -1.0000000000\n"
     "     __dprintf_chk: -1.0000000000, -1.0000000000\n"
     "     __fprintf_chk: -1.0000000000, -1.0000000000\n"
     "      __printf_chk: -1.0000000000, -1.0000000000\n"
     "    __snprintf_chk: -1.0000000000, -1.0000000000\n"
     "     __sprintf_chk: -1.0000000000, -1.0000000000\n"
+    "    __vaprintf_chk: -1.0000000000, -1.0000000000\n"
     "   __vasprintf_chk: -1.0000000000, -1.0000000000\n"
     "    __vdprintf_chk: -1.0000000000, -1.0000000000\n"
     "    __vfprintf_chk: -1.0000000000, -1.0000000000\n"
     "     __vprintf_chk: -1.0000000000, -1.0000000000\n"
     "   __vsnprintf_chk: -1.0000000000, -1.0000000000\n"
     "    __vsprintf_chk: -1.0000000000, -1.0000000000\n"
+    "     __aprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "    __asprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "     __dprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "     __fprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "      __printf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "    __snprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "     __sprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
+    "    __vaprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "   __vasprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "    __vdprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "    __vfprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "     __vprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "   __vsnprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "    __vsprintf_chk: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
+    "    __vaprintf_chk: 3.000000, 2.000000, 1.000000\n"
     "   __vasprintf_chk: 3.000000, 2.000000, 1.000000\n"
     "    __vdprintf_chk: 3.000000, 2.000000, 1.000000\n"
     "    __vfprintf_chk: 3.000000, 2.000000, 1.000000\n"
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c
index e762e962e189..7629ee7b6bfd 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/test-printf-ldbl-compat.c
@@ -27,12 +27,24 @@ 
 static void
 do_test_call_varg (FILE *stream, const char *format, ...)
 {
-  char *buffer = NULL;
+  char *buffer;
   char string[128];
   va_list args;
   int ret;
 
+  printf ("%15s", "vaprintf: ");
+  va_start (args, format);
+  buffer = vaprintf (format, args);
+  va_end (args);
+  if (buffer == NULL)
+    printf ("Error using vaprintf\n");
+  else
+    printf ("%s", buffer);
+  free (buffer);
+  printf ("\n");
+
   printf ("%15s", "vasprintf: ");
+  buffer = NULL;
   va_start (args, format);
   ret = vasprintf (&buffer, format, args);
   va_end (args);
@@ -81,11 +93,21 @@  do_test_call_varg (FILE *stream, const char *format, ...)
 static void
 do_test_call_rarg (FILE *stream, const char *format, long double ld, double d)
 {
-  char *buffer = NULL;
+  char *buffer;
   char string[128];
   int ret;
 
+  printf ("%15s", "aprintf: ");
+  buffer = aprintf (format, ld, d);
+  if (buffer == NULL)
+    printf ("Error using aprintf\n");
+  else
+    printf ("%s", buffer);
+  free (buffer);
+  printf ("\n");
+
   printf ("%15s", "asprintf: ");
+  buffer = NULL;
   ret = asprintf (&buffer, format, ld, d);
   if (ret == -1 || buffer == NULL)
     printf ("Error using asprintf\n");
@@ -146,30 +168,35 @@  do_test (void)
 
   /* Compare against the expected output.  */
   const char *expected =
+    "      aprintf: -1.0000000000, -1.0000000000\n"
     "     asprintf: -1.0000000000, -1.0000000000\n"
     "      dprintf: -1.0000000000, -1.0000000000\n"
     "      fprintf: -1.0000000000, -1.0000000000\n"
     "       printf: -1.0000000000, -1.0000000000\n"
     "     snprintf: -1.0000000000, -1.0000000000\n"
     "      sprintf: -1.0000000000, -1.0000000000\n"
+    "     vaprintf: -1.0000000000, -1.0000000000\n"
     "    vasprintf: -1.0000000000, -1.0000000000\n"
     "     vdprintf: -1.0000000000, -1.0000000000\n"
     "     vfprintf: -1.0000000000, -1.0000000000\n"
     "      vprintf: -1.0000000000, -1.0000000000\n"
     "    vsnprintf: -1.0000000000, -1.0000000000\n"
     "     vsprintf: -1.0000000000, -1.0000000000\n"
+    "      aprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "     asprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "      dprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "      fprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "       printf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "     snprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "      sprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
+    "     vaprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "    vasprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "     vdprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "     vfprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "      vprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "    vsnprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
     "     vsprintf: -0x1.0000000000p+0, -0x1.0000000000p+0\n"
+    "     vaprintf: 3.000000, 2.000000, 1.000000\n"
     "    vasprintf: 3.000000, 2.000000, 1.000000\n"
     "     vdprintf: 3.000000, 2.000000, 1.000000\n"
     "     vfprintf: 3.000000, 2.000000, 1.000000\n"
diff --git a/sysdeps/ieee754/ldbl-opt/Makefile b/sysdeps/ieee754/ldbl-opt/Makefile
index ef7da1f83038..3effc4ef3921 100644
--- a/sysdeps/ieee754/ldbl-opt/Makefile
+++ b/sysdeps/ieee754/ldbl-opt/Makefile
@@ -15,6 +15,8 @@  libnldbl-calls = \
   acos \
   acosh \
   acospi \
+  aprintf \
+  aprintf_chk \
   asin \
   asinh \
   asinpi \
@@ -223,6 +225,8 @@  libnldbl-calls = \
   trunc \
   ufromfp \
   ufromfpx \
+  vaprintf \
+  vaprintf_chk \
   vasprintf \
   vasprintf_chk \
   vdprintf \
@@ -556,6 +560,7 @@  CFLAGS-tst-nldbl-wscanf-binary-gnu89.c += -mlong-double-64 -std=gnu89 \
 endif
 
 routines_no_fortify += \
+  nldbl-aprintf \
   nldbl-asprintf \
   nldbl-dprintf \
   nldbl-fprintf \
@@ -567,6 +572,7 @@  routines_no_fortify += \
   nldbl-sprintf \
   nldbl-swprintf \
   nldbl-syslog \
+  nldbl-vaprintf \
   nldbl-vasprintf \
   nldbl-vdprintf \
   nldbl-vfprintf \
diff --git a/sysdeps/ieee754/ldbl-opt/Versions b/sysdeps/ieee754/ldbl-opt/Versions
index 5345f1c68379..f7dec42d189e 100644
--- a/sysdeps/ieee754/ldbl-opt/Versions
+++ b/sysdeps/ieee754/ldbl-opt/Versions
@@ -98,6 +98,16 @@  libc {
     __nldbl___isoc23_vfwscanf;
     __nldbl___isoc23_vswscanf;
   }
+  GLIBC_2.44 {
+    __aprintf;
+    aprintf;
+    vaprintf;
+    __nldbl___aprintf;
+    __nldbl_aprintf;
+    __nldbl_vaprintf;
+    __nldbl___aprintf_chk;
+    __nldbl___vaprintf_chk;
+  }
 }
 libm {
   NLDBL_VERSION {
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-aprintf.c b/sysdeps/ieee754/ldbl-opt/nldbl-aprintf.c
new file mode 100644
index 000000000000..fe250c039904
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-aprintf.c
@@ -0,0 +1,17 @@ 
+#include "nldbl-compat.h"
+
+attribute_hidden
+char *
+__aprintf (const char *fmt, ...)
+{
+  va_list ap;
+  char *p;
+
+  va_start (ap, fmt);
+  p = __nldbl_vaprintf (fmt, ap);
+  va_end (ap);
+
+  return p;
+}
+extern __typeof (__aprintf) aprintf attribute_hidden;
+weak_alias (__aprintf, aprintf)
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-aprintf_chk.c b/sysdeps/ieee754/ldbl-opt/nldbl-aprintf_chk.c
new file mode 100644
index 000000000000..77b1d221bda1
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-aprintf_chk.c
@@ -0,0 +1,15 @@ 
+#include "nldbl-compat.h"
+
+attribute_hidden
+char *
+__aprintf_chk (int flag, const char *fmt, ...)
+{
+  va_list ap;
+  char *p;
+
+  va_start (ap, fmt);
+  p = __nldbl___vaprintf_chk (flag, fmt, ap);
+  va_end (ap);
+
+  return p;
+}
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index e239cd5bc5c4..f5c69f7ff4d5 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -55,6 +55,22 @@  libc_hidden_proto (__nldbl___isoc23_vfwscanf)
    we don't need to split this into one file per function for the
    sake of statically linked programs.  */
 
+int
+attribute_compat_text_section
+__nldbl___aprintf (const char *fmt, ...)
+{
+  va_list ap;
+  char *p;
+
+  va_start (ap, fmt);
+  if (__vasprintf_internal (&p, fmt, ap, PRINTF_LDBL_IS_DBL) < 0)
+    p = NULL;
+  va_end (ap);
+
+  return p;
+}
+weak_alias (__nldbl___aprintf, __nldbl_aprintf)
+
 int
 attribute_compat_text_section
 __nldbl___asprintf (char **string_ptr, const char *fmt, ...)
@@ -208,6 +224,14 @@  __nldbl_swprintf (wchar_t *s, size_t n, const wchar_t *fmt, ...)
   return ret;
 }
 
+char *
+attribute_compat_text_section weak_function
+__nldbl_vaprintf (const char *fmt, va_list ap)
+{
+  char *p;
+  return __vasprintf_internal (&p, fmt, ap, PRINTF_LDBL_IS_DBL) < 0 ? NULL : p;
+}
+
 int
 attribute_compat_text_section weak_function
 __nldbl_vasprintf (char **result_ptr, const char *fmt, va_list ap)
@@ -651,6 +675,36 @@  __nldbl___wprintf_chk (int flag, const wchar_t *fmt, ...)
   return ret;
 }
 
+char *
+attribute_compat_text_section
+__nldbl___vaprintf_chk (int flag, const char *fmt, va_list ap)
+{
+  char *p;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  return __vasprintf_internal (&p, fmt, ap, mode) < 0 ? NULL : p;
+}
+
+char *
+attribute_compat_text_section
+__nldbl___aprintf_chk (int flag, const char *fmt, ...)
+{
+  va_list ap;
+  char *p;
+  unsigned int mode = PRINTF_LDBL_IS_DBL;
+  if (flag > 0)
+    mode |= PRINTF_FORTIFY;
+
+  va_start (ap, fmt);
+  if (__vasprintf_internal (&p, fmt, ap, mode) < 0)
+    p = NULL;
+  va_end (ap);
+
+  return p;
+}
+
 int
 attribute_compat_text_section
 __nldbl___vasprintf_chk (char **ptr, int flag, const char *fmt, va_list ap)
@@ -1342,3 +1396,8 @@  compat_symbol (libc, __nldbl___fprintf_chk, __fprintf_chk, GLIBC_2_3_4);
 compat_symbol (libc, __nldbl___vprintf_chk, __vprintf_chk, GLIBC_2_3_4);
 compat_symbol (libc, __nldbl___vfprintf_chk, __vfprintf_chk, GLIBC_2_3_4);
 #endif
+#if LONG_DOUBLE_COMPAT(libc, GLIBC_2_4_4)
+compat_symbol (libc, __nldbl_aprintf, aprintf, GLIBC_2_4_4);
+compat_symbol (libc, __nldbl_vaprintf, vaprintf, GLIBC_2_4_4);
+compat_symbol (libc, __nldbl___aprintf, __aprintf, GLIBC_2_4_4);
+#endif
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
index f22177892846..9da1c2d241b4 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
@@ -46,6 +46,7 @@  NLDBL_DECL (_IO_vfscanf);
 NLDBL_DECL (vfscanf);
 NLDBL_DECL (vfwscanf);
 NLDBL_DECL (obstack_vprintf);
+NLDBL_DECL (vaprintf);
 NLDBL_DECL (vasprintf);
 NLDBL_DECL (dprintf);
 NLDBL_DECL (vdprintf);
@@ -57,6 +58,8 @@  NLDBL_DECL (vsprintf);
 NLDBL_DECL (vsscanf);
 NLDBL_DECL (vswprintf);
 NLDBL_DECL (vswscanf);
+NLDBL_DECL (__aprintf);
+NLDBL_DECL (aprintf);
 NLDBL_DECL (__asprintf);
 NLDBL_DECL (asprintf);
 NLDBL_DECL (__printf_fp);
@@ -126,6 +129,8 @@  extern int __nldbl___vsnprintf_chk (char *__restrict, size_t, int, size_t,
 extern int __nldbl___vswprintf_chk (wchar_t *__restrict, size_t, int, size_t,
 				    const wchar_t *__restrict, __gnuc_va_list)
   __THROW;
+extern char *__nldbl___vaprintf_chk (int, const char *, __gnuc_va_list)
+  __THROW __attribute_malloc__;
 extern int __nldbl___vasprintf_chk (char **, int, const char *, __gnuc_va_list)
   __THROW;
 extern int __nldbl___vdprintf_chk (int, int, const char *, __gnuc_va_list);
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-vaprintf.c b/sysdeps/ieee754/ldbl-opt/nldbl-vaprintf.c
new file mode 100644
index 000000000000..6ba7789c0063
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-vaprintf.c
@@ -0,0 +1,9 @@ 
+#include "nldbl-compat.h"
+
+attribute_hidden
+weak_function
+char *
+vaprintf (const char *fmt, va_list ap)
+{
+  return __nldbl_vaprintf (fmt, ap);
+}
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-vaprintf_chk.c b/sysdeps/ieee754/ldbl-opt/nldbl-vaprintf_chk.c
new file mode 100644
index 000000000000..72e4fca7964d
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-vaprintf_chk.c
@@ -0,0 +1,8 @@ 
+#include "nldbl-compat.h"
+
+attribute_hidden
+char *
+__vaprintf_chk (int flag, const char *fmt, va_list ap)
+{
+  return __nldbl___vaprintf_chk (flag, fmt, ap);
+}
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index 0166703bdb38..19849ec9e388 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2798,7 +2798,10 @@  GLIBC_2.43 tss_delete F
 GLIBC_2.43 tss_get F
 GLIBC_2.43 tss_set F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
 GLIBC_2.44 __mq_open_2 F
+GLIBC_2.44 __vaprintf_chk F
 GLIBC_2.44 aio_cancel F
 GLIBC_2.44 aio_cancel64 F
 GLIBC_2.44 aio_error F
@@ -2814,6 +2817,7 @@  GLIBC_2.44 aio_suspend F
 GLIBC_2.44 aio_suspend64 F
 GLIBC_2.44 aio_write F
 GLIBC_2.44 aio_write64 F
+GLIBC_2.44 aprintf F
 GLIBC_2.44 gai_cancel F
 GLIBC_2.44 gai_error F
 GLIBC_2.44 gai_suspend F
@@ -2835,6 +2839,7 @@  GLIBC_2.44 timer_delete F
 GLIBC_2.44 timer_getoverrun F
 GLIBC_2.44 timer_gettime F
 GLIBC_2.44 timer_settime F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/mach/hurd/x86_64/libc.abilist b/sysdeps/mach/hurd/x86_64/libc.abilist
index 0262a079aa83..75f4ee9ba7f1 100644
--- a/sysdeps/mach/hurd/x86_64/libc.abilist
+++ b/sysdeps/mach/hurd/x86_64/libc.abilist
@@ -2474,7 +2474,10 @@  GLIBC_2.43 tss_delete F
 GLIBC_2.43 tss_get F
 GLIBC_2.43 tss_set F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
 GLIBC_2.44 __mq_open_2 F
+GLIBC_2.44 __vaprintf_chk F
 GLIBC_2.44 aio_cancel F
 GLIBC_2.44 aio_cancel64 F
 GLIBC_2.44 aio_error F
@@ -2490,6 +2493,7 @@  GLIBC_2.44 aio_suspend F
 GLIBC_2.44 aio_suspend64 F
 GLIBC_2.44 aio_write F
 GLIBC_2.44 aio_write64 F
+GLIBC_2.44 aprintf F
 GLIBC_2.44 gai_cancel F
 GLIBC_2.44 gai_error F
 GLIBC_2.44 gai_suspend F
@@ -2511,6 +2515,7 @@  GLIBC_2.44 timer_delete F
 GLIBC_2.44 timer_getoverrun F
 GLIBC_2.44 timer_gettime F
 GLIBC_2.44 timer_settime F
+GLIBC_2.44 vaprintf F
 HURD_CTHREADS_0.3 __mutex_init F
 HURD_CTHREADS_0.3 __mutex_lock F
 HURD_CTHREADS_0.3 __mutex_trylock F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 3156688addba..1dfc4868fcf3 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2775,3 +2775,8 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 8af5b0b58188..bd8456cb535e 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -3122,6 +3122,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 35fcef2cc4c1..cc608a70e2dc 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2536,3 +2536,8 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index a6c6b951bfa7..8bb4c76c0c82 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -2828,6 +2828,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index e76015fe666a..84ce598df7ec 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -2825,6 +2825,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 1fb7cdcad5de..a431ad7d2a92 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2812,3 +2812,8 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 0710ccecf9d6..cec2ae38bf03 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2849,6 +2849,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 3afe3a88eb42..443b553c9f36 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -3032,6 +3032,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
index c2b3a66d3a1d..69119490a49d 100644
--- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
@@ -2296,3 +2296,8 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index d6855131e8b8..b57426dea5c9 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -2808,6 +2808,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 4e3fe9c42f28..d0630627ce09 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2975,6 +2975,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 29f0c5f954b5..cf9b9feee6ca 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2861,3 +2861,8 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 2ef62838f75c..5699f65a8c3f 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2858,3 +2858,8 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 031e8961acce..3dd7985954b1 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2938,6 +2938,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 8dc99d81b4bb..4acff6b710dc 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2936,6 +2936,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 054c5b6391b9..c0ae4197c6be 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2944,6 +2944,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 13f0148bc000..63c62110045c 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2846,6 +2846,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
index e7ffe07dd8d5..a3b89d620f09 100644
--- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
+++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
@@ -2286,3 +2286,8 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index dea4b20f05c1..fa44aa466688 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -3165,6 +3165,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index b45e12746368..5657ea762da0 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -3210,6 +3210,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 942cf6a02763..233c5f0bea73 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2919,6 +2919,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 65d78e50760b..c48eb3ed85d3 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2995,3 +2995,8 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index dcab30d72eec..ae677eb8da7f 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2539,3 +2539,8 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 796ef35e26e5..734e540902d4 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2739,3 +2739,8 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
diff --git a/sysdeps/unix/sysv/linux/s390/libc.abilist b/sysdeps/unix/sysv/linux/s390/libc.abilist
index 8f2350ee0b64..f6f9c998a111 100644
--- a/sysdeps/unix/sysv/linux/s390/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/libc.abilist
@@ -2956,6 +2956,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 7aa98c5aede5..100b5de75e94 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2855,6 +2855,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 6bd4f8f63a1a..f16c9e83fd79 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2852,6 +2852,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index b52cab2a3515..fa79c7b9918b 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -3186,6 +3186,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index ff99cd4f219a..becd745b1ab2 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2822,6 +2822,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 306cd627fd82..a3fefbc56330 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2771,6 +2771,11 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 8b9c448742ed..659654d97665 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2790,3 +2790,8 @@  GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.44 __aprintf F
+GLIBC_2.44 __aprintf_chk F
+GLIBC_2.44 __vaprintf_chk F
+GLIBC_2.44 aprintf F
+GLIBC_2.44 vaprintf F