diff options
author | Benoit Germain <bnt.germain@gmail.com> | 2012-10-25 10:59:23 +0300 |
---|---|---|
committer | Benoit Germain <bnt.germain@gmail.com> | 2012-10-25 10:59:23 +0300 |
commit | 518d7ba7bf9ff18fb60e9f304465164c9b068a99 (patch) | |
tree | 363f077ae9a1c76aaa26403b3b7d3dd6433b326a /src/tools.c | |
parent | 1d2a314407f5e70a5b46b3166402d79b531099c4 (diff) | |
download | lanes-518d7ba7bf9ff18fb60e9f304465164c9b068a99.tar.gz lanes-518d7ba7bf9ff18fb60e9f304465164c9b068a99.tar.bz2 lanes-518d7ba7bf9ff18fb60e9f304465164c9b068a99.zip |
Raise an error on multiple-named functions.
Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order
on different VMs even when the tables are populated the exact same way.
When Lua is built with compatibility options (such as LUA_COMPAT_ALL),
this causes several base libraries to register functions under multiple names.
This, with the randomizer, can cause the first name of a function to be different on different VMs,
which breaks function transfer.
This means that Lua 5.2 must be built with compatibility off to be able to use Lanes.
Even under Lua 5.1, this may cause trouble (even if this would be much less frequent)
Unfortunately, this fails with string.gfind/string.gmatch when Lua 5.1 is built with LUA_COMPAT_GFIND (which is the case of LuaBinaries),
so for the time being, fail only for Lua 5.2 as the randomizer is the real show breaker here.
Diffstat (limited to 'src/tools.c')
-rw-r--r-- | src/tools.c | 84 |
1 files changed, 41 insertions, 43 deletions
diff --git a/src/tools.c b/src/tools.c index 2fc7b58..e89b340 100644 --- a/src/tools.c +++ b/src/tools.c | |||
@@ -202,19 +202,19 @@ static lua_CFunction luaG_tocfunction( lua_State *L, int _i, FuncSubType *_out) | |||
202 | 202 | ||
203 | 203 | ||
204 | // inspired from tconcat() in ltablib.c | 204 | // inspired from tconcat() in ltablib.c |
205 | static char const * luaG_pushFQN(lua_State *L, int t, int last) | 205 | static char const* luaG_pushFQN(lua_State *L, int t, int last) |
206 | { | 206 | { |
207 | int i = 1; | 207 | int i = 1; |
208 | luaL_Buffer b; | 208 | luaL_Buffer b; |
209 | STACK_CHECK( L) | 209 | STACK_CHECK( L) |
210 | luaL_buffinit(L, &b); | 210 | luaL_buffinit(L, &b); |
211 | for( ; i < last; i++) | 211 | for( ; i < last; ++ i) |
212 | { | 212 | { |
213 | lua_rawgeti( L, t, i); | 213 | lua_rawgeti( L, t, i); |
214 | luaL_addvalue( &b); | 214 | luaL_addvalue( &b); |
215 | luaL_addlstring(&b, ".", 1); | 215 | luaL_addlstring(&b, ".", 1); |
216 | } | 216 | } |
217 | if (i == last) /* add last value (if interval was not empty) */ | 217 | if( i == last) // add last value (if interval was not empty) |
218 | { | 218 | { |
219 | lua_rawgeti( L, t, i); | 219 | lua_rawgeti( L, t, i); |
220 | luaL_addvalue( &b); | 220 | luaL_addvalue( &b); |
@@ -225,7 +225,7 @@ static char const * luaG_pushFQN(lua_State *L, int t, int last) | |||
225 | } | 225 | } |
226 | 226 | ||
227 | 227 | ||
228 | static void populate_func_lookup_table_recur( lua_State *L, int _ctx_base, int _i, int _depth) | 228 | static void populate_func_lookup_table_recur( lua_State* L, int _ctx_base, int _i, int _depth) |
229 | { | 229 | { |
230 | lua_Integer visit_count; | 230 | lua_Integer visit_count; |
231 | // slot 1 in the stack contains the table that receives everything we found | 231 | // slot 1 in the stack contains the table that receives everything we found |
@@ -282,49 +282,47 @@ static void populate_func_lookup_table_recur( lua_State *L, int _ctx_base, int _ | |||
282 | lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k | 282 | lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k |
283 | lua_insert( L, -2); // ... {_i} {bfc} k k {} | 283 | lua_insert( L, -2); // ... {_i} {bfc} k k {} |
284 | lua_rawset( L, breadth_first_cache); // ... {_i} {bfc} k | 284 | lua_rawset( L, breadth_first_cache); // ... {_i} {bfc} k |
285 | STACK_MID( L, 2) | ||
286 | } | 285 | } |
287 | else if( lua_isfunction( L, -1)) // ... {_i} {bfc} k func | 286 | else if( lua_isfunction( L, -1) && (luaG_getfuncsubtype( L, -1) != FST_Bytecode)) // ... {_i} {bfc} k func |
288 | { | 287 | { |
289 | if( luaG_getfuncsubtype( L, -1) != FST_Bytecode) | 288 | char const* prevName, * newName; |
289 | // first, raise an error if the function is already known | ||
290 | lua_pushvalue( L, -1); // ... {_i} {bfc} k func func | ||
291 | lua_rawget( L, dest); // ... {_i} {bfc} k func name? | ||
292 | prevName = lua_tostring( L, -1); // NULL if we got nil (first encounter of this function) | ||
293 | // push function name in fqn stack (note that concatenation will crash if name is a not string or a number) | ||
294 | lua_pushvalue( L, -3); // ... {_i} {bfc} k func name? k | ||
295 | ++ _depth; | ||
296 | lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k func name? | ||
297 | // generate name | ||
298 | newName = luaG_pushFQN( L, fqn, _depth); // ... {_i} {bfc} k func name? "f.q.n" | ||
299 | // Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order | ||
300 | // on different VMs even when the tables are populated the exact same way. | ||
301 | // When Lua is built with compatibility options (such as LUA_COMPAT_ALL), | ||
302 | // this causes several base libraries to register functions under multiple names. | ||
303 | // This, with the randomizer, can cause the first name of a function to be different on different VMs, | ||
304 | // which breaks function transfer. | ||
305 | // This means that Lua 5.2 must be built with compatibility off to be able to use Lanes. | ||
306 | // Even under Lua 5.1, this may cause trouble (even if this would be much less frequent) | ||
307 | // Unfortunately, this fails with string.gfind/string.gmatch when Lua 5.1 is built with LUA_COMPAT_GFIND (which is the case of LuaBinaries), | ||
308 | // so for the time being, fail only for Lua 5.2 as the randomizer is the real show breaker here. | ||
309 | if( (LUA_VERSION_NUM > 501) && (prevName != NULL)) | ||
290 | { | 310 | { |
291 | //char const *fqnString; for debugging | 311 | (void) luaL_error( L, "multiple names detected (%s and %s)", prevName, newName); |
292 | bool_t not_registered; | 312 | return; |
293 | // first, skip everything if the function is already known | ||
294 | lua_pushvalue( L, -1); // ... {_i} {bfc} k func func | ||
295 | lua_rawget( L, dest); // ... {_i} {bfc} k func name? | ||
296 | not_registered = lua_isnil( L, -1); | ||
297 | lua_pop( L, 1); // ... {_i} {bfc} k func | ||
298 | if( not_registered) | ||
299 | { | ||
300 | ++ _depth; | ||
301 | // push function name in fqn stack (note that concatenation will crash if name is a not string!) | ||
302 | lua_pushvalue( L, -2); // ... {_i} {bfc} k func k | ||
303 | lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k func | ||
304 | // generate name | ||
305 | /*fqnString =*/ (void) luaG_pushFQN( L, fqn, _depth); // ... {_i} {bfc} k func "f.q.n" | ||
306 | //puts( fqnString); | ||
307 | // prepare the stack for database feed | ||
308 | lua_pushvalue( L, -1); // ... {_i} {bfc} k func "f.q.n" "f.q.n" | ||
309 | lua_pushvalue( L, -3); // ... {_i} {bfc} k func "f.q.n" "f.q.n" func | ||
310 | // t["f.q.n"] = func | ||
311 | lua_rawset( L, dest); // ... {_i} {bfc} k func "f.q.n" | ||
312 | // t[func] = "f.q.n" | ||
313 | lua_rawset( L, dest); // ... {_i} {bfc} k | ||
314 | // remove table name from fqn stack | ||
315 | lua_pushnil( L); // ... {_i} {bfc} k nil | ||
316 | lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k | ||
317 | -- _depth; | ||
318 | } | ||
319 | else | ||
320 | { | ||
321 | lua_pop( L, 1); // ... {_i} {bfc} k | ||
322 | } | ||
323 | } | ||
324 | else | ||
325 | { | ||
326 | lua_pop( L, 1); // ... {_i} {bfc} k | ||
327 | } | 313 | } |
314 | // prepare the stack for database feed | ||
315 | lua_remove( L, -2); // ... {_i} {bfc} k func "f.q.n" | ||
316 | lua_pushvalue( L, -1); // ... {_i} {bfc} k func "f.q.n" "f.q.n" | ||
317 | lua_pushvalue( L, -3); // ... {_i} {bfc} k func "f.q.n" "f.q.n" func | ||
318 | // t["f.q.n"] = func | ||
319 | lua_rawset( L, dest); // ... {_i} {bfc} k func "f.q.n" | ||
320 | // t[func] = "f.q.n" | ||
321 | lua_rawset( L, dest); // ... {_i} {bfc} k | ||
322 | // remove table name from fqn stack | ||
323 | lua_pushnil( L); // ... {_i} {bfc} k nil | ||
324 | lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k | ||
325 | -- _depth; | ||
328 | } | 326 | } |
329 | else | 327 | else |
330 | { | 328 | { |