Two units tests fails on FreeBSD 14.2-RELEASE (amd64) with version 1.7.2
Project version: 1.7.2
C compiler for the host machine: cc (clang 18.1.6 "FreeBSD clang version 18.1.6 (https://github.com/llvm/llvm-project.git llvmorg-18.1.6-0-g1118c2e05e67)")
C linker for the host machine: cc ld.lld 18.1.6
>>> MSAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1 MESON_TEST_ITERATION=1 UBSAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1 NO_YAML=0 MALLOC_PERTURB_=186 ASAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1 NO_PYTHON=1 LD_LIBRARY_PATH=/usr/ports/sysutils/dtc/work/dtc-1.7.2/_build/libfdt /usr/ports/sysutils/dtc/work/dtc-1.7.2/tests/run_tests.sh -t fdtget
fdtget-runtest.sh "MyBoardName\0MyBoardFamilyName\0" -tr label01.dts.fdtget.test.dtb / compatible: FAIL Results differ from expected
>>> MSAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1 MESON_TEST_ITERATION=1 UBSAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1 MALLOC_PERTURB_=34 NO_YAML=0 ASAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1 NO_PYTHON=1 LD_LIBRARY_PATH=/usr/ports/sysutils/dtc/work/dtc-1.7.2/_build/libfdt /usr/ports/sysutils/dtc/work/dtc-1.7.2/tests/run_tests.sh -t fdtput
fdtput-runtest.sh 2 3 12 label01.dts.fdtput.test.dtb /randomnode tricky1 -tbi 02 003 12: FAIL Results differ from expected
Using meson build without python support enabled
Let me know if you need more information
That's unfortunate. However, I don't have easy access to a FreeBSD machine to debug with.
Is there anything I can provide in terms of logs that may help etc?
Is there anything I can provide in terms of logs that may help etc?
Not really, sorry. If you had good instructions for setting up a FreeBSD VM running on qemu on Linux, that would help.
Ok, I figured out to get a FreeBSD VM running and I've diagnosed the problem.
The problem is that FreeBSD's printf(1) doesn't handle \0 escapes in parameters formatted with %b - it effectively terminates that argument. It's debatable whether that's a bug in printf - it does seem to be an inconsistency, because it will handle \0 in the main format string fine.
Still looking at how to fix / workaround this in the test.
Well, that explains the first failure. The second one is different - it happens because on FreeBSD sscanf("003", "%i", &val) gives 0 rather than 3. In figuring out how to work around that, though, I discovered that a bunch of code in fdtput is pretty awful. Still looking at how to fix it.
Ok, I figured out to get a FreeBSD VM running and I've diagnosed the problem.
The problem is that FreeBSD's printf(1) doesn't handle
\0escapes in parameters formatted with%b- it effectively terminates that argument. It's debatable whether that's a bug in printf - it does seem to be an inconsistency, because it will handle\0in the main format string fine.Still looking at how to fix / workaround this in the test.
No need to debate, FreeBSD's printf(1) manual page acknowledges this bug in the BUGS section. -> https://man.freebsd.org/cgi/man.cgi?query=printf&apropos=0&sektion=1&manpath=FreeBSD+14.2-RELEASE&arch=default&format=html#end
Workarounds:
- install GNU coreutils and use the
gprintfprogram, which works across\0 - install bash and use its
printfbuilt-in, which works across\0
For FreeBSD, the former could use BINARY_ALIAS in ports unless the tests override/hardcode PATH.
Well, that explains the first failure. The second one is different - it happens because on FreeBSD
sscanf("003", "%i", &val)gives 0 rather than 3. In figuring out how to work around that, though, I discovered that a bunch of code in fdtput is pretty awful. Still looking at how to fix it.
Seems FreeBSD's sscanf is broken, but strtol seems OK.
// this is try.c
// compile and run: cc -o try try.c && ./try
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
int main() {
int val;
int len;
int retval;
retval = sscanf("003", "%i%n", &val, &len);
printf("sscanf, retval = %d, val = %d, len = %d\n", retval, val, len);
long longval;
char *startptr = "003";
char *endptr;
errno = 0;
longval = strtol(startptr, &endptr, 0);
printf("strtol, longval = %ld, len = %d, errno = %d\n", longval, (int)(endptr - startptr), errno);
return 0;
}
yields
sscanf, retval = 1, val = 0, len = 2
strtol, longval = 3, len = 3, errno = 0
Meaning sscanf chickened out in the middle of the "003" sequence, len is 2, but it claims 1 successful conversion in the return value. (0 is the octal specifier, 03 is an octal sequence that strtol can parse). POSIX suggests that sscanf's %i is supposed to scan "AS IF" strtol with base 0 were used.
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=288440
Ok, I figured out to get a FreeBSD VM running and I've diagnosed the problem. The problem is that FreeBSD's printf(1) doesn't handle
\0escapes in parameters formatted with%b- it effectively terminates that argument. It's debatable whether that's a bug in printf - it does seem to be an inconsistency, because it will handle\0in the main format string fine. Still looking at how to fix / workaround this in the test.No need to debate, FreeBSD's printf(1) manual page acknowledges this bug in the BUGS section. -> https://man.freebsd.org/cgi/man.cgi?query=printf&apropos=0&sektion=1&manpath=FreeBSD+14.2-RELEASE&arch=default&format=html#end
Ah, good to know.
Workarounds:
* install GNU coreutils and use the `gprintf` program, which works across `\0` * install bash and use its `printf` **built-in**, which works across `\0`For FreeBSD, the former could use BINARY_ALIAS in ports unless the tests override/hardcode PATH.
Turns out to be easier than that. BSD's printf(1) does handle \0 in the main format string. So we can just change the test script to use that rather than %b. Kind of not best practice, but not really a problem for our situation. I have a queued fix for this (see here).
Well, that explains the first failure. The second one is different - it happens because on FreeBSD
sscanf("003", "%i", &val)gives 0 rather than 3. In figuring out how to work around that, though, I discovered that a bunch of code in fdtput is pretty awful. Still looking at how to fix it.Seems FreeBSD's sscanf is broken, but strtol seems OK.
Yes, I noticed that too. My plan is to switch to strtol() - I always find scanf() confusing anyway. I was sidetracked by spotting other nonsense in the surrounding code.
// this is try.c // compile and run: cc -o try try.c && ./try #include <stdlib.h> #include <stdio.h> #include <errno.h>
int main() { int val; int len; int retval; retval = sscanf("003", "%i%n", &val, &len); printf("sscanf, retval = %d, val = %d, len = %d\n", retval, val, len); long longval; char *startptr = "003"; char *endptr; errno = 0; longval = strtol(startptr, &endptr, 0); printf("strtol, longval = %ld, len = %d, errno = %d\n", longval, (int)(endptr - startptr), errno); return 0; }
yields
sscanf, retval = 1, val = 0, len = 2 strtol, longval = 3, len = 3, errno = 0Meaning sscanf chickened out in the middle of the "003" sequence, len is 2, but it claims 1 successful conversion in the return value. (0 is the octal specifier, 03 is an octal sequence that strtol can parse). POSIX suggests that sscanf's %i is supposed to scan "AS IF" strtol with base 0 were used.
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=288440
Ah, thanks. I signed up to get an account on the FreeBSD bugzilla, but you've saved me the trouble of filing this.
Ok, punted on the other cleanups for the time being, but I believe I've fixed the bug on BSD. Can you please retry with latest git main.
Checks out fine on 14.3-RELEASE (amd64) on my end, thanks!
@diizzyy good to hear. Fwiw, I just got FreeBSD tests working again on Cirrus CI, so I hope to avoid this sort of regression in future.