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\\' |
