control: tag -1 + patch
Hi,
On 2026-02-23 13:42, Emanuele Rocca wrote:
> Source: busybox
> Version: 1:1.37.0-10
> Severity: important
> Tags: ftbfs upstream
> Justification: fails to build from source
> User: [email protected]
> Usertags: glibc-2.43
>
> Hi,
>
> busybox fails to build from source on arm64 when using glibc 2.43,
> currently in experimental.
>
> The issue is triggered by glibc 2.43 on arm64 enabling 2MB THP by
> default:
> https://sourceware.org/git/?p=glibc.git;a=commit;h=321e1fc73f53081d92ba357cdd48c56b79292020
>
> The problem is however not architecture-specific. For example it can be
> reproduced with glibc 2.42 on amd64 by building the package with the
> GLIBC_TUNABLES environment variable set to glibc.malloc.hugetlb=2.
>
> Successful build with glibc 2.42, currently in sid:
> https://people.debian.org/~ema/glibc-2.43-rebuilds/output-2/busybox_arm64.build
>
> Logs of a failed build with glibc 2.43 are here:
> https://people.debian.org/~ema/glibc-2.43-rebuilds/output-1/busybox_arm64.build
>
> Salient part:
>
> FAIL: printf understands %s '"x' "'y" "'zTAIL"
> [...]
> FAIL: printf handles positive numbers for %f
> [...]
> PASS: xxd -p -r ignores the nibble with 2nd char bad
> 2 failure(s) detected; running with -v (verbose) will give more info
> make[2]: *** [debian/rules:135: b/deb/.stamp-test] Error 1
> make[2]: Leaving directory '/build/reproducible-path/busybox-1.37.0'
> make[1]: *** [debian/rules:60: install] Error 2
> make[1]: Leaving directory '/build/reproducible-path/busybox-1.37.0'
> make: *** [debian/rules:60: binary] Error 2
> dpkg-buildpackage: error: debian/rules binary subprocess failed with exit
> status 2
The problem happens because of the common misconception that errno is
only set in case of errors. It is therefore used as an accumulator in
some parts of the printf busybox applet. Now that malloc() sets errno to
ENOENT in some cases on arm64, even with successfully allocation, this
causes the above issues.
Please find attached a naive implementation of a fix, basically saving
and restoring errno around printf calls. There is probably a better fix
possible, but it implies refactoring a significant part of the file to
actually return errors differently.
Regards
Aurelien
--
Aurelien Jarno GPG: 4096R/1DDD8C9B
[email protected] http://aurel32.net
diff --git a/coreutils/printf.c b/coreutils/printf.c
index 3cd48cfcc..a5d995ab5 100644
--- a/coreutils/printf.c
+++ b/coreutils/printf.c
@@ -191,6 +191,7 @@ static void print_direc(char *format, unsigned fmt_length,
double dv;
char saved;
char *have_prec, *have_width;
+ int saved_errno, ret;
saved = format[fmt_length];
format[fmt_length] = '\0';
@@ -205,22 +206,32 @@ static void print_direc(char *format, unsigned fmt_length,
switch (format[fmt_length - 1]) {
case 'c':
- printf(format, *argument);
+ saved_errno = errno;
+ ret = printf(format, *argument);
+ /* Restore errno if there was no error */
+ if (ret >= 0) {
+ errno = saved_errno;
+ }
break;
case 'd':
case 'i':
llv = my_xstrtoll(skip_whitespace(argument));
print_long:
+ saved_errno = errno;
if (!have_width) {
if (!have_prec)
- printf(format, llv);
+ ret = printf(format, llv);
else
- printf(format, precision, llv);
+ ret = printf(format, precision, llv);
} else {
if (!have_prec)
- printf(format, field_width, llv);
+ ret = printf(format, field_width, llv);
else
- printf(format, field_width, precision, llv);
+ ret = printf(format, field_width, precision, llv);
+ }
+ /* Restore errno if there was no error */
+ if (ret >= 0) {
+ errno = saved_errno;
}
break;
case 'o':
@@ -238,16 +249,21 @@ static void print_direc(char *format, unsigned fmt_length,
} else {
/* Hope compiler will optimize it out by moving call
* instruction after the ifs... */
+ saved_errno = errno;
if (!have_width) {
if (!have_prec)
- printf(format, argument, /*unused:*/ argument, argument);
+ ret = printf(format, argument, /*unused:*/ argument, argument);
else
- printf(format, precision, argument, /*unused:*/ argument);
+ ret = printf(format, precision, argument, /*unused:*/ argument);
} else {
if (!have_prec)
- printf(format, field_width, argument, /*unused:*/ argument);
+ ret = printf(format, field_width, argument, /*unused:*/ argument);
else
- printf(format, field_width, precision, argument);
+ ret = printf(format, field_width, precision, argument);
+ }
+ /* Restore errno if there was no error */
+ if (ret >= 0) {
+ errno = saved_errno;
}
break;
}
@@ -257,16 +273,21 @@ static void print_direc(char *format, unsigned fmt_length,
case 'g':
case 'G':
dv = my_xstrtod(argument);
+ saved_errno = errno;
if (!have_width) {
if (!have_prec)
- printf(format, dv);
+ ret = printf(format, dv);
else
- printf(format, precision, dv);
+ ret = printf(format, precision, dv);
} else {
if (!have_prec)
- printf(format, field_width, dv);
+ ret = printf(format, field_width, dv);
else
- printf(format, field_width, precision, dv);
+ ret = printf(format, field_width, precision, dv);
+ }
+ /* Restore errno if there was no error */
+ if (ret >= 0) {
+ errno = saved_errno;
}
break;
} /* switch */