Jelajahi Sumber

Fixed bug in 'string.format("%p")'

The string "(null)" used for non-collectable values must be printed as a
string, not as a pointer. (Bug introduced in commit e0cbaa50fa7).
Roberto Ierusalimschy 5 tahun lalu
induk
melakukan
513559cc47
3 mengubah file dengan 19 tambahan dan 8 penghapusan
  1. 4 2
      lstrlib.c
  2. 1 2
      ltests.c
  3. 14 4
      testes/strings.lua

+ 4 - 2
lstrlib.c

@@ -1271,8 +1271,10 @@ static int str_format (lua_State *L) {
         }
         case 'p': {
           const void *p = lua_topointer(L, arg);
-          if (p == NULL)
-            p = "(null)";  /* NULL not a valid parameter in ISO C 'printf' */
+          if (p == NULL) {  /* avoid calling 'printf' with argument NULL */
+            p = "(null)";  /* result */
+            form[strlen(form) - 1] = 's';  /* format it as a string */
+          }
           nb = l_sprintf(buff, maxitem, form, p);
           break;
         }

+ 1 - 2
ltests.c

@@ -131,8 +131,7 @@ static void warnf (void *ud, const char *msg, int tocont) {
         if (buff[0] != '#' && onoff)  /* unexpected warning? */
           badexit("Unexpected warning in test mode: %s\naborting...\n",
                   buff, NULL);
-        /* else */ /* FALLTHROUGH */
-      }
+      }  /* FALLTHROUGH */
       case 1: {  /* allow */
         if (onoff)
           fprintf(stderr, "Lua warning: %s\n", buff);  /* print warning */

+ 14 - 4
testes/strings.lua

@@ -158,28 +158,38 @@ do  -- tests for '%p' format
   -- not much to test, as C does not specify what '%p' does.
   -- ("The value of the pointer is converted to a sequence of printing
   -- characters, in an implementation-defined manner.")
-  local null = string.format("%p", nil)
-  assert(string.format("%p", {}) ~= null)
+  local null = "(null)"    -- nulls are formatted by Lua
   assert(string.format("%p", 4) == null)
   assert(string.format("%p", true) == null)
+  assert(string.format("%p", nil) == null)
+  assert(string.format("%p", {}) ~= null)
   assert(string.format("%p", print) ~= null)
   assert(string.format("%p", coroutine.running()) ~= null)
   assert(string.format("%p", io.stdin) ~= null)
   assert(string.format("%p", io.stdin) == string.format("%p", io.stdin))
+  assert(string.format("%p", print) == string.format("%p", print))
+  assert(string.format("%p", print) ~= string.format("%p", assert))
+
+  assert(#string.format("%90p", {}) == 90)
+  assert(#string.format("%-60p", {}) == 60)
+  assert(string.format("%10p", false) == string.rep(" ", 10 - #null) .. null)
+  assert(string.format("%-12p", 1.5) == null .. string.rep(" ", 12 - #null))
+
   do
     local t1 = {}; local t2 = {}
     assert(string.format("%p", t1) ~= string.format("%p", t2))
   end
+
   do     -- short strings are internalized
     local s1 = string.rep("a", 10)
-    local s2 = string.rep("a", 10)
+    local s2 = string.rep("aa", 5)
   assert(string.format("%p", s1) == string.format("%p", s2))
   end
+
   do     -- long strings aren't internalized
     local s1 = string.rep("a", 300); local s2 = string.rep("a", 300)
     assert(string.format("%p", s1) ~= string.format("%p", s2))
   end
-  assert(#string.format("%90p", {}) == 90)
 end
 
 x = '"ílo"\n\\'