r113890 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r113889‎ | r113890 | r113891 >
Date:03:50, 15 March 2012
Author:tstarling
Status:deferred
Tags:
Comment:
* Allow LuaSandbox objects to be re-entered, i.e. lua -> php -> lua.
* When there is an emergency timeout, make the LuaSandbox object "invalid", with state=NULL, instead of re-initialising it.
* Cleaned up conversion of LUA_TFUNCTION to PHP LuaSandboxFunction object, from r110080.
* Fixed code duplication from r110080 by merging the two places where LuaSandboxFunction objects are made. Moved zval allocation to the luasandbox_lua_to_zval() caller so that it can set return_value.
* In luasandbox_lua_to_zval(), fixed negative index handling in the LUA_TFUNCTION case.
* Fixed handling of the case where more than 2^31 chunks are created
* Added LuaSandboxFunction::__construct(), which just throws an error, to prevent creation of these objects with "new LuaSandboxFunction"
* Fixed a couple of missing TSRM parameters
* Added some test cases
Modified paths:
  • /trunk/php/luasandbox/luasandbox.c (modified) (history)
  • /trunk/php/luasandbox/php_luasandbox.h (modified) (history)
  • /trunk/php/luasandbox/tests/LuaSandboxFunction_construct.phpt (added) (history)
  • /trunk/php/luasandbox/tests/call.phpt (added) (history)
  • /trunk/php/luasandbox/tests/callback_exception.phpt (added) (history)
  • /trunk/php/luasandbox/tests/dump_loadBinary_call.phpt (added) (history)
  • /trunk/php/luasandbox/tests/invalid_state.phpt (added) (history)
  • /trunk/php/luasandbox/tests/loadString.phpt (added) (history)
  • /trunk/php/luasandbox/tests/reentrant.phpt (added) (history)

Diff [purge]

