diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-03-16 14:13:13 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-03-16 14:13:13 -0300 |
commit | 513559cc4760392b6fa33754c516683ef49dba22 (patch) | |
tree | 7080bdf0e31f0ce14545a0e8a68daff3b36cec62 | |
parent | e4607523234f16ed9ed0436340b9315377dbfe7f (diff) | |
download | lua-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.c | 6 | ||||
-rw-r--r-- | ltests.c | 3 | ||||
-rw-r--r-- | testes/strings.lua | 18 |
3 files changed, 19 insertions, 8 deletions
@@ -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 | } |
@@ -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) | ||
183 | end | 193 | end |
184 | 194 | ||
185 | x = '"ílo"\n\\' | 195 | x = '"ílo"\n\\' |