Anomie has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/298312

Change subject: Update for PHP 7
......................................................................

Update for PHP 7

They made several changes that result in a lot of conditional
compilation:
* zval** is now zval*, and many (but not all) zval* are now plain zval.
  zvals are often allocated on the stack now, so even when we do get a
  zval* it might not last beyond the current function call.
* Objects are stored directly in zvals now, no more object store. This
  also means we don't free the object in the 'free_obj' callback
  anymore.
* The HashTable API changed significantly, it stores zvals instead of
  arbitrary data, doesn't include the trailing \0 in keys anymore, and
  has a completely new way of iterating.
* A new "zend_string" struct to replace char* + length. Although in most
  cases we can get away with "zend_hash_str_*" methods to avoid having
  to construct zend_strings.
* Various other gratuitous method signature changes.

Bug: T139558
Change-Id: I34ba41ace1f8ff14371a116e0d2880f4e7cf58c5
---
M data_conversion.c
M library.c
M luasandbox.c
M luasandbox_types.h
A tests/datatypes.phpt
M timer.c
6 files changed, 584 insertions(+), 181 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/php/luasandbox 
refs/changes/12/298312/1

diff --git a/data_conversion.c b/data_conversion.c
index 0c0ccad..46a78ea 100644
--- a/data_conversion.c
+++ b/data_conversion.c
@@ -19,6 +19,7 @@
 using std::isfinite;
 #endif
 
+static void luasandbox_throw_runtimeerror(lua_State * L, zval * sandbox_zval, 
const char *message TSRMLS_DC);
 static inline int luasandbox_is_recursive(HashTable * ht);
 static inline void luasandbox_protect_recursion(HashTable * ht);
 static inline void luasandbox_unprotect_recursion(HashTable * ht);
