[PATCH v1] newlib: Add optional long long output to nano printf
Juan Carlos Jimenez <[email protected]> Thu, 30 Jul 2026 18:02:54 +0200
| Newsgroups | gmane.comp.lib.newlib |
|---|---|
| Message-ID | <[email protected]> |
Nano printf consumes at most one length-modifier character. With %lld it
treats the second l as the conversion, emits "ld", and leaves the argument
unread. Later conversions then read from the wrong variadic-argument
position. A following %s can interpret integer data as a pointer and
dereference it. On Cortex-M7, this was reproduced as a fault while nano
scanned the invalid string pointer. The bug can therefore crash the
caller, rather than merely produce incorrect 64-bit output.
Although nano formatted I/O is documented as a C89 subset, this limitation
also breaks a Newlib library path. Newlib's strftime("%s") implementation
uses %lld to format epoch seconds. Under nano, that internal call reports
success after returning "ld" instead of the timestamp. The C89-only scope
therefore leaves a Newlib library feature broken, not only application code
using C99 formats.
Add the default-off --enable-newlib-nano-io-long-long option. Keep this
separate from --enable-newlib-io-long-long: configure.host enables that
option by default for many targets while nano currently ignores it, so
reusing it would alter existing nano configurations.
When enabled, recognize the ll modifier for integer output and perform the
conversion in a separate weak _printf_long_long archive member. If the
member is not linked, consume the correctly typed argument without
rendering it so later arguments remain synchronized. Add %lln support as
well.
When the option is disabled, preprocessing removes the new parser and %lln
paths, and nano-vfprintf_ll.c is not added to libc. On GCC-compatible
targets, enabled applications must also link with -u _printf_long_long to
include the conversion helper. Nano scanf remains unchanged.
Add tests for signed and unsigned conversions, bases, flags, field width,
precision, truncation, %lln, the PRI*64 macros, LLONG_MIN, strftime("%s"),
and argument synchronization without the weak helper.
Signed-off-by: Juan Carlos Jimenez <[email protected]>
---
newlib/README | 31 ++--
newlib/configure.ac | 15 ++
newlib/libc/stdio/Makefile.inc | 3 +
newlib/libc/stdio/nano-vfprintf.c | 31 ++++
newlib/libc/stdio/nano-vfprintf_i.c | 7 +
newlib/libc/stdio/nano-vfprintf_ll.c | 137 ++++++++++++++++++
newlib/libc/stdio/nano-vfprintf_local.h | 27 +++-
.../nano-printf-long-long-unlinked.c | 32 ++++
.../newlib.stdio/nano-printf-long-long.c | 109 ++++++++++++++
9 files changed, 379 insertions(+), 13 deletions(-)
create mode 100644 newlib/libc/stdio/nano-vfprintf_ll.c
create mode 100644 newlib/testsuite/newlib.stdio/nano-printf-long-long-unlinked.c
create mode 100644 newlib/testsuite/newlib.stdio/nano-printf-long-long.c
diff --git a/newlib/README b/newlib/README
index 2f9ab13d1..7feb2956b 100644
--- a/newlib/README
+++ b/newlib/README
@@ -410,16 +410,24 @@ One feature can be enabled by specifying `--enable-FEATURE=yes' or
invoke clean-up functions such as _fini or global destructors.
Disabled by default.
+`--enable-newlib-nano-io-long-long'
+ Enable long long output in nano printf-family functions.
+ Nano formatted I/O is unchanged when this option is disabled.
+ Disabled by default.
+
`--enable-newlib-nano-formatted-io'
This builds NEWLIB with a special implementation of formatted I/O
functions, designed to lower the size of application on small systems
with size constraint issues. This option does not affect wide-char
formatted I/O functions. Some notes about the feature:
- 1) The non-wide-char formatted I/O functions only support the C89
- standard. The only exception is the configuration option provides
- limited support for long double. Internally, the nano formatted I/O
- functions use double so accuracy is only guaranteed to double
- precision.
+ 1) The non-wide-char formatted I/O functions support the C89
+ standard. When `--enable-newlib-nano-io-long-long' is configured and
+ `_printf_long_long' is linked, the printf-family functions additionally
+ support the "ll" integer length modifier. The scanf-family functions
+ continue to support C89 integer conversions. The only other exception
+ is the configuration option providing limited support for long double.
+ Internally, the nano formatted I/O functions use double so accuracy is
+ only guaranteed to double precision.
2) Floating-point support is split out of the formatted I/O code into
weak functions which are not linked by default. Programs that need
floating-point I/O support must explicitly request linking of one or
@@ -430,7 +438,13 @@ One feature can be enabled by specifying `--enable-FEATURE=yes' or
by default, but if the floating-point functions are not explicitly
linked in, this may result in undefined behavior for programs that
need floating-point I/O support.
- 3) Integer-only versions of the formatted I/O functions (the iprintf/
+ 3) Long long output conversion is similarly split into the
+ `_printf_long_long' function. With GCC-compatible compilers it is a
+ weak symbol, so programs that need long long output conversions with
+ printf-family functions must request it at link time with
+ `-u _printf_long_long'. Although long long format specifiers are
+ recognized, they are not rendered unless the helper is linked.
+ 4) Integer-only versions of the formatted I/O functions (the iprintf/
iscanf family) simply alias their regular counter-parts.
The affected functions are:
@@ -456,7 +470,7 @@ One feature can be enabled by specifying `--enable-FEATURE=yes' or
_viscanf_r _vfiscanf_r _vsiscanf_r
- 4) As mentioned, the option does not affect wide-char formatted I/O.
+ 5) As mentioned, the option does not affect wide-char formatted I/O.
The following configuration options are ignored for non-wide-char
formatted I/O functions, and can be thought of as disabled.
@@ -472,8 +486,7 @@ One feature can be enabled by specifying `--enable-FEATURE=yes' or
specifiers will not be recognized or handled, and the -u option
will not work either.
- 5) As a rule, no features from outside of C89 standard will be
- considered in this implementation.
+ 6) Other features from outside of C89 standard are not supported.
Disabled by default.
diff --git a/newlib/configure.ac b/newlib/configure.ac
index 4640e69c5..d9f86db77 100644
--- a/newlib/configure.ac
+++ b/newlib/configure.ac
@@ -279,6 +279,17 @@ AC_ARG_ENABLE(newlib_nano_formatted_io,
esac],[newlib_nano_formatted_io=no])
AM_CONDITIONAL(NEWLIB_NANO_FORMATTED_IO, test x$newlib_nano_formatted_io = xyes)
+dnl Support --enable-newlib-nano-io-long-long
+AC_ARG_ENABLE(newlib-nano-io-long-long,
+[ --enable-newlib-nano-io-long-long
+ enable long long output in nano printf],
+[case "${enableval}" in
+ yes) newlib_nano_io_long_long=yes ;;
+ no) newlib_nano_io_long_long=no ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for newlib-nano-io-long-long) ;;
+ esac],[newlib_nano_io_long_long=no])
+AM_CONDITIONAL(NEWLIB_NANO_IO_LONG_LONG, test x$newlib_nano_io_long_long = xyes)
+
dnl Support --enable-retargetable-locking
dnl This option is also read in libc/configure.in. It is repeated
dnl here so that it shows up in the help text.
@@ -535,6 +546,10 @@ if test "${newlib_nano_formatted_io}" = "yes"; then
AC_DEFINE(_NANO_FORMATTED_IO, 1, [Define if small footprint nano-formatted-IO implementation used.])
fi
+if test "${newlib_nano_io_long_long}" = "yes"; then
+ AC_DEFINE(_WANT_NANO_IO_LONG_LONG, 1, [Define to enable long long output in nano printf.])
+fi
+
if test "${newlib_retargetable_locking}" = "yes"; then
AC_DEFINE(_RETARGETABLE_LOCKING, 1, [Define if using retargetable functions for default lock routines.])
fi
diff --git a/newlib/libc/stdio/Makefile.inc b/newlib/libc/stdio/Makefile.inc
index ce298e5cb..b6e6ee421 100644
--- a/newlib/libc/stdio/Makefile.inc
+++ b/newlib/libc/stdio/Makefile.inc
@@ -10,6 +10,9 @@ libc_a_SOURCES += \
%D%/nano-vfscanf.c \
%D%/nano-vfscanf_i.c \
%D%/nano-vfscanf_float.c
+if NEWLIB_NANO_IO_LONG_LONG
+libc_a_SOURCES += %D%/nano-vfprintf_ll.c
+endif
else
libc_a_SOURCES += \
%D%/fiprintf.c \
diff --git a/newlib/libc/stdio/nano-vfprintf.c b/newlib/libc/stdio/nano-vfprintf.c
index bdcc9b218..afe31af4b 100644
--- a/newlib/libc/stdio/nano-vfprintf.c
+++ b/newlib/libc/stdio/nano-vfprintf.c
@@ -611,6 +611,16 @@ _VFPRINTF_R (struct _reent *data,
prt_data.flags |= (SHORTINT << (cp - flag_chars));
fmt++;
}
+#ifndef _NO_LONGLONG
+ /* The generic parser above consumes the first 'l'. A second one
+ selects a distinct long long argument and must also be consumed. */
+ if ((prt_data.flags & LONGINT) && *fmt == 'l')
+ {
+ prt_data.flags &= ~LONGINT;
+ prt_data.flags |= QUADINT;
+ fmt++;
+ }
+#endif
/* The conversion specifiers. */
prt_data.code = *fmt++;
@@ -633,6 +643,27 @@ _VFPRINTF_R (struct _reent *data,
n = _printf_float (data, &prt_data, fp, pfunc, &ap_copy);
}
else
+#endif
+#ifndef _NO_LONGLONG
+ /* Keep long long conversion in a separate archive member so ordinary
+ integer formatting does not pull in long long division support. */
+ if ((prt_data.flags & QUADINT)
+ && memchr ("diouxX", prt_data.code, 6))
+ {
+ /* Consume the correctly typed argument if _printf_long_long is not
+ linked, as is done for an unlinked _printf_float above. */
+ if (_printf_long_long == NULL)
+ {
+ if (prt_data.code == 'd' || prt_data.code == 'i')
+ GET_ARG (N, ap_copy, long long);
+ else
+ GET_ARG (N, ap_copy, unsigned long long);
+ n = 0;
+ }
+ else
+ n = _printf_long_long (data, &prt_data, fp, pfunc, &ap_copy);
+ }
+ else
#endif
n = _printf_i (data, &prt_data, fp, pfunc, &ap_copy);
diff --git a/newlib/libc/stdio/nano-vfprintf_i.c b/newlib/libc/stdio/nano-vfprintf_i.c
index f7da95251..d2c12b098 100644
--- a/newlib/libc/stdio/nano-vfprintf_i.c
+++ b/newlib/libc/stdio/nano-vfprintf_i.c
@@ -201,6 +201,13 @@ number:
pdata->size = pdata->buf + BUF - cp;
break;
case 'n':
+#ifndef _NO_LONGLONG
+ /* %lln stores through a long long pointer; treating it as %ln would
+ use the wrong pointer type and update only part of the destination. */
+ if (pdata->flags & QUADINT)
+ *GET_ARG (N, *ap, long long *) = pdata->ret;
+ else
+#endif
if (pdata->flags & LONGINT)
*GET_ARG (N, *ap, long_ptr_t) = pdata->ret;
else if (pdata->flags & SHORTINT)
diff --git a/newlib/libc/stdio/nano-vfprintf_ll.c b/newlib/libc/stdio/nano-vfprintf_ll.c
new file mode 100644
index 000000000..949e10773
--- /dev/null
+++ b/newlib/libc/stdio/nano-vfprintf_ll.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2026 Morningstar Corporation.
+ * Copyright (c) 2012-2014 ARM Ltd
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the company may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <newlib.h>
+
+#include <_ansi.h>
+#include <reent.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include "nano-vfprintf_local.h"
+
+#ifndef _NO_LONGLONG
+/* Decode and print a long long integer conversion. */
+int
+_printf_long_long (struct _reent *data,
+ struct _prt_data_t *pdata,
+ FILE *fp,
+ int (*pfunc)(struct _reent *, FILE *, const char *,
+ size_t len),
+ va_list *ap)
+{
+ unsigned long long value;
+ int base;
+ int n;
+ int realsz;
+ char *cp = pdata->buf + BUF;
+ const char *xdigs = "0123456789ABCDEF";
+
+ switch (pdata->code)
+ {
+ case 'd':
+ case 'i':
+ {
+ long long signed_value = GET_ARG (N, *ap, long long);
+
+ if (signed_value < 0)
+ {
+ value = -(unsigned long long) signed_value;
+ pdata->l_buf[0] = '-';
+ }
+ else
+ value = signed_value;
+ }
+ base = 10;
+ break;
+ case 'u':
+ value = GET_ARG (N, *ap, unsigned long long);
+ base = 10;
+ pdata->l_buf[0] = '\0';
+ break;
+ case 'o':
+ value = GET_ARG (N, *ap, unsigned long long);
+ base = 8;
+ pdata->l_buf[0] = '\0';
+ break;
+ case 'X':
+ value = GET_ARG (N, *ap, unsigned long long);
+ base = 16;
+ pdata->l_buf[0] = '\0';
+ pdata->l_buf[2] = 'X';
+ if (pdata->flags & ALT)
+ pdata->flags |= HEXPREFIX;
+ break;
+ default:
+ value = GET_ARG (N, *ap, unsigned long long);
+ base = 16;
+ pdata->l_buf[0] = '\0';
+ pdata->l_buf[2] = 'x';
+ xdigs = "0123456789abcdef";
+ if (pdata->flags & ALT)
+ pdata->flags |= HEXPREFIX;
+ break;
+ }
+
+ if (value == 0)
+ pdata->flags &= ~HEXPREFIX;
+
+ if ((pdata->dprec = pdata->prec) >= 0)
+ pdata->flags &= ~ZEROPAD;
+
+ if (value != 0 || pdata->prec != 0)
+ {
+ do
+ {
+ *--cp = xdigs[value % base];
+ value /= base;
+ }
+ while (value);
+ }
+
+ pdata->size = pdata->buf + BUF - cp;
+ if (base == 8 && (pdata->flags & ALT) && pdata->prec <= pdata->size
+ && (pdata->size == 0 || *cp != '0'))
+ {
+ *--cp = '0';
+ pdata->size++;
+ }
+
+ n = _printf_common (data, pdata, &realsz, fp, pfunc);
+ if (n == -1)
+ goto error;
+
+ PRINT (cp, pdata->size);
+ if (pdata->flags & LADJUST)
+ PAD (pdata->width - realsz, pdata->blank);
+
+ return (pdata->width > realsz ? pdata->width : realsz);
+error:
+ return -1;
+}
+#endif
diff --git a/newlib/libc/stdio/nano-vfprintf_local.h b/newlib/libc/stdio/nano-vfprintf_local.h
index 15ddce08e..8cb2db37c 100644
--- a/newlib/libc/stdio/nano-vfprintf_local.h
+++ b/newlib/libc/stdio/nano-vfprintf_local.h
@@ -74,6 +74,9 @@
#define _NO_LONGDBL
#define _NO_LONGLONG
+#ifdef _WANT_NANO_IO_LONG_LONG
+# undef _NO_LONGLONG
+#endif
#define _PRINTF_FLOAT_TYPE double
@@ -135,10 +138,13 @@ typedef short * short_ptr_t;
#define SHORTINT 0x040 /* Short integer. */
#define LONGINT 0x080 /* Long integer. */
#define LONGDBL 0x100 /* Long double. */
-/* ifdef _NO_LONGLONG, make QUADINT equivalent to LONGINT, so
- that %lld behaves the same as %ld, not as %d, as expected if:
- sizeof (long long) = sizeof long > sizeof int. */
-#define QUADINT LONGINT
+/* The otherwise unused 0x200 bit keeps long long distinct when support is
+ configured. */
+#ifndef _NO_LONGLONG
+# define QUADINT 0x200 /* Quad integer. */
+#else
+# define QUADINT LONGINT
+#endif
#define FPT 0x400 /* Floating point number. */
/* Define as 0, to make SARG and UARG occupy fewer instructions. */
# define CHARINT 0
@@ -222,6 +228,19 @@ _printf_i (struct _reent *data, struct _prt_data_t *pdata, FILE *fp,
int (*pfunc)(struct _reent *, FILE *, const char *, size_t len),
va_list *ap);
+#ifndef _NO_LONGLONG
+/* Make _printf_long_long weak with GCC-compatible compilers so ordinary
+ integer formatting does not pull long long conversion routines into
+ size-constrained applications. */
+extern int
+_printf_long_long (struct _reent *data,
+ struct _prt_data_t *pdata,
+ FILE *fp,
+ int (*pfunc)(struct _reent *, FILE *,
+ const char *, size_t len),
+ va_list *ap) _ATTRIBUTE((__weak__));
+#endif
+
/* Make _printf_float weak symbol, so it won't be linked in if target program
does not need it. */
extern int
diff --git a/newlib/testsuite/newlib.stdio/nano-printf-long-long-unlinked.c b/newlib/testsuite/newlib.stdio/nano-printf-long-long-unlinked.c
new file mode 100644
index 000000000..904259108
--- /dev/null
+++ b/newlib/testsuite/newlib.stdio/nano-printf-long-long-unlinked.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2026 Morningstar Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * is freely granted, provided that this notice is preserved.
+ */
+
+#include <newlib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "check.h"
+
+int
+main (void)
+{
+#if defined (_NANO_FORMATTED_IO) \
+ && defined (_WANT_NANO_IO_LONG_LONG) \
+ && defined (__GNUC__)
+ static const char expected[] = "before||after";
+ char actual[sizeof ("before|-1|after")];
+ int ret;
+
+ /* The weak helper is deliberately not linked by this test. */
+ ret = snprintf (actual, sizeof (actual), "%s|%lld|%s",
+ "before", -1LL, "after");
+ CHECK (ret == (int) strlen (expected));
+ CHECK (strcmp (actual, expected) == 0);
+#endif
+
+ exit (0);
+}
diff --git a/newlib/testsuite/newlib.stdio/nano-printf-long-long.c b/newlib/testsuite/newlib.stdio/nano-printf-long-long.c
new file mode 100644
index 000000000..df491ecac
--- /dev/null
+++ b/newlib/testsuite/newlib.stdio/nano-printf-long-long.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2026 Morningstar Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * is freely granted, provided that this notice is preserved.
+ */
+
+#include <newlib.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "check.h"
+
+#if defined (_NANO_FORMATTED_IO) && defined (_WANT_NANO_IO_LONG_LONG)
+struct _reent;
+struct _prt_data_t;
+extern int
+_printf_long_long (struct _reent *, struct _prt_data_t *, FILE *,
+ int (*)(struct _reent *, FILE *, const char *, size_t),
+ va_list *);
+int (*const force_printf_long_long)
+ (struct _reent *, struct _prt_data_t *, FILE *,
+ int (*)(struct _reent *, FILE *, const char *, size_t), va_list *)
+ = _printf_long_long;
+#endif
+
+int
+main (void)
+{
+#if defined (_NANO_FORMATTED_IO) && defined (_WANT_NANO_IO_LONG_LONG)
+ static const char expected[] =
+ "-9223372036854775807|18446744073709551615|ffffffffffffffff|"
+ "FEDCBA9876543210|1777777777777777777777|0x2a|"
+ "00000000000000000042|0018446744073709551615|-123|1234567890";
+ char actual[sizeof (expected)];
+ char epoch_seconds[sizeof ("2208988800")];
+ char truncated[5];
+ long long count = -1;
+ struct tm epoch_2040 = { 0 };
+ volatile size_t truncated_size = sizeof (truncated);
+ size_t time_len;
+ int ret;
+
+ ret = snprintf (actual, sizeof (actual),
+ "%lld|%llu|%llx|%llX|%llo|%#llx|"
+ "%020llu|%.22llu|%d|%lu%lln",
+ -9223372036854775807LL, 18446744073709551615ULL,
+ 18446744073709551615ULL, 0xfedcba9876543210ULL,
+ 18446744073709551615ULL, 42ULL, 42ULL,
+ 18446744073709551615ULL, -123, 1234567890UL, &count);
+ CHECK (ret == (int) strlen (expected));
+ CHECK (count == ret);
+ CHECK (strcmp (actual, expected) == 0);
+
+ ret = snprintf (truncated, truncated_size, "%llu",
+ 18446744073709551615ULL);
+ CHECK (ret == 20);
+ CHECK (strcmp (truncated, "1844") == 0);
+
+ ret = snprintf (actual, sizeof (actual), "%#llo", 0ULL);
+ CHECK (ret == 1);
+ CHECK (strcmp (actual, "0") == 0);
+ ret = snprintf (actual, sizeof (actual), "%#.0llo", 0ULL);
+ CHECK (ret == 1);
+ CHECK (strcmp (actual, "0") == 0);
+
+ ret = snprintf (actual, sizeof (actual), "%+lld|% lld|%-5llu|%#llX",
+ 7LL, 7LL, 8ULL, 42ULL);
+ CHECK (ret == 16);
+ CHECK (strcmp (actual, "+7| 7|8 |0X2A") == 0);
+
+ ret = snprintf (actual, sizeof (actual), "%lli", -123LL);
+ CHECK (ret == 4);
+ CHECK (strcmp (actual, "-123") == 0);
+
+# if defined (INT64_MAX) && defined (UINT64_MAX) \
+ && defined (PRId64) && defined (PRIu64) && defined (PRIx64)
+ ret = snprintf (actual, sizeof (actual),
+ "%" PRId64 "|%" PRIu64 "|%" PRIx64,
+ INT64_MIN, UINT64_MAX, UINT64_MAX);
+ CHECK (ret == 58);
+ CHECK (strcmp (actual,
+ "-9223372036854775808|18446744073709551615|ffffffffffffffff")
+ == 0);
+# endif
+
+ /* Newlib's strftime %s conversion formats its result with %lld. */
+ epoch_2040.tm_year = 140;
+ epoch_2040.tm_mday = 1;
+ epoch_2040.tm_isdst = -1;
+ time_len = strftime (epoch_seconds, sizeof (epoch_seconds), "%s",
+ &epoch_2040);
+ CHECK (time_len == 10);
+ CHECK (strcmp (epoch_seconds, "2208988800") == 0);
+
+# if LLONG_MAX == 9223372036854775807LL \
+ && LLONG_MIN == (-9223372036854775807LL - 1LL)
+ ret = snprintf (actual, sizeof (actual), "%lld", LLONG_MIN);
+ CHECK (ret == 20);
+ CHECK (strcmp (actual, "-9223372036854775808") == 0);
+# endif
+#endif
+
+ exit (0);
+}
--
2.34.1