Anomie has uploaded a new change for review. https://gerrit.wikimedia.org/r/84985
Change subject: Handle __pairs when marshalling Lua-to-PHP ...................................................................... Handle __pairs when marshalling Lua-to-PHP Tables that have a custom __pairs method are not being PHPized properly, it's effectively using "rawpairs". This means that, for example, passing a table from mw.loadData to PHP doesn't work right. The fix is to use the __pairs function if it exists in the metatable. We could, in fact, just use 'pairs' itself in all cases, but it's a lot clearer to just use lua_next for the common case where there is no __pairs. Change-Id: I8cd51efc624554db6d375562aaa9421559603fae --- M data_conversion.c 1 file changed, 75 insertions(+), 27 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/php/luasandbox refs/changes/85/84985/1 diff --git a/data_conversion.c b/data_conversion.c index be7af4e..3150b1c 100644 --- a/data_conversion.c +++ b/data_conversion.c @@ -15,6 +15,8 @@ static int luasandbox_lua_to_array(HashTable *ht, lua_State *L, int index, zval * sandbox_zval, HashTable * recursionGuard TSRMLS_DC); +static int luasandbox_lua_pair_to_array(HashTable *ht, lua_State *L, + zval * sandbox_zval, HashTable * recursionGuard TSRMLS_DC); static int luasandbox_free_zval_userdata(lua_State * L); static int luasandbox_push_hashtable(lua_State * L, HashTable * ht); static int luasandbox_has_error_marker(lua_State * L, int index, void * marker); @@ -380,10 +382,6 @@ static int luasandbox_lua_to_array(HashTable *ht, lua_State *L, int index, zval * sandbox_zval, HashTable * recursionGuard TSRMLS_DC) { - const char * str; - size_t length; - zval *value; - lua_Number n; int top = lua_gettop(L); // Normalise the input index so that we can push without invalidating it. @@ -391,37 +389,87 @@ index += top + 1; } - lua_pushnil(L); - while (lua_next(L, index) != 0) { - MAKE_STD_ZVAL(value); - if (!luasandbox_lua_to_zval(value, L, -1, sandbox_zval, recursionGuard TSRMLS_CC)) { - // Conversion failed, fix stack and bail - lua_settop(L, top); - return 0; - } + // If the input table has a __pairs function, we need to use that instead + // of lua_next. + if (luaL_getmetafield(L, index, "__pairs")) { + lua_pushvalue(L, index); + lua_call(L, 1, 3); + while (1) { + // We need to copy static-data and func so we can reuse them for + // each iteration. + lua_pushvalue(L, -3); + lua_insert(L, -2); + lua_pushvalue(L, -3); + lua_insert(L, -2); - if (lua_type(L, -2) == LUA_TNUMBER) { - n = lua_tonumber(L, -2); - if (n == floor(n)) { - // Integer key - zend_hash_index_update(ht, n, (void*)&value, sizeof(zval*), NULL); - lua_settop(L, top + 1); - continue; + // Call the custom 'next' function from __pairs + lua_call(L, 2, 2); + + if (lua_isnil(L, -2)) { + // Nil key == end. Cleanup stack and exit loop. + lua_settop(L, top); + break; + } + if (!luasandbox_lua_pair_to_array(ht, L, sandbox_zval, recursionGuard TSRMLS_CC)) { + // Failed to convert value. Cleanup stack and return failure. + lua_settop(L, top); + return 0; } } - - // Make a copy of the key so that we can call lua_tolstring() which is destructive - lua_pushvalue(L, -2); - str = lua_tolstring(L, -1, &length); - zend_hash_update(ht, str, length + 1, (void*)&value, sizeof(zval*), NULL); - - // Pop temporary values off the stack - lua_settop(L, top + 1); + } else { + // No __pairs, we can use lua_next + lua_pushnil(L); + while (lua_next(L, index) != 0) { + if (!luasandbox_lua_pair_to_array(ht, L, sandbox_zval, recursionGuard TSRMLS_CC)) { + // Failed to convert value. Cleanup stack and return failure. + lua_settop(L, top); + return 0; + } + } } return 1; } /* }}} */ +/** {{{ luasandbox_lua_pair_to_array + * + * Take the lua key-value pair at the top of the Lua stack and add it to the given HashTable. + * On success the value is popped, but the key remains on the stack. + */ +static int luasandbox_lua_pair_to_array(HashTable *ht, lua_State *L, + zval * sandbox_zval, HashTable * recursionGuard TSRMLS_DC) +{ + const char * str; + size_t length; + zval *value; + lua_Number n; + + // Convert value, then remove it + MAKE_STD_ZVAL(value); + if (!luasandbox_lua_to_zval(value, L, -1, sandbox_zval, recursionGuard TSRMLS_CC)) { + return 0; + } + lua_pop(L, 1); + + // Convert key, but leave it there + if (lua_type(L, -1) == LUA_TNUMBER) { + n = lua_tonumber(L, -1); + if (n == floor(n)) { + // Integer key + zend_hash_index_update(ht, n, (void*)&value, sizeof(zval*), NULL); + return 1; + } + } + + // Make a copy of the key so that we can call lua_tolstring() which is destructive + lua_pushvalue(L, -1); + str = lua_tolstring(L, -1, &length); + zend_hash_update(ht, str, length + 1, (void*)&value, sizeof(zval*), NULL); + lua_pop(L, 1); + return 1; +} +/* }}} */ + /** {{{ luasandbox_wrap_fatal * * Pop a value off the top of the stack, and push a fatal error wrapper -- To view, visit https://gerrit.wikimedia.org/r/84985 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I8cd51efc624554db6d375562aaa9421559603fae Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/php/luasandbox Gerrit-Branch: master Gerrit-Owner: Anomie <bjor...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits