Musl, like Posix, allows the "L" prefix to be used only on long doubles, and "ll" prefix on long long int. However, glibc actually allows both on both types.
So this patch changes both prefixes to allow both types, to work like Linux. It also adds a test that this works. We saw this problem in an actual application, which used the "%Lx" format, that worked on Linux but not on OSv (on OSv, the entire printf did not happen because of the format parse error). Fixes #818. Signed-off-by: Nadav Har'El <n...@scylladb.com> --- tests/tst-printf.cc | 34 ++++++++++++++++++++++++++++++++++ libc/stdio/vfprintf.c | 9 +++++++++ 2 files changed, 43 insertions(+) diff --git a/tests/tst-printf.cc b/tests/tst-printf.cc index 959dbc4..04713f0 100644 --- a/tests/tst-printf.cc +++ b/tests/tst-printf.cc @@ -15,6 +15,7 @@ #include <stdio.h> #include <string.h> +#include <stdarg.h> static int tests = 0, fails = 0; @@ -30,6 +31,27 @@ static void report(bool ok, std::string msg) // some builtin. So we need to use this variable const char *format = "%s"; + +std::string print(const char* fmt, ...){ + int size = 512; + char* buffer = 0; + buffer = new char[size]; + va_list vl; + va_start(vl, fmt); + int nsize = vsnprintf(buffer, size, fmt, vl); + if(size<=nsize){ //fail delete buffer and try again + delete[] buffer; + buffer = 0; + buffer = new char[nsize+1]; //+1 for /0 + nsize = vsnprintf(buffer, size, fmt, vl); + } + std::string ret(buffer); + va_end(vl); + delete[] buffer; + return ret; +} + + int main(int ac, char** av) { // Test that when snprintf is given a >32-bit length, including -1, @@ -44,5 +66,17 @@ int main(int ac, char** av) report(snprintf(dest2, 1ULL<<40, format, source) == 5, "snprintf with n=2^40"); report(strcmp(source, dest2) == 0, "strcmp that result"); + // Posix states that the "L" prefix is for long double, and "ll" is + // for long long int, but in Linux glibc these are actually synonyms, + // and either can be used + // Test that the L format prefix, for "long double", works + long double d = 123.456; + long long int i = 123456; + report(print("%Lf", d) == "123.456000", "Lf"); + report(print("%llf", d) == "123.456000", "llf"); + report(print("%Ld", i) == "123456", "Ld"); + report(print("%lld", i) == "123456", "lld"); + std::cout << "SUMMARY: " << tests << " tests, " << fails << " failures\n"; + return (fails != 0); } diff --git a/libc/stdio/vfprintf.c b/libc/stdio/vfprintf.c index 1e7e6a4..aac790c 100644 --- a/libc/stdio/vfprintf.c +++ b/libc/stdio/vfprintf.c @@ -91,6 +91,10 @@ static const unsigned char states[]['z'-'A'+1] = { S('o') = ULLONG, S('u') = ULLONG, S('x') = ULLONG, S('X') = ULLONG, S('n') = PTR, + // unlike Posix, glibc also allows ll prefix for long double, + // same as L prefix: + S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL, + S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL, }, { /* 3: h-prefixed */ S('d') = SHORT, S('i') = SHORT, S('o') = USHORT, S('u') = USHORT, @@ -106,6 +110,11 @@ static const unsigned char states[]['z'-'A'+1] = { S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL, S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL, S('n') = PTR, + // unlike Posix, glibc also allows L prefix for long long int, + // same as ll prefix: + S('d') = LLONG, S('i') = LLONG, + S('o') = ULLONG, S('u') = ULLONG, + S('x') = ULLONG, S('X') = ULLONG, }, { /* 6: z- or t-prefixed (assumed to be same size) */ S('d') = PDIFF, S('i') = PDIFF, S('o') = SIZET, S('u') = SIZET, -- 2.9.3 -- 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 osv-dev+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.