From: Nadav Har'El <[email protected]> Committer: Nadav Har'El <[email protected]> Branch: master
libc: add stub strfromf128(), strtof128() Recent versions of libstdc++ (such as the one that comes with Fedora 38) started using the functions strtof128() and strfromf128() when some C++ template uses the _Float128 type. It's not trivial to implement these functions: I created in tests/tst-f128.cc a test of what these functions need to do according to these functions on glibc - the test passes only on glibc. But luckily, we don't really need to implement them - it's enough to stub them (and they'll abort if ever used by the application). After this patch, the OSv kernel and various images (e.g., my favorite "scripts/build image=rogue; scripts/run.py") work on Fedora 38, but the default image "scripts/build" still doesn't work because of a missing symbol in Lua. Signed-off-by: Nadav Har'El <[email protected]> --- diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile @@ -1721,6 +1721,7 @@ $(out)/libc/stdlib/qsort_r.o: COMMON += -Wno-dangling-pointer libc += stdlib/strtol.o libc += stdlib/strtod.o libc += stdlib/wcstol.o +libc += stdlib/unimplemented.o libc += string/__memcpy_chk.o libc += string/explicit_bzero.o diff --git a/include/api/stdlib.h b/include/api/stdlib.h --- a/include/api/stdlib.h +++ b/include/api/stdlib.h @@ -22,12 +22,18 @@ double atof (const char *); float strtof (const char *__restrict, char **__restrict); double strtod (const char *__restrict, char **__restrict); long double strtold (const char *__restrict, char **__restrict); +__float128 strtof128 (const char *__restrict, char **__restrict); long strtol (const char *__restrict, char **__restrict, int); unsigned long strtoul (const char *__restrict, char **__restrict, int); long long strtoll (const char *__restrict, char **__restrict, int); unsigned long long strtoull (const char *__restrict, char **__restrict, int); +int strfromd (char *__restrict, size_t, const char *__restrict, double); +int strfromf (char *__restrict, size_t, const char *__restrict, float); +int strfromld (char *__restrict, size_t, const char *__restrict, long double); +int strfromf128 (char *__restrict, size_t, const char *__restrict, __float128); + int rand (void); void srand (unsigned); diff --git a/libc/stdlib/unimplemented.cc b/libc/stdlib/unimplemented.cc --- a/libc/stdlib/unimplemented.cc +++ b/libc/stdlib/unimplemented.cc @@ -0,0 +1,23 @@ +/* Based on recent addition to Musl, see + */ + +#include <stdlib.h> +#include <osv/stubbing.hh> + +// We are missing an implementation of the new C23 functions strfrom[fdl] +// and eventually we can get such an implementation from Musl (see a +// proposal in https://www.openwall.com/lists/musl/2023/05/31/28), but +// for now we'll just leave these functions missing - and applications that +// try to use them will report the missing function. +// +// But for strfromf128() we need an stub now, because recent versions of +// libstdc++ started to use them. It's fine that the implementation is just +// a stub - whatever code uses the new C++ feature should fail reporting +// the unimplemented feature. +// Later, when we implement this function, we already have a test for it +// in tests/tst-f128.cc. +UNIMPL(int strfromf128(char *, size_t, const char *, __float128)) + +// Similarly, recent versions of libstdc++ need strtof128, but don't actually +// use it until the user really uses the __float128 type. +UNIMPL(__float128 strtof128(const char *, char **)) diff --git a/modules/tests/Makefile b/modules/tests/Makefile --- a/modules/tests/Makefile +++ b/modules/tests/Makefile @@ -141,6 +141,7 @@ tests := tst-pthread.so misc-ramdisk.so tst-vblk.so tst-bsd-evh.so \ tst-netlink.so misc-zfs-io.so misc-zfs-arc.so tst-pthread-create.so \ misc-futex-perf.so misc-syscall-perf.so tst-brk.so tst-reloc.so # libstatic-thread-variable.so tst-static-thread-variable.so \ +# tst-f128.so \ ifeq ($(arch),x64) tests += tst-mmx-fpu.so diff --git a/tests/tst-f128.cc b/tests/tst-f128.cc --- a/tests/tst-f128.cc +++ b/tests/tst-f128.cc @@ -0,0 +1,59 @@ +// Tests for strfrom128() and strtof128() needed because of issue #1238. +// This test should pass on both OSv and on Linux with recent glibc with +// those two functions added. +// This test does NOT currently pass on OSv - we only have a stub +// implementation of these functions. + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +unsigned int tests_total = 0, tests_failed = 0; + +void report(const char* name, bool passed) +{ + static const char* status[] = {"FAIL", "PASS"}; + printf("%s: %s\n", status[passed], name); + tests_total += 1; + tests_failed += !passed; +} + +int main(void) +{ + printf("Starting strfromf128()/strtof128() test\n"); + // It appears that gcc truncates floating literals to 64 bit, and + // with "L" suffix, to 80 bits. To really get 128 bits, the "f128" suffix + // is needed. + __float128 pi = 3.14159265358979323846264338327950288419716939937510f128; + // Successful path for strfromf128(), with 20 digits of precision + // (precision which would not be achievable for 64-bit double):. + // Note that the 20th digit is rounded (...46 is rounded to ...5). + char buf[1024]; + int ret = strfromf128(buf, sizeof(buf), "%.20g", pi); + report("strfromf128 returns 21", ret == 21); + report("strfromf128 returns right string", !strcmp(buf, "3.1415926535897932385")); + + // Test strfromf128() with not enough place for the number, or just + // enough place for the number but not for the final null. Still returns + // the whole length. + ret = strfromf128(buf, 10, "%.20g", pi); + report("strfromf128 returns 21", ret == 21); + ret = strfromf128(buf, 21, "%.20g", pi); + report("strfromf128 returns 21", ret == 21); + + // Successful path for strtof128(), with endptr==null. + // The result of converting spi to a number should be the same as pi + // defined above - not less precision. + const char* spi = "3.14159265358979323846264338327950288419716939937510 hi"; + __float128 npi = strtof128(spi, nullptr); + report("strtof128 returns the right value", npi == pi); + + // With endptr!=null, we get the pointer to the end of the number + char *endptr; + npi = strtof128(spi, &endptr); + report("strtof128 returns the right value", npi == pi); + report("strtof128 returns the right end", (endptr - spi) == 52); + + printf("SUMMARY: %u tests / %u failures\n", tests_total, tests_failed); + return !!tests_failed; +} -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/osv-dev/000000000000ab96ff06052f97ce%40google.com.
