[COMMIT osv master] libc: add stub strfromf128(), strtof128()

31 views
Skip to first unread message

Commit Bot

unread,
Sep 12, 2023, 4:50:28 PM9/12/23
to osv...@googlegroups.com, Nadav Har'El
From: Nadav Har'El <n...@scylladb.com>
Committer: Nadav Har'El <n...@scylladb.com>
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 <n...@scylladb.com>

---
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;
+}
Reply all
Reply to author
Forward
0 new messages