aboutsummaryrefslogtreecommitdiff
path: root/src/tools.c
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2012-10-25 10:59:23 +0300
committerBenoit Germain <bnt.germain@gmail.com>2012-10-25 10:59:23 +0300
commit518d7ba7bf9ff18fb60e9f304465164c9b068a99 (patch)
tree363f077ae9a1c76aaa26403b3b7d3dd6433b326a /src/tools.c
parent1d2a314407f5e70a5b46b3166402d79b531099c4 (diff)
downloadlanes-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.c84
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
205static char const * luaG_pushFQN(lua_State *L, int t, int last) 205static 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
228static void populate_func_lookup_table_recur( lua_State *L, int _ctx_base, int _i, int _depth) 228static 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 {