summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2020-03-16 14:13:13 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2020-03-16 14:13:13 -0300
commit513559cc4760392b6fa33754c516683ef49dba22 (patch)
tree7080bdf0e31f0ce14545a0e8a68daff3b36cec62
parente4607523234f16ed9ed0436340b9315377dbfe7f (diff)
downloadlua-513559cc4760392b6fa33754c516683ef49dba22.tar.gz
lua-513559cc4760392b6fa33754c516683ef49dba22.tar.bz2
lua-513559cc4760392b6fa33754c516683ef49dba22.zip
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).
-rw-r--r--lstrlib.c6
-rw-r--r--ltests.c3
-rw-r--r--testes/strings.lua18
3 files changed, 19 insertions, 8 deletions
diff --git a/lstrlib.c b/lstrlib.c
index 28df2d45..2ba8bde4 100644
--- a/lstrlib.c
+++ b/lstrlib.c
@@ -1271,8 +1271,10 @@ static int str_format (lua_State *L) {
1271 } 1271 }
1272 case 'p': { 1272 case 'p': {
1273 const void *p = lua_topointer(L, arg); 1273 const void *p = lua_topointer(L, arg);
1274 if (p == NULL) 1274 if (p == NULL) { /* avoid calling 'printf' with argument NULL */
1275 p = "(null)"; /* NULL not a valid parameter in ISO C 'printf' */ 1275 p = "(null)"; /* result */
1276 form[strlen(form) - 1] = 's'; /* format it as a string */
1277 }
1276 nb = l_sprintf(buff, maxitem, form, p); 1278 nb = l_sprintf(buff, maxitem, form, p);
1277 break; 1279 break;
1278 } 1280 }
diff --git a/ltests.c b/ltests.c
index 76a6ea9b..7e6d8610 100644
--- a/ltests.c
+++ b/ltests.c
@@ -131,8 +131,7 @@ static void warnf (void *ud, const char *msg, int tocont) {
131 if (buff[0] != '#' && onoff) /* unexpected warning? */ 131 if (buff[0] != '#' && onoff) /* unexpected warning? */
132 badexit("Unexpected warning in test mode: %s\naborting...\n", 132 badexit("Unexpected warning in test mode: %s\naborting...\n",
133 buff, NULL); 133 buff, NULL);
134 /* else */ /* FALLTHROUGH */ 134 } /* FALLTHROUGH */
135 }
136 case 1: { /* allow */ 135 case 1: { /* allow */
137 if (onoff) 136 if (onoff)
138 fprintf(stderr, "Lua warning: %s\n", buff); /* print warning */ 137 fprintf(stderr, "Lua warning: %s\n", buff); /* print warning */
diff --git a/testes/strings.lua b/testes/strings.lua
index 2ce3ebc3..4a10857e 100644
--- a/testes/strings.lua
+++ b/testes/strings.lua
@@ -158,28 +158,38 @@ do -- tests for '%p' format
158 -- not much to test, as C does not specify what '%p' does. 158 -- not much to test, as C does not specify what '%p' does.
159 -- ("The value of the pointer is converted to a sequence of printing 159 -- ("The value of the pointer is converted to a sequence of printing
160 -- characters, in an implementation-defined manner.") 160 -- characters, in an implementation-defined manner.")
161 local null = string.format("%p", nil) 161 local null = "(null)" -- nulls are formatted by Lua
162 assert(string.format("%p", {}) ~= null)
163 assert(string.format("%p", 4) == null) 162 assert(string.format("%p", 4) == null)
164 assert(string.format("%p", true) == null) 163 assert(string.format("%p", true) == null)
164 assert(string.format("%p", nil) == null)
165 assert(string.format("%p", {}) ~= null)
165 assert(string.format("%p", print) ~= null) 166 assert(string.format("%p", print) ~= null)
166 assert(string.format("%p", coroutine.running()) ~= null) 167 assert(string.format("%p", coroutine.running()) ~= null)
167 assert(string.format("%p", io.stdin) ~= null) 168 assert(string.format("%p", io.stdin) ~= null)
168 assert(string.format("%p", io.stdin) == string.format("%p", io.stdin)) 169 assert(string.format("%p", io.stdin) == string.format("%p", io.stdin))
170 assert(string.format("%p", print) == string.format("%p", print))
171 assert(string.format("%p", print) ~= string.format("%p", assert))
172
173 assert(#string.format("%90p", {}) == 90)
174 assert(#string.format("%-60p", {}) == 60)
175 assert(string.format("%10p", false) == string.rep(" ", 10 - #null) .. null)
176 assert(string.format("%-12p", 1.5) == null .. string.rep(" ", 12 - #null))
177
169 do 178 do
170 local t1 = {}; local t2 = {} 179 local t1 = {}; local t2 = {}
171 assert(string.format("%p", t1) ~= string.format("%p", t2)) 180 assert(string.format("%p", t1) ~= string.format("%p", t2))
172 end 181 end
182
173 do -- short strings are internalized 183 do -- short strings are internalized
174 local s1 = string.rep("a", 10) 184 local s1 = string.rep("a", 10)
175 local s2 = string.rep("a", 10) 185 local s2 = string.rep("aa", 5)
176 assert(string.format("%p", s1) == string.format("%p", s2)) 186 assert(string.format("%p", s1) == string.format("%p", s2))
177 end 187 end
188
178 do -- long strings aren't internalized 189 do -- long strings aren't internalized
179 local s1 = string.rep("a", 300); local s2 = string.rep("a", 300) 190 local s1 = string.rep("a", 300); local s2 = string.rep("a", 300)
180 assert(string.format("%p", s1) ~= string.format("%p", s2)) 191 assert(string.format("%p", s1) ~= string.format("%p", s2))
181 end 192 end
182 assert(#string.format("%90p", {}) == 90)
183end 193end
184 194
185x = '"ílo"\n\\' 195x = '"ílo"\n\\'