Index: trunk/php/luasandbox/luasandbox.c
@@ -23,6 +23,12 @@
2424 #define LUASANDBOX_LJ_64
2525 #endif
2626
 27+#define CHECK_VALID_STATE(state) \
 28+ if (!state) { \
 29+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid LuaSandbox state"); \
 30+ RETURN_FALSE; \
 31+ }
 32+
2733 static zend_object_value luasandbox_new(zend_class_entry *ce TSRMLS_DC);
2834 static lua_State * luasandbox_newstate(php_luasandbox_obj * intern);
2935 static void luasandbox_free_storage(void *object TSRMLS_DC);
@@ -42,15 +48,18 @@
4349 static void luasandbox_set_timespec(struct timespec * dest, double source);
4450 static int luasandbox_function_init(zval * this_ptr, php_luasandboxfunction_obj ** pfunc,
4551 lua_State ** pstate, php_luasandbox_obj ** psandbox TSRMLS_DC);
46 -static void luasandbox_call_helper(lua_State * L, php_luasandbox_obj * sandbox,
 52+static void luasandbox_call_helper(lua_State * L, zval * sandbox_zval,
 53+ php_luasandbox_obj * sandbox,
4754 zval *** args, zend_uint numArgs, zval * return_value TSRMLS_DC);
4855 static int luasandbox_push_zval(lua_State * L, zval * z);
4956 static void luasandbox_push_zval_userdata(lua_State * L, zval * z);
50 -static zval * luasandbox_lua_to_zval(lua_State * L, int index, HashTable * recursionGuard);
 57+static void luasandbox_lua_to_zval(zval * z, lua_State * L, int index,
 58+ zval * sandbox_zval, HashTable * recursionGuard TSRMLS_DC);
5159 static void luasandbox_lua_to_array(HashTable *ht, lua_State *L, int index,
52 - HashTable * recursionGuard);
 60+ zval * sandbox_zval, HashTable * recursionGuard TSRMLS_DC);
5361 static php_luasandbox_obj * luasandbox_get_php_obj(lua_State * L);
5462 static void luasandbox_handle_error(lua_State * L, int status);
 63+static void luasandbox_handle_emergency_timeout(php_luasandbox_obj * sandbox);
5564 static int luasandbox_push_hashtable(lua_State * L, HashTable * ht);
5665 static int luasandbox_call_php(lua_State * L);
5766 static int luasandbox_dump_writer(lua_State * L, const void * p, size_t sz, void * ud);
@@ -145,6 +154,9 @@
146155 ZEND_ARG_INFO(0, functions)
147156 ZEND_END_ARG_INFO()
148157
 158+ZEND_BEGIN_ARG_INFO(arginfo_luasandboxfunction___construct, 0)
 159+ZEND_END_ARG_INFO()
 160+
149161 ZEND_BEGIN_ARG_INFO(arginfo_luasandboxfunction_call, 0)
150162 ZEND_ARG_INFO(0, ...)
151163 ZEND_END_ARG_INFO()
@@ -171,6 +183,8 @@
172184 };
173185
174186 const zend_function_entry luasandboxfunction_methods[] = {
 187+ PHP_ME(LuaSandboxFunction, __construct, arginfo_luasandboxfunction___construct,
 188+ ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)
175189 PHP_ME(LuaSandboxFunction, call, arginfo_luasandboxfunction_call, 0)
176190 PHP_ME(LuaSandboxFunction, dump, arginfo_luasandboxfunction_dump, 0)
177191 {NULL, NULL, NULL}
@@ -298,9 +312,9 @@
299313 */
300314 static inline void luasandbox_enter_php(lua_State * L, php_luasandbox_obj * intern)
301315 {
302 - intern->in_php = 1;
 316+ intern->in_php ++;
303317 if (intern->timed_out) {
304 - intern->in_php = 0;
 318+ intern->in_php --;
305319 luaL_error(L, luasandbox_timeout_message);
306320 }
307321 }
@@ -313,7 +327,7 @@
314328 */
315329 static inline void luasandbox_leave_php(lua_State * L, php_luasandbox_obj * intern)
316330 {
317 - intern->in_php = 0;
 331+ intern->in_php --;
318332 }
319333 /* }}} */
320334
@@ -418,7 +432,7 @@
419433 // Register a pointer to the PHP object so that C functions can find it
420434 lua_pushlightuserdata(L, (void*)intern);
421435 lua_setfield(L, LUA_REGISTRYINDEX, "php_luasandbox_obj");
422 -
 436+
423437 // Create the metatable for zval destruction
424438 lua_createtable(L, 0, 1);
425439 lua_pushcfunction(L, luasandbox_free_zval_userdata);
@@ -437,16 +451,18 @@
438452 {
439453 php_luasandbox_obj * intern = (php_luasandbox_obj*)object;
440454
441 - // In 64-bit LuaJIT mode, restore the old allocator before calling
442 - // lua_close() because lua_close() actually checks that the value of the
443 - // function pointer is unchanged before destroying the underlying
444 - // allocator. If the allocator has been changed, the mmap is not freed.
 455+ if (intern->state) {
 456+ // In 64-bit LuaJIT mode, restore the old allocator before calling
 457+ // lua_close() because lua_close() actually checks that the value of the
 458+ // function pointer is unchanged before destroying the underlying
 459+ // allocator. If the allocator has been changed, the mmap is not freed.
445460 #ifdef LUASANDBOX_LJ_64
446 - lua_setallocf(intern->state, intern->old_alloc, intern->old_alloc_ud);
 461+ lua_setallocf(intern->state, intern->old_alloc, intern->old_alloc_ud);
447462 #endif
448463
449 - lua_close(intern->state);
450 - intern->state = NULL;
 464+ lua_close(intern->state);
 465+ intern->state = NULL;
 466+ }
451467 zend_object_std_dtor(&intern->std);
452468 efree(object);
453469 }
@@ -455,9 +471,6 @@
456472 /** {{{ luasandboxfunction_new
457473 *
458474 * "new" handler for the LuaSandboxFunction class.
459 - *
460 - * TODO: Make it somehow impossible to construct these objects from user code.
461 - * Only LuaSandbox methods should be constructing them.
462475 */
463476 static zend_object_value luasandboxfunction_new(zend_class_entry *ce TSRMLS_CC)
464477 {
@@ -492,14 +505,16 @@
493506 if (func->sandbox) {
494507 php_luasandbox_obj * sandbox = (php_luasandbox_obj*)
495508 zend_object_store_get_object(func->sandbox TSRMLS_CC);
496 - lua_State * L = sandbox->state;
 509+ if (sandbox && sandbox->state) {
 510+ lua_State * L = sandbox->state;
497511
498 - // Delete the chunk
499 - if (func->index) {
500 - lua_getfield(L, LUA_REGISTRYINDEX, "php_luasandbox_chunks");
501 - lua_pushnil(L);
502 - lua_rawseti(L, -2, func->index);
503 - lua_pop(L, 1);
 512+ // Delete the chunk
 513+ if (func->index) {
 514+ lua_getfield(L, LUA_REGISTRYINDEX, "php_luasandbox_chunks");
 515+ lua_pushnil(L);
 516+ lua_rawseti(L, -2, func->index);
 517+ lua_pop(L, 1);
 518+ }
504519 }
505520
506521 // Delete the parent reference
@@ -548,9 +563,9 @@
549564 {
550565 php_luasandbox_obj * obj = (php_luasandbox_obj*)ud;
551566 void * nptr;
552 - obj->in_php = 1;
 567+ obj->in_php ++;
553568 if (!luasandbox_update_memory_accounting(obj, osize, nsize)) {
554 - obj->in_php = 0;
 569+ obj->in_php --;
555570 return NULL;
556571 }
557572
@@ -564,7 +579,7 @@
565580 } else {
566581 nptr = erealloc(ptr, nsize);
567582 }
568 - obj->in_php = 0;
 583+ obj->in_php --;
569584 return nptr;
570585 }
571586 /* }}} */
@@ -668,20 +683,8 @@
669684 sandbox = (php_luasandbox_obj*)
670685 zend_object_store_get_object(this_ptr TSRMLS_CC);
671686 L = sandbox->state;
 687+ CHECK_VALID_STATE(L);
672688
673 - // The following code puts zval of the sandbox object into the register.
674 - // Why here? It should have been done at the constructor, but there was
675 - // no getThis() available at that point. Let's hope user will not run any
676 - // code requiring this register until he actually loads the code.
677 - // Why put it? Because when creating function object we need a zval,
678 - // not just php_luasandbox_obj, since we are going to reference to it from
679 - // the function object, and such referencing is possible only through zvalues.
680 - // Let us hope putting zval into Lua register won't corrupt any PHP internal
681 - // mechanisms.
682 - // FIXME: there should be a better way of doing this.
683 - lua_pushlightuserdata(L, (void*)getThis());
684 - lua_setfield(L, LUA_REGISTRYINDEX, "php_luasandbox_obj_zval");
685 -
686689 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s",
687690 &code, &codeLength, &chunkName, &chunkNameLength) == FAILURE) {
688691 RETURN_FALSE;
@@ -713,33 +716,20 @@
714717 RETURN_FALSE;
715718 }
716719
717 - // Get the chunks table
718 - lua_getfield(L, LUA_REGISTRYINDEX, "php_luasandbox_chunks");
719 -
720 - // Get the next free index
721 - index = ++(sandbox->function_index);
722 - if (index >= INT_MAX) {
723 - php_error_docref(NULL TSRMLS_CC, E_WARNING,
724 - "too many chunks loaded already");
725 - RETURN_FALSE;
726 - }
727 -
728720 // Parse the string into a function on the stack
729721 status = luaL_loadbuffer(L, code, codeLength, chunkName);
730722 if (status != 0) {
731723 luasandbox_handle_error(L, status);
732724 return;
733725 }
734 -
735 - // Store the resulting function to the chunks table
736 - lua_rawseti(L, -2, (int)index);
737726
738 - // Create a LuaSandboxFunction object to hold a reference to the function
739 - object_init_ex(return_value, luasandboxfunction_ce);
740 - func_obj = (php_luasandboxfunction_obj*)zend_object_store_get_object(return_value);
741 - func_obj->index = index;
742 - func_obj->sandbox = getThis();
743 - Z_ADDREF_P(getThis());
 727+ // Make a zval out of it, and return false on error
 728+ luasandbox_lua_to_zval(return_value, L, lua_gettop(L), this_ptr, NULL TSRMLS_CC);
 729+ if (Z_TYPE_P(return_value) == IS_NULL) {
 730+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
 731+ "too many chunks loaded already");
 732+ RETVAL_FALSE;
 733+ }
744734
745735 // Balance the stack
746736 lua_pop(L, 1);
@@ -773,6 +763,23 @@
774764 }
775765 /* }}} */
776766
 767+/** {{{ luasandbox_handle_emergency_timeout
 768+ *
 769+ * Handle the situation where the emergency_timeout flag is set. Throws an
 770+ * appropriate exception and destroys the state.
 771+ */
 772+static void luasandbox_handle_emergency_timeout(php_luasandbox_obj * sandbox)
 773+{
 774+ lua_close(sandbox->state);
 775+ sandbox->state = NULL;
 776+ sandbox->emergency_timed_out = 0;
 777+ zend_throw_exception(luasandboxemergencytimeout_ce,
 778+ "The maximum execution time was exceeded "
 779+ "and the current Lua statement failed to return, leading to "
 780+ "destruction of the Lua state", LUA_ERRRUN);
 781+}
 782+/* }}} */
 783+
777784 /** {{{ luasandbox_handle_error
778785 *
779786 * Handles the error return situation from lua_pcall() and lua_load(), where a
@@ -945,6 +952,7 @@
946953 php_luasandbox_obj * sandbox = (php_luasandbox_obj*)
947954 zend_object_store_get_object(getThis() TSRMLS_CC);
948955 lua_State * L = sandbox->state;
 956+ CHECK_VALID_STATE(L);
949957
950958 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s*",
951959 &name, &nameLength, &args, &numArgs) == FAILURE)
@@ -959,7 +967,7 @@
960968 RETVAL_FALSE;
961969 } else {
962970 // Call it
963 - luasandbox_call_helper(L, sandbox, args, numArgs, return_value TSRMLS_CC);
 971+ luasandbox_call_helper(L, getThis(), sandbox, args, numArgs, return_value TSRMLS_CC);
964972 }
965973
966974 // Delete varargs
@@ -980,6 +988,8 @@
981989 *pfunc = (php_luasandboxfunction_obj *)
982990 zend_object_store_get_object(this_ptr TSRMLS_CC);
983991 if (!*pfunc || !(*pfunc)->sandbox || !(*pfunc)->index) {
 992+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
 993+ "attempt to call uninitialized LuaSandboxFunction object" );
984994 return 0;
985995 }
986996
@@ -987,6 +997,11 @@
988998 zend_object_store_get_object((*pfunc)->sandbox TSRMLS_CC);
989999 *pstate = (*psandbox)->state;
9901000
 1001+ if (!*pstate) {
 1002+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid LuaSandbox state");
 1003+ return 0;
 1004+ }
 1005+
9911006 // Find the function
9921007 lua_getfield(*pstate, LUA_REGISTRYINDEX, "php_luasandbox_chunks");
9931008 lua_rawgeti(*pstate, -1, (*pfunc)->index);
@@ -998,6 +1013,16 @@
9991014 }
10001015 /* }}} */
10011016
 1017+/* {{{ proto private final LuaSandboxFunction::__construct()
 1018+ *
 1019+ * Construct a LuaSandboxFunction object. Do not call this directly, use
 1020+ * LuaSandbox::loadString().
 1021+ */
 1022+PHP_METHOD(LuaSandboxFunction, __construct)
 1023+{
 1024+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "LuaSandboxFunction cannot be constructed directly");
 1025+}
 1026+
10021027 /** {{{ proto array LuaSandboxFunction::call(...)
10031028 *
10041029 * Call a LuaSandboxFunction. The arguments to this function are passed through
@@ -1023,8 +1048,6 @@
10241049 php_luasandbox_obj * sandbox;
10251050
10261051 if (!luasandbox_function_init(getThis(), &func, &L, &sandbox TSRMLS_CC)) {
1027 - php_error_docref(NULL TSRMLS_CC, E_WARNING,
1028 - "attempt to call uninitialized LuaSandboxFunction object" );
10291052 RETURN_FALSE;
10301053 }
10311054
@@ -1035,7 +1058,7 @@
10361059 }
10371060
10381061 // Call the function
1039 - luasandbox_call_helper(L, sandbox, args, numArgs, return_value TSRMLS_CC);
 1062+ luasandbox_call_helper(L, func->sandbox, sandbox, args, numArgs, return_value TSRMLS_CC);
10401063
10411064 // Delete varargs
10421065 if (numArgs) {
@@ -1049,7 +1072,7 @@
10501073 * Call the function at the top of the stack and then pop it. Set return_value
10511074 * to an array containing all the results.
10521075 */
1053 -static void luasandbox_call_helper(lua_State * L, php_luasandbox_obj * sandbox,
 1076+static void luasandbox_call_helper(lua_State * L, zval * sandbox_zval, php_luasandbox_obj * sandbox,
10541077 zval *** args, zend_uint numArgs, zval * return_value TSRMLS_DC)
10551078 {
10561079 // Save the top position
@@ -1058,6 +1081,7 @@
10591082 int cpu_limited = 0;
10601083 luasandbox_timer_set t;
10611084 int i, numResults;
 1085+ zval * old_zval;
10621086
10631087 // Check to see if the value is a valid function
10641088 if (lua_type(L, -1) != LUA_TFUNCTION) {
@@ -1078,7 +1102,7 @@
10791103 }
10801104
10811105 // Initialise the CPU limit timer
1082 - if (sandbox->is_cpu_limited) {
 1106+ if (!sandbox->in_lua && sandbox->is_cpu_limited) {
10831107 cpu_limited = 1;
10841108 if (!LUASANDBOX_G(signal_handler_installed)) {
10851109 luasandbox_timer_install_handler(&LUASANDBOX_G(old_handler));
@@ -1087,26 +1111,26 @@
10881112 &sandbox->cpu_emergency_limit);
10891113 }
10901114
 1115+ // Save the current zval for later use in luasandbox_call_php. Restore it
 1116+ // after execution finishes, to support re-entrancy.
 1117+ old_zval = sandbox->current_zval;
 1118+ sandbox->current_zval = sandbox_zval;
 1119+
10911120 // Call the function
 1121+ sandbox->in_lua++;
10921122 status = lua_pcall(L, numArgs, LUA_MULTRET, 0);
 1123+ sandbox->in_lua--;
 1124+ sandbox->current_zval = old_zval;
10931125
10941126 // Stop the timer
10951127 if (cpu_limited) {
10961128 luasandbox_timer_stop(&t);
10971129 }
1098 -
1099 - // If there was an emergency timeout, destroy the state
11001130 if (sandbox->emergency_timed_out) {
1101 - lua_close(L);
1102 - L = sandbox->state = luasandbox_newstate(sandbox);
1103 - sandbox->emergency_timed_out = 0;
1104 - zend_throw_exception(luasandboxemergencytimeout_ce,
1105 - "The maximum execution time was exceeded "
1106 - "and the current Lua statement failed to return, leading to "
1107 - "destruction of the Lua state", LUA_ERRRUN);
 1131+ luasandbox_handle_emergency_timeout(sandbox);
11081132 return;
11091133 }
1110 -
 1134+
11111135 // Handle normal errors
11121136 if (status) {
11131137 luasandbox_handle_error(L, status);
@@ -1120,7 +1144,9 @@
11211145
11221146 // Fill the array with the results
11231147 for (i = 0; i < numResults; i++) {
1124 - zval * element = luasandbox_lua_to_zval(L, origTop + i, NULL);
 1148+ zval * element;
 1149+ MAKE_STD_ZVAL(element);
 1150+ luasandbox_lua_to_zval(element, L, origTop + i, sandbox_zval, NULL TSRMLS_CC);
11251151 zend_hash_next_index_insert(Z_ARRVAL_P(return_value),
11261152 (void*)&element,
11271153 sizeof(zval*), NULL);
@@ -1300,23 +1326,23 @@
13011327
13021328 /** {{{ luasandbox_lua_to_zval
13031329 *
1304 - * Convert a lua value to a zval. Allocates the zval on the heap and returns
1305 - * a pointer to it.
 1330+ * Convert a lua value to a zval.
13061331 *
13071332 * If a value is encountered that can't be converted to a zval, a LuaPlaceholder
13081333 * object is returned instead.
13091334 *
 1335+ * @param z A pointer to the destination zval
13101336 * @param L The lua state
13111337 * @param index The stack index to the input value
 1338+ * @param sandbox_zval A zval poiting to a valid LuaSandbox object which will be
 1339+ * used for the parent object of any LuaSandboxFunction objects created.
13121340 * @param recursionGuard A hashtable for keeping track of tables that have been
13131341 * processed, to allow infinite recursion to be avoided. External callers
13141342 * should set this to NULL.
13151343 */
1316 -static zval * luasandbox_lua_to_zval(lua_State * L, int index, HashTable * recursionGuard)
 1344+static void luasandbox_lua_to_zval(zval * z, lua_State * L, int index,
 1345+ zval * sandbox_zval, HashTable * recursionGuard TSRMLS_DC)
13171346 {
1318 - zval * z;
1319 - MAKE_STD_ZVAL(z);
1320 -
13211347 switch (lua_type(L, index)) {
13221348 case LUA_TNIL:
13231349 ZVAL_NULL(z);
@@ -1379,7 +1405,7 @@
13801406
13811407 // Process the array
13821408 array_init(z);
1383 - luasandbox_lua_to_array(Z_ARRVAL_P(z), L, index, recursionGuard);
 1409+ luasandbox_lua_to_array(Z_ARRVAL_P(z), L, index, sandbox_zval, recursionGuard TSRMLS_CC);
13841410
13851411 if (allocated) {
13861412 zend_hash_destroy(recursionGuard);
@@ -1390,37 +1416,35 @@
13911417 case LUA_TFUNCTION: {
13921418 int func_index;
13931419 php_luasandboxfunction_obj * func_obj;
1394 - php_luasandbox_obj * sandbox;
1395 - zval * sandbox_zval;
 1420+ php_luasandbox_obj * sandbox = (php_luasandbox_obj*)
 1421+ zend_object_store_get_object(sandbox_zval);
 1422+
 1423+ // Normalise the input index so that we can push without invalidating it.
 1424+ if (index < 0) {
 1425+ index += lua_gettop(L) + 1;
 1426+ }
13961427
1397 - // Get the sandbox object and its zval
1398 - sandbox = luasandbox_get_php_obj(L);
1399 - lua_getfield(L, LUA_REGISTRYINDEX, "php_luasandbox_obj_zval");
1400 - sandbox_zval = (zval*)lua_touserdata(L, -1);
1401 - assert(sandbox_zval != NULL);
1402 - lua_pop(L, 1);
1403 -
14041428 // Get the chunks table
14051429 lua_getfield(L, LUA_REGISTRYINDEX, "php_luasandbox_chunks");
14061430
14071431 // Get the next free index
1408 - func_index = ++(sandbox->function_index);
1409 - if (func_index >= INT_MAX) {
1410 - php_error_docref(NULL TSRMLS_CC, E_WARNING,
1411 - "too many chunks loaded already");
 1432+ if (sandbox->function_index >= INT_MAX) {
14121433 ZVAL_NULL(z);
 1434+ lua_pop(L, 1);
 1435+ break;
14131436 }
 1437+ func_index = ++(sandbox->function_index);
14141438
1415 - // Put the function together with other chunks
1416 - lua_pushvalue(L, index - 1);
1417 - lua_rawseti(L, -2, (int)func_index);
 1439+ // Store it in the chunks table
 1440+ lua_pushvalue(L, index);
 1441+ lua_rawseti(L, -2, func_index);
14181442
14191443 // Create a LuaSandboxFunction object to hold a reference to the function
14201444 object_init_ex(z, luasandboxfunction_ce);
14211445 func_obj = (php_luasandboxfunction_obj*)zend_object_store_get_object(z);
14221446 func_obj->index = func_index;
14231447 func_obj->sandbox = sandbox_zval;
1424 - Z_ADDREF_P(func_obj->sandbox);
 1448+ Z_ADDREF_P(sandbox_zval);
14251449
14261450 // Balance the stack
14271451 lua_pop(L, 1);
@@ -1433,7 +1457,6 @@
14341458 // TODO: provide derived classes for each type
14351459 object_init_ex(z, luasandboxplaceholder_ce);
14361460 }
1437 - return z;
14381461 }
14391462 /* }}} */
14401463
@@ -1442,7 +1465,7 @@
14431466 * Append the elements of the table in the specified index to the given HashTable.
14441467 */
14451468 static void luasandbox_lua_to_array(HashTable *ht, lua_State *L, int index,
1446 - HashTable * recursionGuard)
 1469+ zval * sandbox_zval, HashTable * recursionGuard TSRMLS_DC)
14471470 {
14481471 const char * str;
14491472 size_t length;
@@ -1455,7 +1478,8 @@
14561479
14571480 lua_pushnil(L);
14581481 while (lua_next(L, index) != 0) {
1459 - value = luasandbox_lua_to_zval(L, -1, recursionGuard);
 1482+ MAKE_STD_ZVAL(value);
 1483+ luasandbox_lua_to_zval(value, L, -1, sandbox_zval, recursionGuard TSRMLS_CC);
14601484
14611485 // Make a copy of the key so that we can call lua_tolstring() which is destructive
14621486 lua_pushvalue(L, -2);
@@ -1509,6 +1533,8 @@
15101534 HashTable * functions;
15111535 Bucket * p;
15121536
 1537+ CHECK_VALID_STATE(L);
 1538+
15131539 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa",
15141540 &libname, &libname_len, &zfunctions) == FAILURE)
15151541 {
@@ -1577,6 +1603,7 @@
15781604 zval **pointers;
15791605 zval ***double_pointers;
15801606 int num_results = 0;
 1607+ TSRMLS_FETCH();
15811608
15821609 // Based on zend_parse_arg_impl()
15831610 if (zend_fcall_info_init(*callback_pp, 0, &fci, &fcc, NULL,
@@ -1599,7 +1626,8 @@
16001627 double_pointers = (zval***)temp;
16011628 pointers = (zval**)(temp + top);
16021629 for (i = 0; i < top; i++ ) {
1603 - pointers[i] = luasandbox_lua_to_zval(L, i + 1, NULL);
 1630+ MAKE_STD_ZVAL(pointers[i]);
 1631+ luasandbox_lua_to_zval(pointers[i], L, i + 1, intern->current_zval, NULL TSRMLS_CC);
16041632 double_pointers[i] = &(pointers[i]);
16051633 }
16061634
@@ -1649,8 +1677,6 @@
16501678 smart_str buf = {0};
16511679
16521680 if (!luasandbox_function_init(getThis(), &func, &L, &sandbox TSRMLS_CC)) {
1653 - php_error_docref(NULL TSRMLS_CC, E_WARNING,
1654 - "attempt to call uninitialized LuaSandboxFunction object" );
16551681 RETURN_FALSE;
16561682 }
16571683
Index: trunk/php/luasandbox/tests/invalid_state.phpt
@@ -0,0 +1,27 @@
 2+--TEST--
 3+Functions called on an invalid LuaSandbox, after emergency timeout
 4+--FILE--
 5+<?php
 6+$sandbox = new LuaSandbox;
 7+$sandbox->setCPULimit(100, 0.1);
 8+$f = $sandbox->loadString('while true do end');
 9+$dump = $f->dump();
 10+try {
 11+ $f->call();
 12+} catch (LuaSandboxEmergencyTimeout $e) {
 13+ print $e->getMessage() . "\n";
 14+}
 15+$f->call();
 16+$sandbox->loadString('foo()');
 17+$sandbox->loadBinary($dump);
 18+$sandbox->callFunction('foo');
 19+--EXPECTF--
 20+The maximum execution time was exceeded and the current Lua statement failed to return, leading to destruction of the Lua state
 21+
 22+Warning: LuaSandboxFunction::call(): invalid LuaSandbox state in %s on line %d
 23+
 24+Warning: LuaSandbox::loadString(): invalid LuaSandbox state in %s on line %d
 25+
 26+Warning: LuaSandbox::loadBinary(): invalid LuaSandbox state in %s on line %d
 27+
 28+Warning: LuaSandbox::callFunction(): invalid LuaSandbox state in %s on line %d
Index: trunk/php/luasandbox/tests/loadString.phpt
@@ -0,0 +1,17 @@
 2+--TEST--
 3+loadString 1
 4+--FILE--
 5+<?php
 6+var_dump($sandbox = new LuaSandbox);
 7+var_dump($f = $sandbox->loadString('foo()'));
 8+try {
 9+ $f = $sandbox->loadString('foo');
 10+} catch( Exception $e ) {
 11+ print $e->getMessage();
 12+}
 13+--EXPECTF--
 14+object(LuaSandbox)#1 (0) {
 15+}
 16+object(LuaSandboxFunction)#2 (0) {
 17+}
 18+[string ""]:1: '=' expected near '<eof>'
Index: trunk/php/luasandbox/tests/LuaSandboxFunction_construct.phpt
@@ -0,0 +1,10 @@
 2+--TEST--
 3+LuaSandboxFunction::construct() is private
 4+--SKIPIF--
 5+<?php if (!extension_loaded("luasandbox")) print "skip"; ?>
 6+--FILE--
 7+<?php
 8+new LuaSandboxFunction;
 9+?>
 10+--EXPECTF--
 11+Fatal error: Call to private LuaSandboxFunction::__construct() from invalid context in %s on line %d
Index: trunk/php/luasandbox/tests/callback_exception.phpt
@@ -0,0 +1,18 @@
 2+--TEST--
 3+Exception in a PHP function called from Lua
 4+--FILE--
 5+<?php
 6+
 7+function throw_exception() {
 8+ throw new Exception('message');
 9+}
 10+$sandbox = new LuaSandbox;
 11+$sandbox->registerLibrary( 'test', array( 'throw_exception' => 'throw_exception' ) );
 12+$f = $sandbox->loadString('test.throw_exception()');
 13+try {
 14+ $f->call();
 15+} catch ( Exception $e ) {
 16+ print $e->getMessage();
 17+}
 18+--EXPECT--
 19+message
Index: trunk/php/luasandbox/tests/call.phpt
@@ -0,0 +1,11 @@
 2+--TEST--
 3+LuaSandboxFunction::call
 4+--FILE--
 5+<?php
 6+$sandbox = new LuaSandbox;
 7+var_dump( $sandbox->loadString( 'return 1' )->call() );
 8+--EXPECT--
 9+array(1) {
 10+ [0]=>
 11+ int(1)
 12+}
Index: trunk/php/luasandbox/tests/reentrant.phpt
@@ -0,0 +1,53 @@
 2+--TEST--
 3+Re-entering Lua during a callback to PHP
 4+--FILE--
 5+<?php
 6+$sandbox = new LuaSandbox;
 7+$chunk = $sandbox->loadString('
 8+ function factorial(n)
 9+ if n <= 1 then
 10+ return 1
 11+ else
 12+ return n * test.factorial(n - 1)
 13+ end
 14+ end
 15+
 16+ return factorial
 17+');
 18+
 19+$ret = $chunk->call();
 20+$luaFactorial = $ret[0];
 21+
 22+$sandbox->registerLibrary( 'test', array( 'factorial' => 'factorial' ) );
 23+
 24+function factorial($n) {
 25+ global $luaFactorial;
 26+ if ($n <= 1) {
 27+ return 1;
 28+ } else {
 29+ $ret = $luaFactorial->call($n - 1);
 30+ return $n * $ret[0];
 31+ }
 32+}
 33+
 34+print factorial(10) . "\n";
 35+var_dump( $luaFactorial->call(10) );
 36+
 37+try {
 38+ $luaFactorial->call(1000000000);
 39+} catch ( LuaSandboxError $e ) {
 40+ print $e->getMessage() . "\n";
 41+}
 42+try {
 43+ factorial(1000000000);
 44+} catch ( LuaSandboxError $e ) {
 45+ print $e->getMessage() . "\n";
 46+}
 47+--EXPECT--
 48+3628800
 49+array(1) {
 50+ [0]=>
 51+ int(3628800)
 52+}
 53+C stack overflow
 54+C stack overflow
Index: trunk/php/luasandbox/tests/dump_loadBinary_call.phpt
@@ -0,0 +1,21 @@
 2+--TEST--
 3+dump -> loadBinary -> call
 4+--FILE--
 5+<?php
 6+
 7+var_dump( $sandbox = new LuaSandbox );
 8+var_dump( $f = $sandbox->loadString( 'return 1' ) );
 9+$dump = $f->dump();
 10+var_dump( $restore = $sandbox->loadBinary( $dump ) );
 11+var_dump( $restore->call() );
 12+--EXPECT--
 13+object(LuaSandbox)#1 (0) {
 14+}
 15+object(LuaSandboxFunction)#2 (0) {
 16+}
 17+object(LuaSandboxFunction)#3 (0) {
 18+}
 19+array(1) {
 20+ [0]=>
 21+ int(1)
 22+}
Index: trunk/php/luasandbox/php_luasandbox.h
@@ -34,6 +34,7 @@
3535 PHP_METHOD(LuaSandbox, callFunction);
3636 PHP_METHOD(LuaSandbox, registerLibrary);
3737
 38+PHP_METHOD(LuaSandboxFunction, __construct);
3839 PHP_METHOD(LuaSandboxFunction, call);
3940 PHP_METHOD(LuaSandboxFunction, dump);
4041
@@ -57,6 +58,8 @@
5859 lua_Alloc old_alloc;
5960 void * old_alloc_ud;
6061 int in_php;
 62+ int in_lua;
 63+ zval * current_zval; /* The zval for the LuaSandbox which is currently executing Lua code */
6164 volatile int timed_out;
6265 volatile int emergency_timed_out;
6366 int is_cpu_limited;

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r110080Implement returning Lua functions from the Lua code....vasilievvv20:59, 26 January 2012

Status & tagging log