Fix C pre-processor bindings for values, PHP5 bugs

This commit is contained in:
Alex Palaistras 2016-05-09 13:22:10 +01:00
parent ca3030252f
commit e414904c5b
11 changed files with 220 additions and 143 deletions

View File

@ -64,17 +64,17 @@ void context_exec(engine_context *context, char *filename) {
}
void *context_eval(engine_context *context, char *script) {
zval str, tmp;
zval *str = _value_init();
_value_set_string(&str, script);
// Compile script value.
uint32_t compiler_options = CG(compiler_options);
VALUE_SET_STRING(&str, script);
CG(compiler_options) = ZEND_COMPILE_DEFAULT_FOR_EVAL;
zend_op_array *op = zend_compile_string(&str, "gophp-engine");
zend_op_array *op = zend_compile_string(str, "gophp-engine");
CG(compiler_options) = compiler_options;
zval_dtor(&str);
zval_dtor(str);
// Return error if script failed to compile.
if (!op) {
@ -83,6 +83,7 @@ void *context_eval(engine_context *context, char *script) {
}
// Attempt to execute compiled string.
zval tmp;
_context_eval(op, &tmp);
// Allocate result value and copy temporary execution result in.

View File

@ -5,53 +5,17 @@
#ifndef ___VALUE_H___
#define ___VALUE_H___
#define CASE_BOOL IS_BOOL
#define VALUE_TRUTH(v) (Z_BVAL_P(v))
zval *_value_init();
void _value_destroy(engine_value *val);
#define VALUE_SET_STRING(z, s) ZVAL_STRING(z, s, 1);
int _value_truth(zval *val);
void _value_set_string(zval **val, char *str);
#define VALUE_INIT(v) do { \
MAKE_STD_ZVAL(v); \
ZVAL_NULL(v); \
} while (0)
static int _value_current_key_get(HashTable *ht, char **str_index, ulong *num_index);
static void _value_current_key_set(HashTable *ht, engine_value *val);
#define HASH_GET_CURRENT_KEY(h, k, i) zend_hash_get_current_key(h, k, i, 0)
#define HASH_SET_CURRENT_KEY(h, v) do { \
zval *t; \
MAKE_STD_ZVAL(t); \
zend_hash_get_current_key_zval(h, t); \
add_next_index_zval(v, t); \
} while (0)
static void _value_array_next_get(HashTable *ht, engine_value *val);
static void _value_array_index_get(HashTable *ht, unsigned long index, engine_value *val);
static void _value_array_key_get(HashTable *ht, char *key, engine_value *val);
#define VALUE_ARRAY_NEXT_GET(h, v) do { \
zval **t = NULL; \
if (zend_hash_get_current_data(h, (void **) &t) == SUCCESS) { \
value_set_zval(v, *t); \
zend_hash_move_forward(h); \
} \
return v; \
} while (0)
#define VALUE_ARRAY_INDEX_GET(h, i, v) do { \
zval **t = NULL; \
if (zend_hash_index_find(h, i, (void **) &t) == SUCCESS) { \
value_set_zval(v, *t); \
} \
return v; \
} while (0)
#define VALUE_ARRAY_KEY_GET(h, k, v) do { \
zval **t = NULL; \
if (zend_hash_find(h, k, strlen(k) + 1, (void **) &t) == SUCCESS) { \
value_set_zval(v, *t); \
} \
return v; \
} while (0)
// Destroy and free engine value.
static inline void value_destroy(engine_value *val) {
zval_dtor(val->internal);
free(val);
}
#endif
#endif

View File

