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 <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits