From: Nadav Har'El <n...@scylladb.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

printf(): fix "L" and "ll" prefixes

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>
Message-Id: <20161214163437.14901-2-...@scylladb.com>

---
diff --git a/libc/stdio/vfprintf.c b/libc/stdio/vfprintf.c
--- 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,
diff --git a/tests/tst-printf.cc b/tests/tst-printf.cc
--- 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);
 }

--
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.

Reply via email to