@ -5,55 +5,17 @@
#ifndef ___VALUE_H___
#define ___VALUE_H___
#define CASE_BOOL IS_TRUE: case IS_FALSE
#define VALUE_TRUTH(v) (Z_TYPE_P(v) == IS_TRUE)
zval *_value_init();
void _value_destroy(engine_value *val);
#define VALUE_SET_STRING(z, s) ZVAL_STRING(z, s);
int _value_truth(zval *val);
void _value_set_string(zval **val, char *str);
#define VALUE_INIT(v) do { \
(v) = malloc(sizeof(zval)); \
ZVAL_NULL(v); \
} while (0)
static int _value_current_key_get(HashTable *ht, zend_string **str_index, zend_ulong *num_index);
static void _value_current_key_set(HashTable *ht, engine_value *val);
#define HASH_GET_CURRENT_KEY(h, k, i) zend_hash_get_current_key(h, k, i)
#define HASH_SET_CURRENT_KEY(h, v) do { \
zval t; \
zend_hash_get_current_key_zval(h, &t); \
add_next_index_zval(v, &t); \
} while (0)
static void _value_array_next_get(HashTable *ht, engine_value *val);
static void _value_array_index_get(HashTable *ht, unsigned long index, engine_value *val);
static void _value_array_key_get(HashTable *ht, char *key, engine_value *val);
#define VALUE_ARRAY_NEXT_GET(h, v) do { \
zval *t = NULL; \
if ((t = zend_hash_get_current_data(h)) != NULL) { \
value_set_zval(v, t); \
zend_hash_move_forward(h); \
} \
return v; \
} while (0)
#define VALUE_ARRAY_INDEX_GET(h, i, v) do { \
zval *t = NULL; \
if ((t = zend_hash_index_find(h, i)) != NULL) { \
value_set_zval(v, t); \
} \
return v; \
} while (0)
#define VALUE_ARRAY_KEY_GET(h, k, v) do { \
zval *t = NULL; \
zend_string *s = zend_string_init(k, strlen(k), 0); \
if ((t = zend_hash_find(h, s)) != NULL) { \
value_set_zval(v, t); \
} \
zend_string_release(s); \
return v; \
} while (0)
// Destroy and free engine value.
static inline void value_destroy(engine_value *val) {
zval_dtor(val->internal);
free(val->internal);
free(val);
}
#endif
#endif

View File

@ -21,12 +21,8 @@ enum {
KIND_OBJECT
};
static inline void value_copy(zval *dst, zval *src) {
ZVAL_COPY_VALUE(dst, src);
zval_copy_ctor(dst);
}
engine_value *value_new();
void value_copy(zval *dst, zval *src);
int value_kind(engine_value *val);
void value_set_null(engine_value *val);
@ -57,4 +53,4 @@ engine_value *value_array_key_get(engine_value *arr, char *key);
#include "_value.h"
#endif
#endif

View File

@ -43,7 +43,7 @@ static int receiver_exists(zval *object, zval *member, int check) {
if (check == 1) {
// Value exists and is "truthy".
convert_to_boolean(val->internal);
result = VALUE_TRUTH(val->internal) ? 1 : 0;
result = _value_truth(val->internal);
} else if (check == 0) {
// Value exists and is not null.
result = (val->kind != KIND_NULL) ? 1 : 0;
@ -52,7 +52,7 @@ static int receiver_exists(zval *object, zval *member, int check) {
result = 0;
}
value_destroy(val);
_value_destroy(val);
return result;
}
@ -71,7 +71,7 @@ static int receiver_method_call(char *name, INTERNAL_FUNCTION_PARAMETERS) {
RETVAL_NULL();
} else {
value_copy(return_value, result->internal);
value_destroy(result);
_value_destroy(result);
}
}

View File

@ -13,7 +13,7 @@ static zval *_receiver_get(zval *object, zval *member, int type, const zend_lite
}
value_copy(retval, result->internal);
value_destroy(result);
_value_destroy(result);
return retval;
}
@ -54,14 +54,14 @@ static void _receiver_free(void *object) {
// Initialize instance of method receiver object. The method receiver itself is
// attached in the constructor function call.
static zend_object_value *_receiver_init(zend_class_entry *class_type) {
static zend_object_value _receiver_init(zend_class_entry *class_type) {
engine_receiver *this = emalloc(sizeof(engine_receiver));
memset(this, 0, sizeof(engine_receiver));
zend_object_std_init(&this->obj, class_type);
zend_object_value object;
object.handle = zend_objects_store_put(this, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) receiver_free, NULL);
object.handle = zend_objects_store_put(this, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) _receiver_free, NULL);
object.handlers = &receiver_handlers;
return object;
@ -83,8 +83,8 @@ static engine_receiver *_receiver_this(zval *object) {
static void _receiver_handlers_set(zend_object_handlers *handlers) {
zend_object_handlers *std = zend_get_std_object_handlers();
handlers.get_class_name = std->get_class_name;
handlers.get_class_entry = std->get_class_entry;
handlers->get_class_name = std->get_class_name;
handlers->get_class_entry = std->get_class_entry;
}
// Return class name for method receiver.

63
engine/src/php5/_value.c Normal file
View File

@ -0,0 +1,63 @@
// Copyright 2016 Alexander Palaistras. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.
zval *_value_init() {
zval *tmp = NULL;
MAKE_STD_ZVAL(tmp);
ZVAL_NULL(tmp);
return tmp;
}
// Destroy and free engine value.
void _value_destroy(engine_value *val) {
zval_dtor(val->internal);
free(val);
}
int _value_truth(zval *val) {
return (Z_TYPE_P(val) != IS_BOOL) ? -1 : ((Z_BVAL_P(val)) ? 1 : 0);
}
void _value_set_string(zval **val, char *str) {
ZVAL_STRING(*val, str, 1);
}
static int _value_current_key_get(HashTable *ht, char **str_index, ulong *num_index) {
return zend_hash_get_current_key(ht, str_index, num_index, 0);
}
static void _value_current_key_set(HashTable *ht, engine_value *val) {
zval *tmp;
MAKE_STD_ZVAL(tmp);
zend_hash_get_current_key_zval(ht, tmp);
add_next_index_zval(val->internal, tmp);
}
static void _value_array_next_get(HashTable *ht, engine_value *val) {
zval **tmp = NULL;
if (zend_hash_get_current_data(ht, (void **) &tmp) == SUCCESS) {
value_set_zval(val, *tmp);
zend_hash_move_forward(ht);
}
}
static void _value_array_index_get(HashTable *ht, unsigned long index, engine_value *val) {
zval **tmp = NULL;
if (zend_hash_index_find(ht, index, (void **) &tmp) == SUCCESS) {
value_set_zval(val, *tmp);
}
}
static void _value_array_key_get(HashTable *ht, char *key, engine_value *val) {
zval **tmp = NULL;
if (zend_hash_find(ht, key, strlen(key) + 1, (void **) &tmp) == SUCCESS) {
value_set_zval(val, *tmp);
}
}

View File

@ -10,7 +10,7 @@ static zval *_receiver_get(zval *object, zval *member, int type, void **cache_sl
}
value_copy(retval, result->internal);
value_destroy(result);
_value_destroy(result);
return retval;
}

64
engine/src/php7/_value.c Normal file
View File

@ -0,0 +1,64 @@
// Copyright 2016 Alexander Palaistras. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.
zval *_value_init() {
zval *tmp = malloc(sizeof(zval));
ZVAL_NULL(tmp);
return tmp;
}
// Destroy and free engine value.
void _value_destroy(engine_value *val) {
zval_dtor(val->internal);
free(val->internal);
free(val);
}
int _value_truth(zval *val) {
return (Z_TYPE_P(val) == IS_TRUE) ? 1 : ((Z_TYPE_P(val) == IS_FALSE) ? 0 : -1);
}
void _value_set_string(zval **val, char *str) {
ZVAL_STRING(*val, str);
}
static int _value_current_key_get(HashTable *ht, zend_string **str_index, zend_ulong *num_index) {
return zend_hash_get_current_key(ht, str_index, num_index);
}
static void _value_current_key_set(HashTable *ht, engine_value *val) {
zval tmp;
zend_hash_get_current_key_zval(ht, &tmp);
add_next_index_zval(val->internal, &tmp);
}
static void _value_array_next_get(HashTable *ht, engine_value *val) {
zval *tmp = NULL;
if ((tmp = zend_hash_get_current_data(ht)) != NULL) {
value_set_zval(val, tmp);
zend_hash_move_forward(ht);
}
}
static void _value_array_index_get(HashTable *ht, unsigned long index, engine_value *val) {
zval *tmp = NULL;
if ((tmp = zend_hash_index_find(ht, index)) != NULL) {
value_set_zval(val, tmp);
}
}
static void _value_array_key_get(HashTable *ht, char *key, engine_value *val) {
zval *tmp = NULL;
zend_string *str = zend_string_init(key, strlen(key), 0);
if ((tmp = zend_hash_find(ht, str)) != NULL) {
value_set_zval(val, tmp);
}
zend_string_release(str);
}

View File

@ -16,13 +16,20 @@ engine_value *value_new() {
return NULL;
}
VALUE_INIT(val->internal);
val->internal = _value_init();
val->kind = KIND_NULL;
errno = 0;
return val;
}
// Creates a complete copy of a zval.
// The destination zval needs to be correctly initialized before use.
void value_copy(zval *dst, zval *src) {
ZVAL_COPY_VALUE(dst, src);
zval_copy_ctor(dst);
}
// Returns engine value type. Usually compared against KIND_* constants, defined
// in the `value.h` header file.
int value_kind(engine_value *val) {
@ -55,7 +62,7 @@ void value_set_bool(engine_value *val, bool status) {
// Set type and value to string.
void value_set_string(engine_value *val, char *str) {
VALUE_SET_STRING(val->internal, str);
_value_set_string(&val->internal, str);
val->kind = KIND_STRING;
}
@ -78,12 +85,21 @@ void value_set_zval(engine_value *val, zval *src) {
// Determine concrete type from source zval.
switch (Z_TYPE_P(src)) {
case IS_NULL: kind = KIND_NULL; break;
case IS_LONG: kind = KIND_LONG; break;
case IS_DOUBLE: kind = KIND_DOUBLE; break;
case CASE_BOOL: kind = KIND_BOOL; break;
case IS_STRING: kind = KIND_STRING; break;
case IS_OBJECT: kind = KIND_OBJECT; break;
case IS_NULL:
kind = KIND_NULL;
break;
case IS_LONG:
kind = KIND_LONG;
break;
case IS_DOUBLE:
kind = KIND_DOUBLE;
break;
case IS_STRING:
kind = KIND_STRING;
break;
case IS_OBJECT:
kind = KIND_OBJECT;
break;
case IS_ARRAY:
kind = KIND_ARRAY;
HashTable *h = (Z_ARRVAL_P(src));
@ -102,7 +118,7 @@ void value_set_zval(engine_value *val, zval *src) {
for (zend_hash_internal_pointer_reset(h); i < h->nNumOfElements; i++) {
unsigned long index;
int type = HASH_GET_CURRENT_KEY(h, NULL, &index);
int type = _value_current_key_get(h, NULL, &index);
if (type == HASH_KEY_IS_STRING || index != i) {
kind = KIND_MAP;
@ -114,6 +130,12 @@ void value_set_zval(engine_value *val, zval *src) {
break;
default:
// Booleans need special handling for different PHP versions.
if (_value_truth(src) != -1) {
kind = KIND_BOOL;
break;
}
errno = 1;
return;
}
@ -176,13 +198,13 @@ bool value_get_bool(engine_value *val) {
// Return value directly if already in correct type.
if (val->kind == KIND_BOOL) {
return VALUE_TRUTH(val->internal);
return _value_truth(val->internal);
}
value_copy(&tmp, val->internal);
convert_to_boolean(&tmp);
return VALUE_TRUTH(&tmp);
return _value_truth(&tmp);
}
char *value_get_string(engine_value *val) {
@ -251,7 +273,7 @@ engine_value *value_array_keys(engine_value *arr) {
unsigned long i = 0;
for (zend_hash_internal_pointer_reset(h); i < h->nNumOfElements; i++) {
HASH_SET_CURRENT_KEY(h, keys->internal);
_value_current_key_set(h, keys);
zend_hash_move_forward(h);
}
@ -286,16 +308,16 @@ void value_array_reset(engine_value *arr) {
}
engine_value *value_array_next_get(engine_value *arr) {
HashTable *h = NULL;
HashTable *ht = NULL;
engine_value *val = value_new();
switch (arr->kind) {
case KIND_ARRAY:
case KIND_MAP:
h = Z_ARRVAL_P(arr->internal);
ht = Z_ARRVAL_P(arr->internal);
break;
case KIND_OBJECT:
h = Z_OBJPROP_P(arr->internal);
ht = Z_OBJPROP_P(arr->internal);
break;
default:
// Attempting to return the next index of a non-array value will return
@ -305,20 +327,21 @@ engine_value *value_array_next_get(engine_value *arr) {
return val;
}
VALUE_ARRAY_NEXT_GET(h, val);
_value_array_next_get(ht, val);
return val;
}
engine_value *value_array_index_get(engine_value *arr, unsigned long idx) {
HashTable *h = NULL;
HashTable *ht = NULL;
engine_value *val = value_new();
switch (arr->kind) {
case KIND_ARRAY:
case KIND_MAP:
h = Z_ARRVAL_P(arr->internal);
ht = Z_ARRVAL_P(arr->internal);
break;
case KIND_OBJECT:
h = Z_OBJPROP_P(arr->internal);
ht = Z_OBJPROP_P(arr->internal);
break;
default:
// Attempting to return the first index of a non-array value will return
@ -332,24 +355,28 @@ engine_value *value_array_index_get(engine_value *arr, unsigned long idx) {
return val;
}
VALUE_ARRAY_INDEX_GET(h, idx, val);
_value_array_index_get(ht, idx, val);
return val;
}
engine_value *value_array_key_get(engine_value *arr, char *key) {
HashTable *h = NULL;
HashTable *ht = NULL;
engine_value *val = value_new();
switch (arr->kind) {
case KIND_ARRAY:
case KIND_MAP:
h = Z_ARRVAL_P(arr->internal);
ht = Z_ARRVAL_P(arr->internal);
break;
case KIND_OBJECT:
h = Z_OBJPROP_P(arr->internal);
ht = Z_OBJPROP_P(arr->internal);
break;
default:
return val;
}
VALUE_ARRAY_KEY_GET(h, key, val);
}
_value_array_key_get(ht, key, val);
return val;
}
#include "_value.c"

View File

@ -87,7 +87,7 @@ func NewValue(val interface{}) (*Value, error) {
for i := 0; i < v.Len(); i++ {
vs, err := NewValue(v.Index(i).Interface())
if err != nil {
C.value_destroy(ptr)
C._value_destroy(ptr)
return nil, err
}
@ -103,7 +103,7 @@ func NewValue(val interface{}) (*Value, error) {
for _, key := range v.MapKeys() {
kv, err := NewValue(v.MapIndex(key).Interface())
if err != nil {
C.value_destroy(ptr)
C._value_destroy(ptr)
return nil, err
}
@ -132,7 +132,7 @@ func NewValue(val interface{}) (*Value, error) {
fv, err := NewValue(v.Field(i).Interface())
if err != nil {
C.value_destroy(ptr)
C._value_destroy(ptr)
return nil, err
}
@ -144,7 +144,7 @@ func NewValue(val interface{}) (*Value, error) {
case reflect.Invalid:
C.value_set_null(ptr)
default:
C.value_destroy(ptr)
C._value_destroy(ptr)
return nil, fmt.Errorf("Unable to create value of unknown type '%T'", val)
}
@ -278,6 +278,6 @@ func (v *Value) Destroy() {
return
}
C.value_destroy(v.value)
C._value_destroy(v.value)
v.value = nil
}