@@ -67,6 +68,9 @@
 int luasandbox_push_zval(lua_State * L, zval * z)
 {
        switch (Z_TYPE_P(z)) {
+#ifdef IS_UNDEF
+               case IS_UNDEF: // Close enough to IS_NULL
+#endif
                case IS_NULL:
                        lua_pushnil(L);
                        break;
@@ -76,9 +80,19 @@
                case IS_DOUBLE:
                        lua_pushnumber(L, Z_DVAL_P(z));
                        break;
+#ifdef IS_BOOL
                case IS_BOOL:
                        lua_pushboolean(L, Z_BVAL_P(z));
                        break;
+#endif
+#ifdef IS_TRUE
+               case IS_TRUE:
+                       lua_pushboolean(L, 1);
+                       break;
+               case IS_FALSE:
+                       lua_pushboolean(L, 0);
+                       break;
+#endif
                case IS_ARRAY:
                        if (!luasandbox_push_hashtable(L, Z_ARRVAL_P(z))) {
                                return 0;
@@ -92,7 +106,7 @@
                        if (instanceof_function(objce, luasandboxfunction_ce 
TSRMLS_CC)) {
                                php_luasandboxfunction_obj * func_obj;
 
-                               func_obj = (php_luasandboxfunction_obj 
*)zend_object_store_get_object(z TSRMLS_CC);
+                               func_obj = GET_LUASANDBOXFUNCTION_OBJ(z);
 
                                lua_getfield(L, LUA_REGISTRYINDEX, 
"php_luasandbox_chunks");
                                lua_rawgeti(L, -1, func_obj->index);
@@ -108,6 +122,11 @@
                case IS_STRING:
                        lua_pushlstring(L, Z_STRVAL_P(z), Z_STRLEN_P(z));
                        break;
+#ifdef IS_REFERENCE
+               case IS_REFERENCE:
+                       return luasandbox_push_zval(L, Z_REFVAL_P(z));
+#endif
+
                case IS_RESOURCE:
                default:
                        return 0;
@@ -122,16 +141,27 @@
  */
 static int luasandbox_free_zval_userdata(lua_State * L)
 {
-       zval ** zpp = (zval**)lua_touserdata(L, 1);
+#if PHP_VERSION_ID < 70000
+       zval ** ud = (zval**)lua_touserdata(L, 1);
+#else
+       zval * ud = (zval*)lua_touserdata(L, 1);
+#endif
        php_luasandbox_obj * intern = luasandbox_get_php_obj(L);
 
        // Don't abort if the request has timed out, we need to be able to 
clean up
        luasandbox_enter_php_ignore_timeouts(L, intern);
 
-       if (zpp && *zpp) {
-               zval_ptr_dtor(zpp);
+#if PHP_VERSION_ID < 70000
+       if (ud && *ud) {
+               zval_ptr_dtor(ud);
+               *ud = NULL;
        }
-       *zpp = NULL;
+#else
+       if (ud && !Z_ISUNDEF_P(ud)) {
+               zval_ptr_dtor(ud);
+               ZVAL_UNDEF(ud);
+       }
+#endif
        luasandbox_leave_php(L, intern);
        return 0;
 }
@@ -145,10 +175,14 @@
  */
 void luasandbox_push_zval_userdata(lua_State * L, zval * z)
 {
-       zval ** ud;
-       ud = (zval**)lua_newuserdata(L, sizeof(zval*));
+#if PHP_VERSION_ID < 70000
+       zval ** ud = (zval**)lua_newuserdata(L, sizeof(zval*));
        *ud = z;
        Z_ADDREF_P(z);
+#else
+       zval * ud = (zval*)lua_newuserdata(L, sizeof(zval));
+       ZVAL_COPY(ud, z);
+#endif
 
        lua_getfield(L, LUA_REGISTRYINDEX, "php_luasandbox_zval_metatable");
        lua_setmetatable(L, -2);
@@ -162,8 +196,6 @@
  */
 static int luasandbox_push_hashtable(lua_State * L, HashTable * ht)
 {
-       HashPosition p;
-
        // Recursion requires an arbitrary amount of stack space so we have to
        // check the stack.
        luaL_checkstack(L, 10, "converting PHP array to Lua");
@@ -179,6 +211,9 @@
                return 0;
        }
        luasandbox_protect_recursion(ht);
+
+#if PHP_VERSION_ID < 70000
+       HashPosition p;
        for (zend_hash_internal_pointer_reset_ex(ht, &p);
                        zend_hash_get_current_key_type_ex(ht, &p) != 
HASH_KEY_NON_EXISTANT;
                        zend_hash_move_forward_ex(ht, &p))
@@ -206,6 +241,30 @@
 
                lua_settable(L, -3);
        }
+#else
+       ulong lkey;
+       zend_string *key;
+       zval *value;
+       ZEND_HASH_FOREACH_KEY_VAL(ht, lkey, key, value)
+       {
+               if (key) {
+                       lua_pushlstring(L, ZSTR_VAL(key), ZSTR_LEN(key));
+               } else {
+                       lua_pushinteger(L, lkey);
+               }
+
+               if (!luasandbox_push_zval(L, value)) {
+                       // Failed to process that data value
+                       // Pop the key and the half-constructed table
+                       lua_pop(L, 2);
+                       luasandbox_unprotect_recursion(ht);
+                       return 0;
+               }
+
+               lua_settable(L, -3);
+       } ZEND_HASH_FOREACH_END();
+#endif
+
        luasandbox_unprotect_recursion(ht);
        return 1;
 }
@@ -267,33 +326,27 @@
                        const char * str;
                        size_t length;
                        str = lua_tolstring(L, index, &length);
+#if PHP_VERSION_ID < 70000
                        ZVAL_STRINGL(z, str, length, 1);
+#else
+                       ZVAL_STRINGL(z, str, length);
+#endif
                        break;
                }
                case LUA_TTABLE: {
                        const void * ptr = lua_topointer(L, index);
-                       void * data = NULL;
                        int allocated = 0;
                        int success = 1;
                        if (recursionGuard) {
                                // Check for circular reference (infinite 
recursion)
-                               if (zend_hash_find(recursionGuard, (char*)&ptr, 
sizeof(void*), &data) == SUCCESS) {
+#if PHP_VERSION_ID < 70000
+                               if (zend_hash_exists(recursionGuard, 
(char*)&ptr, sizeof(void*)))
+#else
+                               if (zend_hash_str_exists(recursionGuard, 
(char*)&ptr, sizeof(void*)))
+#endif
+                               {
                                        // Found circular reference!
-                                       zval *zex, *ztrace;
-                                       MAKE_STD_ZVAL(zex);
-                                       object_init_ex(zex, 
luasandboxruntimeerror_ce);
-
-                                       ALLOC_INIT_ZVAL(ztrace); // IS_NULL if 
lua_to_zval fails.
-                                       luasandbox_push_structured_trace(L, 1);
-                                       luasandbox_lua_to_zval(ztrace, L, -1, 
sandbox_zval, NULL TSRMLS_CC);
-                                       
zend_update_property(luasandboxruntimeerror_ce, zex, "luaTrace", 
sizeof("luaTrace")-1, ztrace TSRMLS_CC);
-                                       zval_ptr_dtor(&ztrace);
-                                       lua_pop(L, 1);
-
-                                       
zend_update_property_string(luasandboxruntimeerror_ce, zex,
-                                               "message", sizeof("message")-1, 
"Cannot pass circular reference to PHP" TSRMLS_CC);
-                                       
zend_update_property_long(luasandboxruntimeerror_ce, zex, "code", 
sizeof("code")-1, -1 TSRMLS_CC);
-                                       zend_throw_exception_object(zex 
TSRMLS_CC);
+                                       luasandbox_throw_runtimeerror(L, 
sandbox_zval, "Cannot pass circular reference to PHP" TSRMLS_CC);
 
                                        ZVAL_NULL(z); // Need to set something 
to prevent a segfault
                                        return 0;
@@ -306,7 +359,13 @@
 
                        // Add the current table to the recursion guard 
hashtable
                        // Use the pointer as the key, zero-length data
+#if PHP_VERSION_ID < 70000
                        zend_hash_update(recursionGuard, (char*)&ptr, 
sizeof(void*), (void*)"", 1, NULL);
+#else
+                       zval zv;
+                       ZVAL_TRUE(&zv);
+                       zend_hash_str_update(recursionGuard, (char*)&ptr, 
sizeof(void*), &zv);
+#endif
 
                        // Process the array
                        array_init(z);
@@ -328,8 +387,7 @@
                case LUA_TFUNCTION: {
                        int func_index;
                        php_luasandboxfunction_obj * func_obj;
-                       php_luasandbox_obj * sandbox = (php_luasandbox_obj*)
-                               zend_object_store_get_object(sandbox_zval 
TSRMLS_CC);
+                       php_luasandbox_obj * sandbox = 
GET_LUASANDBOX_OBJ(sandbox_zval);
 
                        // Normalise the input index so that we can push 
without invalidating it.
                        if (index < 0) {
@@ -353,10 +411,14 @@
 
                        // Create a LuaSandboxFunction object to hold a 
reference to the function
                        object_init_ex(z, luasandboxfunction_ce);
-                       func_obj = 
(php_luasandboxfunction_obj*)zend_object_store_get_object(z TSRMLS_CC);
+                       func_obj = GET_LUASANDBOXFUNCTION_OBJ(z);
                        func_obj->index = func_index;
+#if PHP_VERSION_ID < 70000
                        func_obj->sandbox = sandbox_zval;
                        Z_ADDREF_P(sandbox_zval);
+#else
+                       ZVAL_COPY(&func_obj->sandbox, sandbox_zval);
+#endif
 
                        // Balance the stack
                        lua_pop(L, 1);
@@ -367,26 +429,9 @@
                case LUA_TLIGHTUSERDATA:
                        // TODO: provide derived classes for each type
                default: {
-                       zval *zex, *ztrace;
                        char *message;
-
                        spprintf(&message, 0, "Cannot pass %s to PHP", 
lua_typename(L, lua_type(L, index)));
-
-                       MAKE_STD_ZVAL(zex);
-                       object_init_ex(zex, luasandboxruntimeerror_ce);
-
-                       ALLOC_INIT_ZVAL(ztrace); // IS_NULL if lua_to_zval 
fails.
-                       luasandbox_push_structured_trace(L, 1);
-                       luasandbox_lua_to_zval(ztrace, L, -1, sandbox_zval, 
NULL TSRMLS_CC);
-                       zend_update_property(luasandboxruntimeerror_ce, zex, 
"luaTrace", sizeof("luaTrace")-1, ztrace TSRMLS_CC);
-                       zval_ptr_dtor(&ztrace);
-                       lua_pop(L, 1);
-
-                       zend_update_property_string(luasandboxruntimeerror_ce, 
zex,
-                               "message", sizeof("message")-1, message 
TSRMLS_CC);
-                       zend_update_property_long(luasandboxruntimeerror_ce, 
zex, "code", sizeof("code")-1, -1 TSRMLS_CC);
-                       zend_throw_exception_object(zex TSRMLS_CC);
-
+                       luasandbox_throw_runtimeerror(L, sandbox_zval, message 
TSRMLS_CC);
                        efree(message);
 
                        ZVAL_NULL(z); // Need to set something to prevent a 
segfault
@@ -483,12 +528,19 @@
 {
        const char * str;
        size_t length;
-       zval *value;
        lua_Number n;
 
-       // Convert value, then remove it
+#if PHP_VERSION_ID < 70000
+       zval *value, *valp;
        ALLOC_INIT_ZVAL(value);
-       if (!luasandbox_lua_to_zval(value, L, -1, sandbox_zval, recursionGuard 
TSRMLS_CC)) {
+       valp = value;
+#else
+       zval value, *valp = &value;
+       ZVAL_NULL(&value);
+#endif
+
+       // Convert value, then remove it
+       if (!luasandbox_lua_to_zval(valp, L, -1, sandbox_zval, recursionGuard 
TSRMLS_CC)) {
                zval_ptr_dtor(&value);
                return 0;
        }
@@ -499,7 +551,11 @@
                n = lua_tonumber(L, -1);
                if (isfinite(n) && n == floor(n)) {
                        // Integer key
+#if PHP_VERSION_ID < 70000
                        zend_hash_index_update(ht, n, (void*)&value, 
sizeof(zval*), NULL);
+#else
+                       zend_hash_index_update(ht, n, valp);
+#endif
                        return 1;
                }
        }
@@ -509,33 +565,20 @@
        str = lua_tolstring(L, -1, &length);
        if ( str == NULL ) {
                // Only strings and integers may be used as keys
-               zval *zex, *ztrace;
                char *message;
-
                spprintf(&message, 0, "Cannot use %s as an array key when 
passing data from Lua to PHP",
                        lua_typename(L, lua_type(L, -2))
                );
-
-               MAKE_STD_ZVAL(zex);
-               object_init_ex(zex, luasandboxruntimeerror_ce);
-
-               ALLOC_INIT_ZVAL(ztrace);
-               luasandbox_push_structured_trace(L, 1);
-               luasandbox_lua_to_zval(ztrace, L, -1, sandbox_zval, NULL 
TSRMLS_CC);
-               zend_update_property(luasandboxruntimeerror_ce, zex, 
"luaTrace", sizeof("luaTrace")-1, ztrace TSRMLS_CC);
-               zval_ptr_dtor(&ztrace);
-               lua_pop(L, 1);
-
-               zend_update_property_string(luasandboxruntimeerror_ce, zex,
-                       "message", sizeof("message")-1, message TSRMLS_CC);
-               zend_update_property_long(luasandboxruntimeerror_ce, zex, 
"code", sizeof("code")-1, -1 TSRMLS_CC);
-               zend_throw_exception_object(zex TSRMLS_CC);
-
+               luasandbox_throw_runtimeerror(L, sandbox_zval, message 
TSRMLS_CC);
                efree(message);
 
                return 0;
        }
+#if PHP_VERSION_ID < 70000
        zend_hash_update(ht, str, length + 1, (void*)&value, sizeof(zval*), 
NULL);
+#else
+       zend_hash_str_update(ht, str, length, valp);
+#endif
        lua_pop(L, 1);
        return 1;
 }
@@ -689,6 +732,43 @@
 }
 /* }}} */
 
+/** {{{ luasandbox_throw_runtimeerror
+ *
+ * Create and throw a luasandboxruntimeerror
+ */
+void luasandbox_throw_runtimeerror(lua_State * L, zval * sandbox_zval, const 
char *message TSRMLS_DC)
+{
+       zval *zex, *ztrace;
+
+#if PHP_VERSION_ID < 70000
+       MAKE_STD_ZVAL(zex);
+       ALLOC_INIT_ZVAL(ztrace); // IS_NULL if lua_to_zval fails.
+#else
+       zval zvex, zvtrace;
+       zex = &zvex;
+       ztrace = &zvtrace;
+       ZVAL_NULL(ztrace); // IS_NULL if lua_to_zval fails.
+#endif
+
+       object_init_ex(zex, luasandboxruntimeerror_ce);
+
+       luasandbox_push_structured_trace(L, 1);
+       luasandbox_lua_to_zval(ztrace, L, -1, sandbox_zval, NULL TSRMLS_CC);
+       zend_update_property(luasandboxruntimeerror_ce, zex, "luaTrace", 
sizeof("luaTrace")-1, ztrace TSRMLS_CC);
+#if PHP_VERSION_ID < 70000
+       zval_ptr_dtor(&ztrace);
+#else
+       zval_ptr_dtor(&zvtrace);
+#endif
+       lua_pop(L, 1);
+
+       zend_update_property_string(luasandboxruntimeerror_ce, zex,
+               "message", sizeof("message")-1, message TSRMLS_CC);
+       zend_update_property_long(luasandboxruntimeerror_ce, zex, "code", 
sizeof("code")-1, -1 TSRMLS_CC);
+       zend_throw_exception_object(zex TSRMLS_CC);
+}
+/* }}} */
+
 /** {{{ luasandbox_is_recursive
  * Check if the recursion flag is set on this hashtable.
  *
@@ -700,10 +780,13 @@
 static inline int luasandbox_is_recursive(HashTable * ht) {
 #ifdef HHVM
        return (int)(protectionSet.get()->count(ht));
-#else
+#elif PHP_VERSION_ID < 70000
        return ht->nApplyCount;
+#else
+       return ht->u.v.nApplyCount;
 #endif
 }
+/* }}} */
 
 /** {{{ luasandbox_protect_recursion
  *
@@ -712,10 +795,13 @@
 static inline void luasandbox_protect_recursion(HashTable * ht) {
 #ifdef HHVM
        protectionSet.get()->insert(ht);
-#else
+#elif PHP_VERSION_ID < 70000
        ht->nApplyCount++;
+#else
+       ht->u.v.nApplyCount++;
 #endif
 }
+/* }}} */
 
 /** {{{ luasandbox_protect_recursion
  *
@@ -724,8 +810,10 @@
 static inline void luasandbox_unprotect_recursion(HashTable * ht) {
 #ifdef HHVM
        protectionSet.get()->erase(ht);
-#else
+#elif PHP_VERSION_ID < 70000
        ht->nApplyCount--;
+#else
+       ht->u.v.nApplyCount--;
 #endif
 }
-
+/* }}} */
diff --git a/library.c b/library.c
index 0734b88..32b807e 100644
--- a/library.c
+++ b/library.c
@@ -134,14 +134,16 @@
        while (lua_next(L, LUA_GLOBALSINDEX) != 0) {
                const char * key;
                size_t key_len;
-               void * data;
                lua_pop(L, 1);
                if (lua_type(L, -1) != LUA_TSTRING) {
                        continue;
                }
                key = lua_tolstring(L, -1, &key_len);
-               if (zend_hash_find(luasandbox_lib_get_allowed_globals(TSRMLS_C),
-                       (char*)key, key_len + 1, &data) == FAILURE)
+#if PHP_VERSION_ID < 70000
+               if 
(!zend_hash_exists(luasandbox_lib_get_allowed_globals(TSRMLS_C), (char*)key, 
key_len + 1))
+#else
+               if 
(!zend_hash_str_exists(luasandbox_lib_get_allowed_globals(TSRMLS_C), key, 
key_len))
+#endif
                {
                        // Not allowed, delete it
                        lua_pushnil(L);
@@ -237,10 +239,21 @@
 
        ALLOC_HASHTABLE(LUASANDBOX_G(allowed_globals));
        zend_hash_init(LUASANDBOX_G(allowed_globals), n, NULL, NULL, 0);
+
+#if PHP_VERSION_ID >= 70000
+       zval zv;
+       ZVAL_TRUE(&zv);
+#endif
+
        for (i = 0; luasandbox_allowed_globals[i]; i++) {
+#if PHP_VERSION_ID < 70000
                zend_hash_update(LUASANDBOX_G(allowed_globals),
                        luasandbox_allowed_globals[i], 
strlen(luasandbox_allowed_globals[i]) + 1,
                        (void*)"", 1, NULL);
+#else
+               zend_hash_str_update(LUASANDBOX_G(allowed_globals),
+                       luasandbox_allowed_globals[i], 
strlen(luasandbox_allowed_globals[i]), &zv);
+#endif
        }
 
        return LUASANDBOX_G(allowed_globals);
diff --git a/luasandbox.c b/luasandbox.c
index 53e273a..d31f9a8 100644
--- a/luasandbox.c
+++ b/luasandbox.c
@@ -14,12 +14,33 @@
 #include "zend_exceptions.h"
 #include "php_luasandbox.h"
 #include "luasandbox_timer.h"
+#if PHP_VERSION_ID < 70000
 #include "ext/standard/php_smart_str.h"
+#else
+#include "zend_smart_str.h"
+#endif
 #include "luasandbox_version.h"
 
 // Compatability for PHP <= 5.3.6
 #ifndef ZEND_FE_END
 #define ZEND_FE_END { NULL, NULL, NULL, 0, 0 }
+#endif
+
+// Compatability typedefs and defines to hide some PHP5/PHP7 differences
+#if PHP_VERSION_ID < 70000
+typedef zend_object_value object_constructor_ret_t;
+typedef int str_param_len_t;
+typedef long long_param_t;
+typedef zval*** star_param_t;
+#define compat_zend_register_internal_class_ex(ce, parent_ce) 
zend_register_internal_class_ex(ce, parent_ce, NULL TSRMLS_CC)
+#define compat_add_assoc_string(assoc, key, val) add_assoc_string((assoc), 
(key), (val), 1)
+#else
+typedef zend_object* object_constructor_ret_t;
+typedef size_t str_param_len_t;
+typedef zend_long long_param_t;
+typedef zval* star_param_t;
+#define compat_zend_register_internal_class_ex(ce, parent_ce) 
zend_register_internal_class_ex(ce, parent_ce)
+#define compat_add_assoc_string(assoc, key, val) add_assoc_string((assoc), 
(key), (val))
 #endif
 
 #define CHECK_VALID_STATE(state) \
@@ -31,10 +52,10 @@
 static PHP_GINIT_FUNCTION(luasandbox);
 static PHP_GSHUTDOWN_FUNCTION(luasandbox);
 static int luasandbox_post_deactivate();
-static zend_object_value luasandbox_new(zend_class_entry *ce TSRMLS_DC);
+static object_constructor_ret_t luasandbox_new(zend_class_entry *ce TSRMLS_DC);
 static lua_State * luasandbox_newstate(php_luasandbox_obj * intern TSRMLS_DC);
 static void luasandbox_free_storage(void *object TSRMLS_DC);
-static zend_object_value luasandboxfunction_new(zend_class_entry *ce 
TSRMLS_DC);
+static object_constructor_ret_t luasandboxfunction_new(zend_class_entry *ce 
TSRMLS_DC);
 static void luasandboxfunction_free_storage(void *object TSRMLS_DC);
 static int luasandbox_panic(lua_State * L);
 static lua_State * luasandbox_state_from_zval(zval * this_ptr TSRMLS_DC);
@@ -46,7 +67,7 @@
        lua_State ** pstate, php_luasandbox_obj ** psandbox TSRMLS_DC);
 static void luasandbox_call_helper(lua_State * L, zval * sandbox_zval,
        php_luasandbox_obj * sandbox,
-       zval *** args, zend_uint numArgs, zval * return_value TSRMLS_DC);
+       star_param_t args, int numArgs, zval * return_value TSRMLS_DC);
 static void luasandbox_handle_error(php_luasandbox_obj * sandbox, int status 
TSRMLS_DC);
 static int luasandbox_dump_writer(lua_State * L, const void * p, size_t sz, 
void * ud);
 static zend_bool luasandbox_instanceof(
@@ -73,6 +94,11 @@
 zend_class_entry *luasandboxfunction_ce;
 
 ZEND_DECLARE_MODULE_GLOBALS(luasandbox);
+
+#if PHP_VERSION_ID >= 70000
+static zend_object_handlers luasandbox_object_handlers;
+static zend_object_handlers luasandboxfunction_object_handlers;
+#endif
 
 /** {{{ arginfo */
 ZEND_BEGIN_ARG_INFO(arginfo_luasandbox_getVersionInfo, 0)
@@ -234,8 +260,7 @@
                "PERCENT", sizeof("PERCENT")-1, LUASANDBOX_PERCENT TSRMLS_CC);
 
        INIT_CLASS_ENTRY(ce, "LuaSandboxError", luasandbox_empty_methods);
-       luasandboxerror_ce = zend_register_internal_class_ex(
-                       &ce, zend_exception_get_default(TSRMLS_C), NULL 
TSRMLS_CC);
+       luasandboxerror_ce = compat_zend_register_internal_class_ex(&ce, 
zend_exception_get_default(TSRMLS_C));
        zend_declare_class_constant_long(luasandboxerror_ce,
                "RUN", sizeof("RUN")-1, LUA_ERRRUN TSRMLS_CC);
        zend_declare_class_constant_long(luasandboxerror_ce,
@@ -246,37 +271,37 @@
                "ERR", sizeof("ERR")-1, LUA_ERRERR TSRMLS_CC);
 
        INIT_CLASS_ENTRY(ce, "LuaSandboxRuntimeError", 
luasandbox_empty_methods);
-       luasandboxruntimeerror_ce = zend_register_internal_class_ex(
-                       &ce, luasandboxerror_ce, NULL TSRMLS_CC);
+       luasandboxruntimeerror_ce = compat_zend_register_internal_class_ex(&ce, 
luasandboxerror_ce);
 
        INIT_CLASS_ENTRY(ce, "LuaSandboxFatalError", luasandbox_empty_methods);
-       luasandboxfatalerror_ce = zend_register_internal_class_ex(
-                       &ce, luasandboxerror_ce, NULL TSRMLS_CC);
+       luasandboxfatalerror_ce = compat_zend_register_internal_class_ex(&ce, 
luasandboxerror_ce);
 
        INIT_CLASS_ENTRY(ce, "LuaSandboxSyntaxError", luasandbox_empty_methods);
-       luasandboxsyntaxerror_ce = zend_register_internal_class_ex(
-               &ce, luasandboxfatalerror_ce, NULL TSRMLS_CC);
+       luasandboxsyntaxerror_ce = compat_zend_register_internal_class_ex(&ce, 
luasandboxfatalerror_ce);
 
        INIT_CLASS_ENTRY(ce, "LuaSandboxMemoryError", luasandbox_empty_methods);
-       luasandboxmemoryerror_ce = zend_register_internal_class_ex(
-                       &ce, luasandboxfatalerror_ce, NULL TSRMLS_CC);
+       luasandboxmemoryerror_ce = compat_zend_register_internal_class_ex(&ce, 
luasandboxfatalerror_ce);
 
        INIT_CLASS_ENTRY(ce, "LuaSandboxErrorError", luasandbox_empty_methods);
-       luasandboxerrorerror_ce = zend_register_internal_class_ex(
-                       &ce, luasandboxfatalerror_ce, NULL TSRMLS_CC);
+       luasandboxerrorerror_ce = compat_zend_register_internal_class_ex(&ce, 
luasandboxfatalerror_ce);
 
        INIT_CLASS_ENTRY(ce, "LuaSandboxTimeoutError", 
luasandbox_empty_methods);
-       luasandboxtimeouterror_ce = zend_register_internal_class_ex(
-                       &ce, luasandboxfatalerror_ce, NULL TSRMLS_CC);
+       luasandboxtimeouterror_ce = compat_zend_register_internal_class_ex(&ce, 
luasandboxfatalerror_ce);
 
        // Deprecated, for catch blocks only
        INIT_CLASS_ENTRY(ce, "LuaSandboxEmergencyTimeoutError", 
luasandbox_empty_methods);
-       luasandboxemergencytimeouterror_ce = zend_register_internal_class_ex(
-               &ce, luasandboxfatalerror_ce, NULL TSRMLS_CC);
+       luasandboxemergencytimeouterror_ce = 
compat_zend_register_internal_class_ex(&ce, luasandboxfatalerror_ce);
 
        INIT_CLASS_ENTRY(ce, "LuaSandboxFunction", luasandboxfunction_methods);
        luasandboxfunction_ce = zend_register_internal_class(&ce TSRMLS_CC);
        luasandboxfunction_ce->create_object = luasandboxfunction_new;
+
+#if PHP_VERSION_ID >= 70000
+       memcpy(&luasandbox_object_handlers, zend_get_std_object_handlers(), 
sizeof(zend_object_handlers));
+       luasandbox_object_handlers.free_obj = 
(zend_object_free_obj_t)luasandbox_free_storage;
+       memcpy(&luasandboxfunction_object_handlers, 
zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+       luasandboxfunction_object_handlers.free_obj = 
(zend_object_free_obj_t)luasandboxfunction_free_storage;
+#endif
 
        luasandbox_timer_minit(TSRMLS_C);
 
@@ -343,10 +368,9 @@
  *
  * "new" handler for the LuaSandbox class
  */
-static zend_object_value luasandbox_new(zend_class_entry *ce TSRMLS_DC)
+static object_constructor_ret_t luasandbox_new(zend_class_entry *ce TSRMLS_DC)
 {
        php_luasandbox_obj * sandbox;
-       zend_object_value retval;
 
        // Create the internal object
        sandbox = (php_luasandbox_obj*)emalloc(sizeof(php_luasandbox_obj));
@@ -364,7 +388,9 @@
        // Initialise the timer
        luasandbox_timer_create(&sandbox->timer, sandbox);
 
+#if PHP_VERSION_ID < 70000
        // Put the object into the store
+       zend_object_value retval;
        retval.handle = zend_objects_store_put(
                sandbox,
                (zend_objects_store_dtor_t)zend_objects_destroy_object,
@@ -373,6 +399,11 @@
        retval.handlers = zend_get_std_object_handlers();
        LUASANDBOX_G(active_count)++;
        return retval;
+#else
+       sandbox->std.handlers = &luasandbox_object_handlers;
+       LUASANDBOX_G(active_count)++;
+       return &sandbox->std;
+#endif
 }
 /* }}} */
 
@@ -424,7 +455,9 @@
                sandbox->state = NULL;
        }
        zend_object_std_dtor(&sandbox->std TSRMLS_CC);
+#if PHP_VERSION_ID < 70000
        efree(object);
+#endif
        LUASANDBOX_G(active_count)--;
 }
 /* }}} */
@@ -433,10 +466,9 @@
  *
  * "new" handler for the LuaSandboxFunction class.
  */
-static zend_object_value luasandboxfunction_new(zend_class_entry *ce TSRMLS_DC)
+static object_constructor_ret_t luasandboxfunction_new(zend_class_entry *ce 
TSRMLS_DC)
 {
        php_luasandboxfunction_obj * intern;
-       zend_object_value retval;
 
        // Create the internal object
        intern = 
(php_luasandboxfunction_obj*)emalloc(sizeof(php_luasandboxfunction_obj));
@@ -446,7 +478,9 @@
        object_properties_init(&intern->std, ce);
 #endif
 
+#if PHP_VERSION_ID < 70000
        // Put the object into the store
+       zend_object_value retval;
        retval.handle = zend_objects_store_put(
                intern,
                (zend_objects_store_dtor_t)zend_objects_destroy_object,
@@ -454,6 +488,10 @@
                NULL TSRMLS_CC);
        retval.handlers = zend_get_std_object_handlers();
        return retval;
+#else
+       intern->std.handlers = &luasandboxfunction_object_handlers;
+       return &intern->std;
+#endif
 }
 /* }}} */
 
@@ -466,9 +504,9 @@
 static void luasandboxfunction_free_storage(void *object TSRMLS_DC)
 {
        php_luasandboxfunction_obj * func = (php_luasandboxfunction_obj*)object;
-       if (func->sandbox) {
-               php_luasandbox_obj * sandbox = (php_luasandbox_obj*)
-                       zend_object_store_get_object(func->sandbox TSRMLS_CC);
+       if (LUASANDBOXFUNCTION_SANDBOX_IS_OK(func)) {
+               zval *zsandbox = LUASANDBOXFUNCTION_GET_SANDBOX_ZVALPTR(func);
+               php_luasandbox_obj * sandbox = GET_LUASANDBOX_OBJ(zsandbox);
                if (sandbox && sandbox->state) {
                        lua_State * L = sandbox->state;
 
@@ -483,9 +521,16 @@
 
                // Delete the parent reference
                zval_ptr_dtor(&func->sandbox);
+#if PHP_VERSION_ID < 70000
+               func->sandbox = NULL;
+#else
+               ZVAL_UNDEF(&func->sandbox);
+#endif
        }
        zend_object_std_dtor(&func->std TSRMLS_CC);
+#if PHP_VERSION_ID < 70000
        efree(object);
+#endif
 }
 /* }}} */
 
@@ -522,8 +567,7 @@
  */
 static lua_State * luasandbox_state_from_zval(zval * this_ptr TSRMLS_DC)
 {
-       php_luasandbox_obj * intern = (php_luasandbox_obj*)
-               zend_object_store_get_object(this_ptr TSRMLS_CC);
+       php_luasandbox_obj * intern = GET_LUASANDBOX_OBJ(this_ptr);
        return intern->state;
 }
 /* }}} */
@@ -536,15 +580,14 @@
 static void luasandbox_load_helper(int binary, INTERNAL_FUNCTION_PARAMETERS)
 {
        char *code, *chunkName = NULL;
-       int codeLength, chunkNameLength;
+       str_param_len_t codeLength, chunkNameLength;
        int status;
        lua_State * L;
        int have_mark;
        php_luasandbox_obj * sandbox;
        int was_paused;
 
-       sandbox = (php_luasandbox_obj*)
-               zend_object_store_get_object(this_ptr TSRMLS_CC);
+       sandbox = GET_LUASANDBOX_OBJ(getThis());
        L = sandbox->state;
        CHECK_VALID_STATE(L);
 
@@ -598,7 +641,7 @@
        }
 
        // Make a zval out of it, and return false on error
-       if (!luasandbox_lua_to_zval(return_value, L, lua_gettop(L), this_ptr, 
NULL TSRMLS_CC) ||
+       if (!luasandbox_lua_to_zval(return_value, L, lua_gettop(L), getThis(), 
NULL TSRMLS_CC) ||
                Z_TYPE_P(return_value) == IS_NULL
        ) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING,
@@ -618,10 +661,10 @@
 PHP_METHOD(LuaSandbox, getVersionInfo)
 {
        array_init_size(return_value, 2);
-       add_assoc_string(return_value, "LuaSandbox", LUASANDBOX_VERSION, 1);
-       add_assoc_string(return_value, "Lua", LUA_RELEASE, 1);
+       compat_add_assoc_string(return_value, "LuaSandbox", LUASANDBOX_VERSION);
+       compat_add_assoc_string(return_value, "Lua", LUA_RELEASE);
 #ifdef LUAJIT_VERSION
-       add_assoc_string(return_value, "LuaJIT", LUAJIT_VERSION, 1);
+       compat_add_assoc_string(return_value, "LuaJIT", LUAJIT_VERSION);
 #endif
 }
 
@@ -667,6 +710,16 @@
        zend_class_entry * ce;
        zval *zex, *ztrace;
 
+#if PHP_VERSION_ID < 70000
+       MAKE_STD_ZVAL(zex);
+       ALLOC_INIT_ZVAL(ztrace); // IS_NULL if lua_to_zval fails.
+#else
+       zval zvex, zvtrace;
+       zex = &zvex;
+       ztrace = &zvtrace;
+       ZVAL_NULL(ztrace);
+#endif
+
        if (EG(exception)) {
                lua_pop(L, 1);
                return;
@@ -696,20 +749,22 @@
                        break;
        }
 
-       MAKE_STD_ZVAL(zex);
        object_init_ex(zex, ce);
 
        if (luasandbox_is_trace_error(L, -1)) {
                // Push the trace on to the top of the stack
                lua_rawgeti(L, -1, 3);
                // Convert it to a zval
-               ALLOC_INIT_ZVAL(ztrace); // IS_NULL if lua_to_zval fails.
-               luasandbox_lua_to_zval(ztrace, L, -1, sandbox->current_zval, 
NULL TSRMLS_CC);
+               luasandbox_lua_to_zval(ztrace, L, -1, 
LUASANDBOX_GET_CURRENT_ZVAL_PTR(sandbox), NULL TSRMLS_CC);
                // Put it in the exception object
                zend_update_property(ce, zex, "luaTrace", sizeof("luaTrace")-1, 
ztrace TSRMLS_CC);
-               zval_ptr_dtor(&ztrace);
                lua_pop(L, 1);
        }
+#if PHP_VERSION_ID < 70000
+       zval_ptr_dtor(&ztrace);
+#else
+       zval_ptr_dtor(&zvtrace);
+#endif
 
        // Initialise standard properties
        // We would get Zend to do this, but the code for it is wrapped inside 
some
@@ -733,9 +788,8 @@
  */
 PHP_METHOD(LuaSandbox, setMemoryLimit)
 {
-       long limit;
-       php_luasandbox_obj * intern = (php_luasandbox_obj*)
-               zend_object_store_get_object(getThis() TSRMLS_CC);
+       long_param_t limit;
+       php_luasandbox_obj * intern = GET_LUASANDBOX_OBJ(getThis());
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
                                &limit) == FAILURE)
@@ -765,8 +819,7 @@
 {
        zval *zp_limit = NULL;
 
-       php_luasandbox_obj * sandbox = (php_luasandbox_obj*)
-               zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_luasandbox_obj * sandbox = GET_LUASANDBOX_OBJ(getThis());
 
        struct timespec limit = {0, 0};
 
@@ -777,8 +830,12 @@
        }
 
        if (!zp_limit
-               || (Z_TYPE_P(zp_limit) == IS_BOOL && Z_BVAL_P(zp_limit) == 0))
-       {
+#ifdef IS_BOOL
+               || (Z_TYPE_P(zp_limit) == IS_BOOL && Z_BVAL_P(zp_limit) == 0)
+#else
+               || Z_TYPE_P(zp_limit) == IS_FALSE
+#endif
+       ) {
                // No limit
                sandbox->is_cpu_limited = 0;
        } else {
@@ -823,8 +880,7 @@
 PHP_METHOD(LuaSandbox, getCPUUsage)
 {
        struct timespec ts;
-       php_luasandbox_obj * sandbox = (php_luasandbox_obj*)
-               zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_luasandbox_obj * sandbox = GET_LUASANDBOX_OBJ(getThis());
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
                RETURN_FALSE;
@@ -854,8 +910,7 @@
  */
 PHP_METHOD(LuaSandbox, pauseUsageTimer)
 {
-       php_luasandbox_obj * sandbox = (php_luasandbox_obj*)
-               zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_luasandbox_obj * sandbox = GET_LUASANDBOX_OBJ(getThis());
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
                RETURN_FALSE;
@@ -876,8 +931,7 @@
  */
 PHP_METHOD(LuaSandbox, unpauseUsageTimer)
 {
-       php_luasandbox_obj * sandbox = (php_luasandbox_obj*)
-               zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_luasandbox_obj * sandbox = GET_LUASANDBOX_OBJ(getThis());
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
                RETURN_FALSE;
@@ -901,8 +955,7 @@
 {
        double period = 2e-3;
        struct timespec ts;
-       php_luasandbox_obj * sandbox = (php_luasandbox_obj*)
-               zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_luasandbox_obj * sandbox = GET_LUASANDBOX_OBJ(getThis());
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|d", &period) == 
FAILURE) {
                RETURN_FALSE;
        }
@@ -919,8 +972,7 @@
 PHP_METHOD(LuaSandbox, disableProfiler)
 {
        struct timespec ts = {0, 0};
-       php_luasandbox_obj * sandbox = (php_luasandbox_obj*)
-               zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_luasandbox_obj * sandbox = GET_LUASANDBOX_OBJ(getThis());
        luasandbox_timer_enable_profiler(&sandbox->timer, &ts);
 }
 /* }}} */
@@ -930,10 +982,17 @@
        Bucket *bucket_a, *bucket_b;
        size_t value_a, value_b;
 
+#if PHP_VERSION_ID < 70000
        bucket_a = *((Bucket **) a);
        bucket_b = *((Bucket **) b);
        value_a = *(size_t*)bucket_a->pData;
        value_b = *(size_t*)bucket_b->pData;
+#else
+       bucket_a = (Bucket *) a;
+       bucket_b = (Bucket *) b;
+       value_a = (size_t)Z_LVAL(bucket_a->val);
+       value_b = (size_t)Z_LVAL(bucket_b->val);
+#endif
 
        if (value_a < value_b) {
                return 1;
@@ -960,10 +1019,8 @@
  */
 PHP_METHOD(LuaSandbox, getProfilerFunctionReport)
 {
-       long units = LUASANDBOX_SECONDS;
-       HashPosition p;
-       php_luasandbox_obj * sandbox = (php_luasandbox_obj*)
-               zend_object_store_get_object(getThis() TSRMLS_CC);
+       long_param_t units = LUASANDBOX_SECONDS;
+       php_luasandbox_obj * sandbox = GET_LUASANDBOX_OBJ(getThis());
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &units) == 
FAILURE) {
                RETURN_FALSE;
        }
@@ -984,7 +1041,11 @@
        }
 
        // Sort the input array in descending order of time usage
+#if PHP_VERSION_ID < 70000
        zend_hash_sort(counts, zend_qsort, luasandbox_sort_profile, 0 
TSRMLS_CC);
+#else
+       zend_hash_sort_ex(counts, zend_qsort, luasandbox_sort_profile, 0);
+#endif
 
        array_init_size(return_value, zend_hash_num_elements(counts));
 
@@ -999,6 +1060,8 @@
                }
        }
 
+#if PHP_VERSION_ID < 70000
+       HashPosition p;
        for (zend_hash_internal_pointer_reset_ex(counts, &p);
                        zend_hash_get_current_key_type_ex(counts, &p) != 
HASH_KEY_NON_EXISTANT;
                        zend_hash_move_forward_ex(counts, &p))
@@ -1017,6 +1080,20 @@
                        add_assoc_double_ex(return_value, func_name, 
func_name_length, *count * scale);
                }
        }
+#else
+       zend_string *key;
+       zval *count, v;
+       ZVAL_NULL(&v);
+       ZEND_HASH_FOREACH_STR_KEY_VAL(counts, key, count)
+       {
+               if (units == LUASANDBOX_SAMPLES) {
+                       zend_hash_add(Z_ARRVAL_P(return_value), key, count);
+               } else {
+                       ZVAL_LONG(&v, Z_LVAL_P(count) * scale);
+                       zend_hash_add(Z_ARRVAL_P(return_value), key, &v);
+               }
+       } ZEND_HASH_FOREACH_END();
+#endif
 
 #ifdef LUASANDBOX_REPORT_OVERRUNS
        if (units == LUASANDBOX_SAMPLES) {
@@ -1032,8 +1109,7 @@
 /** {{{ LuaSandbox::getMemoryUsage */
 PHP_METHOD(LuaSandbox, getMemoryUsage)
 {
-       php_luasandbox_obj * sandbox = (php_luasandbox_obj*)
-               zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_luasandbox_obj * sandbox = GET_LUASANDBOX_OBJ(getThis());
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
                RETURN_FALSE;
@@ -1046,8 +1122,7 @@
 /** {{{ LuaSandbox::getPeakMemoryUsage */
 PHP_METHOD(LuaSandbox, getPeakMemoryUsage)
 {
-       php_luasandbox_obj * sandbox = (php_luasandbox_obj*)
-               zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_luasandbox_obj * sandbox = GET_LUASANDBOX_OBJ(getThis());
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
                RETURN_FALSE;
@@ -1075,12 +1150,11 @@
 PHP_METHOD(LuaSandbox, callFunction)
 {
        char *name;
-       int nameLength = 0;
-       zend_uint numArgs = 0;
-       zval *** args = NULL;
+       str_param_len_t nameLength = 0;
+       int numArgs = 0;
+       star_param_t args = NULL;
 
-       php_luasandbox_obj * sandbox = (php_luasandbox_obj*)
-               zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_luasandbox_obj * sandbox = GET_LUASANDBOX_OBJ(getThis());
        lua_State * L = sandbox->state;
        CHECK_VALID_STATE(L);
 
@@ -1100,10 +1174,12 @@
                luasandbox_call_helper(L, getThis(), sandbox, args, numArgs, 
return_value TSRMLS_CC);
        }
 
+#if PHP_VERSION_ID < 70000
        // Delete varargs
        if (numArgs) {
                efree(args);
        }
+#endif
 }
 /* }}} */
 
@@ -1119,8 +1195,7 @@
 {
        zval *z;
 
-       php_luasandbox_obj * sandbox = (php_luasandbox_obj*)
-               zend_object_store_get_object(getThis() TSRMLS_CC);
+       php_luasandbox_obj * sandbox = GET_LUASANDBOX_OBJ(getThis());
        lua_State * L = sandbox->state;
        CHECK_VALID_STATE(L);
 
@@ -1133,7 +1208,7 @@
        luasandbox_push_zval_userdata(L, z);
        lua_pushcclosure(L, luasandbox_call_php, 1);
 
-       if (!luasandbox_lua_to_zval(return_value, L, lua_gettop(L), this_ptr, 
NULL TSRMLS_CC) ||
+       if (!luasandbox_lua_to_zval(return_value, L, lua_gettop(L), getThis(), 
NULL TSRMLS_CC) ||
                Z_TYPE_P(return_value) == IS_NULL
        ) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING,
@@ -1153,16 +1228,15 @@
 static int luasandbox_function_init(zval * this_ptr, 
php_luasandboxfunction_obj ** pfunc,
        lua_State ** pstate, php_luasandbox_obj ** psandbox TSRMLS_DC)
 {
-       *pfunc = (php_luasandboxfunction_obj *)
-               zend_object_store_get_object(this_ptr TSRMLS_CC);
-       if (!*pfunc || !(*pfunc)->sandbox || !(*pfunc)->index) {
+       *pfunc = GET_LUASANDBOXFUNCTION_OBJ(this_ptr);
+       if (!*pfunc || !LUASANDBOXFUNCTION_SANDBOX_IS_OK(*pfunc) || 
!(*pfunc)->index) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING,
                        "attempt to call uninitialized LuaSandboxFunction 
object" );
                return 0;
        }
 
-       *psandbox = (php_luasandbox_obj*)
-               zend_object_store_get_object((*pfunc)->sandbox TSRMLS_CC);
+       zval *zsandbox = LUASANDBOXFUNCTION_GET_SANDBOX_ZVALPTR(*pfunc);
+       *psandbox = GET_LUASANDBOX_OBJ(zsandbox);
        *pstate = (*psandbox)->state;
 
        if (!*pstate) {
@@ -1209,8 +1283,8 @@
  */
 PHP_METHOD(LuaSandboxFunction, call)
 {
-       zend_uint numArgs = 0;
-       zval *** args = NULL;
+       int numArgs = 0;
+       star_param_t args = NULL;
 
        php_luasandboxfunction_obj * func;
        lua_State * L;
@@ -1227,12 +1301,15 @@
        }
 
        // Call the function
-       luasandbox_call_helper(L, func->sandbox, sandbox, args, numArgs, 
return_value TSRMLS_CC);
+       luasandbox_call_helper(L, LUASANDBOXFUNCTION_GET_SANDBOX_ZVALPTR(func),
+                       sandbox, args, numArgs, return_value TSRMLS_CC);
 
+#if PHP_VERSION_ID < 70000
        // Delete varargs
        if (numArgs) {
                efree(args);
        }
+#endif
 }
 /** }}} */
 
@@ -1246,7 +1323,11 @@
 {
        int status;
        int timer_started = 0;
+#if PHP_VERSION_ID < 70000
        zval * old_zval;
+#else
+       zval old_zval;
+#endif
        int was_paused;
        int old_allow_pause;
 
@@ -1267,8 +1348,13 @@
 
        // Save the current zval for later use in luasandbox_call_php. Restore 
it
        // after execution finishes, to support re-entrancy.
+#if PHP_VERSION_ID < 70000
        old_zval = sandbox->current_zval;
        sandbox->current_zval = sandbox_zval;
+#else
+       ZVAL_COPY_VALUE(&old_zval, &sandbox->current_zval);
+       ZVAL_COPY_VALUE(&sandbox->current_zval, sandbox_zval);
+#endif
 
        // Make sure this is counted against the Lua usage time limit, and set 
the
        // allow_pause flag.
@@ -1281,7 +1367,11 @@
        sandbox->in_lua++;
        status = lua_pcall(sandbox->state, nargs, nresults, errfunc);
        sandbox->in_lua--;
+#if PHP_VERSION_ID < 70000
        sandbox->current_zval = old_zval;
+#else
+       ZVAL_COPY_VALUE(&sandbox->current_zval, &old_zval);
+#endif
 
        // Restore pause state
        sandbox->allow_pause = old_allow_pause;
@@ -1310,13 +1400,14 @@
  * to an array containing all the results.
  */
 static void luasandbox_call_helper(lua_State * L, zval * sandbox_zval, 
php_luasandbox_obj * sandbox,
-       zval *** args, zend_uint numArgs, zval * return_value TSRMLS_DC)
+       star_param_t args, int numArgs, zval * return_value TSRMLS_DC)
 {
        // Save the top position
        int origTop = lua_gettop(L);
        // Keep track of the stack index where the return values will appear
        int retIndex = origTop + 2;
        int i, numResults;
+       zval *v;
 
        // Check to see if the value is a valid function
        if (lua_type(L, -1) != LUA_TFUNCTION) {
@@ -1340,7 +1431,12 @@
                RETURN_FALSE;
        }
        for (i = 0; i < numArgs; i++) {
-               if (!luasandbox_push_zval(L, *(args[i]))) {
+#if PHP_VERSION_ID < 70000
+               v = *(args[i]);
+#else
+               v = &(args[i]);
+#endif
+               if (!luasandbox_push_zval(L, v)) {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING,
                                "unable to convert argument %d to a lua value", 
i + 1);
                        lua_settop(L, origTop - 1);
@@ -1360,6 +1456,7 @@
 
        // Fill the array with the results
        for (i = 0; i < numResults; i++) {
+#if PHP_VERSION_ID < 70000
                zval * element;
                ALLOC_INIT_ZVAL(element); // ensure elem is inited in case we 
bail
                if (!luasandbox_lua_to_zval(element, L, retIndex + i, 
sandbox_zval, NULL TSRMLS_CC)) {
@@ -1370,6 +1467,16 @@
                zend_hash_next_index_insert(Z_ARRVAL_P(return_value),
                        (void*)&element,
                        sizeof(zval*), NULL);
+#else
+               zval element;
+               ZVAL_NULL(&element); // ensure elem is inited in case we bail
+               if (!luasandbox_lua_to_zval(&element, L, retIndex + i, 
sandbox_zval, NULL TSRMLS_CC)) {
+                       // Convert failed (which means an exception), so bail.
+                       zval_ptr_dtor(&element);
+                       break;
+               }
+               zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &element);
+#endif
        }
 
        // Balance the stack
@@ -1463,10 +1570,9 @@
 {
        lua_State * L = luasandbox_state_from_zval(getThis() TSRMLS_CC);
        char * libname = NULL;
-       int libname_len = 0;
+       str_param_len_t libname_len = 0;
        zval * zfunctions = NULL;
        HashTable * functions;
-       HashPosition p;
 
        CHECK_VALID_STATE(L);
 
@@ -1491,6 +1597,8 @@
                lua_createtable(L, 0, zend_hash_num_elements(functions));
        }
 
+#if PHP_VERSION_ID < 70000
+       HashPosition p;
        for (zend_hash_internal_pointer_reset_ex(functions, &p);
                        zend_hash_get_current_key_type_ex(functions, &p) != 
HASH_KEY_NON_EXISTANT;
                        zend_hash_move_forward_ex(functions, &p))
@@ -1518,6 +1626,27 @@
                // Add it to the table
                lua_rawset(L, -3);
        }
+#else
+       ulong lkey;
+       zend_string *key;
+       zval *callback;
+       ZEND_HASH_FOREACH_KEY_VAL(functions, lkey, key, callback)
+       {
+               // Push the key
+               if ( key ) {
+                       lua_pushlstring(L, ZSTR_VAL(key), ZSTR_LEN(key));
+               } else {
+                       lua_pushinteger(L, lkey);
+               }
+
+               // Push the callback zval and create the closure
+               luasandbox_push_zval_userdata(L, callback);
+               lua_pushcclosure(L, luasandbox_call_php, 1);
+
+               // Add it to the table
+               lua_rawset(L, -3);
+       } ZEND_HASH_FOREACH_END();
+#endif
 
        // Move the new table to the global namespace
        // The key is on the stack already
@@ -1553,24 +1682,24 @@
 
        luasandbox_enter_php(L, intern);
 
-       zval ** callback_pp = (zval**)lua_touserdata(L, lua_upvalueindex(1));
-       zval *retval_ptr = NULL;
+       zval * callback_p;
+#if PHP_VERSION_ID < 70000
+       callback_p = *(zval**)lua_touserdata(L, lua_upvalueindex(1));
+#else
+       callback_p = (zval*)lua_touserdata(L, lua_upvalueindex(1));
+#endif
        zend_fcall_info fci;
        zend_fcall_info_cache fcc;
        char *is_callable_error = NULL;
        int top = lua_gettop(L);
        int i;
-       void **temp;
-       zval **pointers;
-       zval ***double_pointers;
        int num_results = 0;
        int status;
-       HashPosition p;
        HashTable * ht;
        TSRMLS_FETCH();
 
        // Based on zend_parse_arg_impl()
-       if (zend_fcall_info_init(*callback_pp, 0, &fci, &fcc, NULL,
+       if (zend_fcall_info_init(callback_p, 0, &fci, &fcc, NULL,
                &is_callable_error TSRMLS_CC) != SUCCESS)
        {
                // Handle errors similar to the way PHP does it: show a warning 
and
@@ -1583,14 +1712,22 @@
                return 1;
        }
 
+#if PHP_VERSION_ID < 70000
+       zval *retval_ptr = NULL;
        fci.retval_ptr_ptr = &retval_ptr;
+#else
+       zval retval;
+       fci.retval = &retval;
+#endif
 
        // Make an array of zval double-pointers to hold the arguments
        int args_failed = 0;
-       temp = (void**)ecalloc(top, sizeof(void*) * 2);
-       double_pointers = (zval***)temp;
-       pointers = (zval**)(temp + top);
+       star_param_t args;
+#if PHP_VERSION_ID < 70000
+       args = (zval***)ecalloc(top * 2, sizeof(void*));
+       zval **pointers = (zval**)(args + top);
        for (i = 0; i < top; i++ ) {
+               args[i] = &(pointers[i]);
                ALLOC_INIT_ZVAL(pointers[i]); // ensure is inited in case we 
fail
                if (!luasandbox_lua_to_zval(pointers[i], L, i + 1, 
intern->current_zval, NULL TSRMLS_CC)) {
                        // Argument conversion failed, so skip the call. The 
PHP exception
@@ -1600,14 +1737,27 @@
                        top = i + 1;
                        break;
                }
-               double_pointers[i] = &(pointers[i]);
        }
+#else
+       args = (zval *)ecalloc(top, sizeof(zval));
+       for (i = 0; i < top; i++ ) {
+               ZVAL_NULL(&args[i]); // ensure is inited in case we fail
+               if (!luasandbox_lua_to_zval(&args[i], L, i + 1, 
&intern->current_zval, NULL TSRMLS_CC)) {
+                       // Argument conversion failed, so skip the call. The 
PHP exception
+                       // from the conversion will be handled below, along 
with freeing
+                       // all the zvals in args[0 <= i < top].
+                       args_failed = 1;
+                       top = i + 1;
+                       break;
+               }
+       }
+#endif
 
        if (!args_failed) {
                // Initialise the fci. Use zend_fcall_info_args_restore() since 
that's an
                // almost-legitimate way to avoid the extra malloc that we'd 
get from
                // zend_fcall_info_argp()
-               zend_fcall_info_args_restore(&fci, top, double_pointers);
+               zend_fcall_info_args_restore(&fci, top, args);
 
                // Sanity check, timers should never be paused at this point
                assert(!luasandbox_timer_is_paused(&intern->timer));
@@ -1618,14 +1768,15 @@
                // Automatically unpause now that PHP has returned
                luasandbox_timer_unpause(&intern->timer);
 
-               if (status == SUCCESS && fci.retval_ptr_ptr && 
*fci.retval_ptr_ptr)
-               {
+#if PHP_VERSION_ID < 70000
+               if (status == SUCCESS && fci.retval_ptr_ptr && 
*fci.retval_ptr_ptr) {
                        // Push the return values back to Lua
                        if (Z_TYPE_PP(fci.retval_ptr_ptr) == IS_NULL) {
                                // No action
                        } else if (Z_TYPE_PP(fci.retval_ptr_ptr) == IS_ARRAY) {
                                ht = Z_ARRVAL_PP(fci.retval_ptr_ptr);
                                luaL_checkstack(L, zend_hash_num_elements(ht) + 
10, "converting PHP return array to Lua");
+                               HashPosition p;
                                for (zend_hash_internal_pointer_reset_ex(ht, 
&p);
                                                
zend_hash_get_current_key_type_ex(ht, &p) != HASH_KEY_NON_EXISTANT;
                                                zend_hash_move_forward_ex(ht, 
&p))
@@ -1641,22 +1792,53 @@
                        }
                        zval_ptr_dtor(&retval_ptr);
                }
+#else
+               if (status == SUCCESS) {
+                       // Push the return values back to Lua
+                       if (Z_ISNULL_P(fci.retval) || Z_ISUNDEF_P(fci.retval)) {
+                               // No action
+                       } else if (Z_TYPE_P(fci.retval) == IS_ARRAY) {
+                               ht = Z_ARRVAL_P(fci.retval);
+                               luaL_checkstack(L, zend_hash_num_elements(ht) + 
10, "converting PHP return array to Lua");
+
+                               zval *value;
+                               ZEND_HASH_FOREACH_VAL(ht, value)
+                               {
+                                       luasandbox_push_zval(L, value);
+                                       num_results++;
+                               } ZEND_HASH_FOREACH_END();
+                       } else {
+                               php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                                       "function tried to return a single 
value to Lua without wrapping it in an array");
+                       }
+                       zval_ptr_dtor(&retval);
+               }
+#endif
        }
 
        // Free the argument zvals
        for (i = 0; i < top; i++) {
-               zval_ptr_dtor(&(pointers[i]));
+#if PHP_VERSION_ID < 70000
+               zval_ptr_dtor(args[i]);
+#else
+               zval_ptr_dtor(&(args[i]));
+#endif
        }
-
-       // Free the pointer arrays
-       efree(temp);
+       efree(args);
        luasandbox_leave_php(L, intern);
 
        // If an exception occurred, convert it to a Lua error
        if (EG(exception)) {
                // Get the error message and push it to the stack
+#if PHP_VERSION_ID < 70000
                zend_class_entry * ce = Z_OBJCE_P(EG(exception));
                zval * zmsg = zend_read_property(ce, EG(exception), "message", 
sizeof("message")-1, 1 TSRMLS_CC);
+#else
+               zval exception, rv;
+               ZVAL_OBJ(&exception, EG(exception));
+               zend_class_entry * ce = Z_OBJCE(exception);
+               zval * zmsg = zend_read_property(ce, &exception, "message", 
sizeof("message")-1, 1, &rv);
+#endif
                if (zmsg && Z_TYPE_P(zmsg) == IS_STRING) {
                        lua_pushlstring(L, Z_STRVAL_P(zmsg), Z_STRLEN_P(zmsg));
                } else {
@@ -1699,8 +1881,13 @@
 
        lua_dump(L, luasandbox_dump_writer, (void*)&buf);
        smart_str_0(&buf);
+#if PHP_VERSION_ID < 70000
        if (buf.len) {
                RETURN_STRINGL(buf.c, buf.len, 0);
+#else
+       if (buf.s) {
+               RETURN_STR(buf.s);
+#endif
        } else {
                smart_str_free(&buf);
                RETURN_EMPTY_STRING();
diff --git a/luasandbox_types.h b/luasandbox_types.h
index a5e5a4c..e437f9f 100644
--- a/luasandbox_types.h
+++ b/luasandbox_types.h
@@ -77,7 +77,11 @@
        php_luasandbox_alloc alloc;
        int in_php;
        int in_lua;
+#if PHP_VERSION_ID < 70000
        zval * current_zval; /* The zval for the LuaSandbox which is currently 
executing Lua code */
+#else
+       zval current_zval; /* The zval for the LuaSandbox which is currently 
executing Lua code */
+#endif
        volatile int timed_out;
        int is_cpu_limited;
        luasandbox_timer_set timer;
@@ -89,10 +93,29 @@
 
 struct _php_luasandboxfunction_obj {
        zend_object std;
+#if PHP_VERSION_ID < 70000
        zval * sandbox;
+#else
+       zval sandbox;
+#endif
        int index;
 };
 typedef struct _php_luasandboxfunction_obj php_luasandboxfunction_obj;
 
+// Accessor macros
+#if PHP_VERSION_ID < 70000
+#define GET_LUASANDBOX_OBJ(z) (php_luasandbox_obj 
*)zend_object_store_get_object(z TSRMLS_CC)
+#define GET_LUASANDBOXFUNCTION_OBJ(z) (php_luasandboxfunction_obj 
*)zend_object_store_get_object(z TSRMLS_CC)
+#define LUASANDBOXFUNCTION_SANDBOX_IS_OK(pfunc) (pfunc)->sandbox
+#define LUASANDBOXFUNCTION_GET_SANDBOX_ZVALPTR(pfunc) (pfunc)->sandbox
+#define LUASANDBOX_GET_CURRENT_ZVAL_PTR(psandbox) (psandbox)->current_zval
+#else
+#define GET_LUASANDBOX_OBJ(z) (php_luasandbox_obj *)Z_OBJ_P(z)
+#define GET_LUASANDBOXFUNCTION_OBJ(z) (php_luasandboxfunction_obj *)Z_OBJ_P(z)
+#define LUASANDBOXFUNCTION_SANDBOX_IS_OK(pfunc) !Z_ISUNDEF((pfunc)->sandbox)
+#define LUASANDBOXFUNCTION_GET_SANDBOX_ZVALPTR(pfunc) &((pfunc)->sandbox)
+#define LUASANDBOX_GET_CURRENT_ZVAL_PTR(psandbox) &((psandbox)->current_zval)
+#endif
+
 #endif /*LUASANDBOX_TYPES_H*/
 
diff --git a/tests/datatypes.phpt b/tests/datatypes.phpt
new file mode 100644
index 0000000..50443dd
--- /dev/null
+++ b/tests/datatypes.phpt
@@ -0,0 +1,55 @@
+--TEST--
+Data type round-tripping
+--FILE--
+<?php
+
+function doTest( $test, $data ) {
+       printf( "%-25s ", "$test:" );
+
+       $sandbox = new LuaSandbox;
+       $sandbox->setMemoryLimit( 100000 );
+       $sandbox->setCPULimit( 0.1 );
+       try {
+               $ret = $sandbox->loadString( 'return ...' )->call( $data );
+               printf( "%s\n", preg_replace( '/\s+/', ' ', var_export( 
$ret[0], 1 ) ) );
+       } catch ( LuaSandboxError $e ) {
+               printf( "EXCEPTION: %s\n", $e->getMessage() );
+       }
+}
+
+doTest( 'null', null );
+doTest( 'int', 123 );
+doTest( 'long', 17179869184 );
+doTest( 'double', 3.125 );
+doTest( 'NAN', NAN );
+doTest( 'INF', INF );
+doTest( 'true', true );
+doTest( 'false', false );
+doTest( 'string', 'foobar' );
+doTest( 'empty string', '' );
+doTest( 'string containing NULs', "foo\0bar" );
+doTest( 'array', array( 'foo', 'bar' ) );
+doTest( 'associative array', array( 'foo', 'bar' => 'baz' ) );
+doTest( 'object', (object)array( 'foo' => 1, 'bar' => 'baz' ) );
+doTest( 'object with numeric keys', (object)array( 'foo', 'bar' ) );
+
+$var = 42;
+doTest( 'array with reference', [ &$var ] );
+
+--EXPECT--
+null:                     NULL
+int:                      123
+long:                     17179869184
+double:                   3.125
+NAN:                      NAN
+INF:                      INF
+true:                     true
+false:                    false
+string:                   'foobar'
+empty string:             ''
+string containing NULs:   'foo' . "\0" . 'bar'
+array:                    array ( 1 => 'bar', 0 => 'foo', )
+associative array:        array ( 0 => 'foo', 'bar' => 'baz', )
+object:                   array ( 'bar' => 'baz', 'foo' => 1, )
+object with numeric keys: array ( 1 => 'bar', 0 => 'foo', )
+array with reference:     array ( 0 => 42, )
diff --git a/timer.c b/timer.c
index 98494e6..b6baf67 100644
--- a/timer.c
+++ b/timer.c
@@ -239,13 +239,29 @@
        }
 
        lua_getupvalue(L, -1, 1);
+#if PHP_VERSION_ID < 70000
        zval ** callback_pp = (zval**)lua_touserdata(L, -1);
        if (!callback_pp || !*callback_pp) {
                return NULL;
        }
        char * callback_name;
-       if (zend_is_callable(*callback_pp, IS_CALLABLE_CHECK_SILENT, 
&callback_name TSRMLS_CC)) {
-               snprintf(buffer, sizeof(buffer), "%s", callback_name);
+       zend_bool ok = zend_is_callable(*callback_pp, IS_CALLABLE_CHECK_SILENT, 
&callback_name TSRMLS_CC);
+#else
+       zval * callback_p = (zval*)lua_touserdata(L, -1);
+       if (!callback_p) {
+               return NULL;
+       }
+       zend_string * callback_name;
+       zend_bool ok = zend_is_callable(callback_p, IS_CALLABLE_CHECK_SILENT, 
&callback_name);
+#endif
+       if (ok) {
+               snprintf(buffer, sizeof(buffer), "%s",
+#if PHP_VERSION_ID < 70000
+                       callback_name
+#else
+                       ZSTR_VAL(callback_name)
+#endif
+               );
                return buffer;
        } else {
                return NULL;
@@ -282,7 +298,14 @@
        if (name) {
                prof_name_size += strlen(name);
        }
+
+#if PHP_VERSION_ID < 70000
        char prof_name[prof_name_size];
+#else
+       zend_string *zstr = zend_string_alloc(prof_name_size, 0);
+       char *prof_name = ZSTR_VAL(zstr);
+#endif
+
        if (!name) {
                if (ar->linedefined > 0) {
                        snprintf(prof_name, prof_name_size, "<%s:%d>", 
ar->short_src, ar->linedefined);
@@ -298,11 +321,13 @@
                        snprintf(prof_name, prof_name_size, "%s", name);
                }
        }
+
+       luasandbox_timer_set * lts = &sandbox->timer;
+       HashTable * ht = lts->function_counts;
+#if PHP_VERSION_ID < 70000
        // Key length in zend_hash conventionally includes the null byte
        uint key_length = (uint)strlen(prof_name) + 1;
        ulong h = zend_inline_hash_func(prof_name, key_length);
-       luasandbox_timer_set * lts = &sandbox->timer;
-       HashTable * ht = lts->function_counts;
        size_t * elt;
        if (SUCCESS == zend_hash_quick_find(ht, prof_name, key_length, h, 
(void**)&elt)) {
                (*elt) += signal_count;
@@ -310,6 +335,18 @@
                size_t init = signal_count;
                zend_hash_quick_add(ht, prof_name, key_length, h, 
(void**)&init, sizeof(size_t), NULL);
        }
+#else
+       ZSTR_LEN(zstr) = strlen(prof_name);
+       zval *elt = zend_hash_find(ht, zstr);
+       if (elt != NULL) {
+               ZVAL_LONG(elt, Z_LVAL_P(elt) + signal_count);
+       } else {
+               zval v;
+               ZVAL_LONG(&v, signal_count);
+               zend_hash_add(ht, zstr, &v);
+       }
+       zend_string_release(zstr);
+#endif
 
        lts->total_count += signal_count;
 }

-- 
To view, visit https://gerrit.wikimedia.org/r/298312
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I34ba41ace1f8ff14371a116e0d2880f4e7cf58c5
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

Reply via email to