From 756a2c4350162a9a7f930bdc0ec7718ff13ea48c Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Fri, 11 Dec 2015 18:14:19 +0100 Subject: [PATCH] flush --- php_psi.h | 84 +++++++++++++++++++++++++++ psi.d/stat.psi | 2 +- psi.d/time.psi | 12 ++-- psi.d/uname.psi | 2 +- src/context.c | 62 ++++++++++++++++++-- src/module.c | 145 ++++++++++++++++++++++++++++++++++++++++++---- src/parser.h | 8 +-- src/parser_proc.y | 3 +- 8 files changed, 288 insertions(+), 30 deletions(-) diff --git a/php_psi.h b/php_psi.h index 54d78b0..dd422b7 100644 --- a/php_psi.h +++ b/php_psi.h @@ -60,6 +60,90 @@ void psi_to_object(zval *return_value, set_value *set, impl_val *ret_val); void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl); +static inline int psi_calc_num_exp_value(num_exp *exp, impl_val *val) { + switch (exp->t) { + case PSI_T_NUMBER: + switch (is_numeric_string(exp->u.numb, strlen(exp->u.numb), (zend_long *) val, (double *) val, 0)) { + case IS_LONG: + return PSI_T_INT64; + case IS_DOUBLE: + return PSI_T_DOUBLE; + } + break; + + case PSI_T_NSNAME: + switch (exp->u.cnst->type->type) { + case PSI_T_INT: + val->i64 = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.lval; + return PSI_T_INT64; + case PSI_T_FLOAT: + val->dval = zend_get_constant_str(exp->u.cnst->name, strlen(exp->u.cnst->name))->value.dval; + return PSI_T_DOUBLE; + default: + return 0; + } + break; + + case PSI_T_NAME: + switch (real_decl_type(exp->u.dvar->arg->type)->type) { + case PSI_T_INT8: + case PSI_T_UINT8: + case PSI_T_INT16: + case PSI_T_UINT16: + case PSI_T_INT32: + case PSI_T_UINT32: + case PSI_T_INT64: + case PSI_T_UINT64: + memcpy(val, deref_impl_val(exp->u.dvar->arg->let->ptr, exp->u.dvar), sizeof(*val)); + return real_decl_type(exp->u.dvar->arg->type)->type; + + case PSI_T_FLOAT: + case PSI_T_DOUBLE: + memcpy(val, deref_impl_val(exp->u.dvar->arg->let->ptr, exp->u.dvar), sizeof(*val)); + return real_decl_type(exp->u.dvar->arg->type)->type; + + EMPTY_SWITCH_DEFAULT_CASE(); + } + break; + + EMPTY_SWITCH_DEFAULT_CASE(); + } + return 0; +} + +static inline int psi_calc_num_exp(num_exp *exp, impl_val *val) { + impl_val num = {0}; + int num_type = psi_calc_num_exp_value(exp, &num); + + if (exp->operand) { + impl_val tmp = {0}; + int tmp_type = psi_calc_num_exp(exp->operand, &tmp); + + return exp->calculator(num_type, &num, tmp_type, &tmp, val); + } + + memcpy(val, &num, sizeof(*val)); + return num_type; +} + +static inline zend_long psi_long_num_exp(num_exp *exp) { + impl_val val = {0}; + + switch (psi_calc_num_exp(exp, &val)) { + case PSI_T_UINT8: val.u16 = val.u8; + case PSI_T_UINT16: val.u32 = val.u16; + case PSI_T_UINT32: val.u64 = val.u32; + case PSI_T_UINT64: return val.u64; + case PSI_T_INT8: val.i16 = val.i8; + case PSI_T_INT16: val.i32 = val.i16; + case PSI_T_INT32: val.i64 = val.i32; + case PSI_T_INT64: return val.i64; + case PSI_T_FLOAT: val.dval = val.fval; + case PSI_T_DOUBLE: return val.dval; + EMPTY_SWITCH_DEFAULT_CASE(); + } +} + ZEND_BEGIN_MODULE_GLOBALS(psi) char *engine; char *directory; diff --git a/psi.d/stat.psi b/psi.d/stat.psi index 17dc188..dc89119 100644 --- a/psi.d/stat.psi +++ b/psi.d/stat.psi @@ -1,7 +1,7 @@ // extern int stat(char *path, struct stat *buf); function psi\stat(string $path, array &$buf = NULL) : int { let path = strval($path); - let buf = calloc(1, struct stat); + let buf = calloc(1, psi\SIZEOF_STRUCT_STAT); return to_int(stat); set $buf = to_array(*buf, to_int(st_dev), diff --git a/psi.d/time.psi b/psi.d/time.psi index a8082c6..ae16b0a 100644 --- a/psi.d/time.psi +++ b/psi.d/time.psi @@ -5,8 +5,8 @@ function psi\time() : int { // extern int gettimeofday(struct timeval *tp, struct timezone *tz); function psi\gettimeofday(array &$tv = NULL, array &$tz = NULL) : int { - let tp = calloc(1, struct timeval); - let tz = calloc(1, struct timezone); + let tp = calloc(1, psi\SIZEOF_STRUCT_TIMEVAL); + let tz = calloc(1, psi\SIZEOF_STRUCT_TIMEZONE); return to_int(gettimeofday); set $tv = to_array(*tp, to_int(tv_sec), @@ -25,7 +25,7 @@ function psi\asctime(array $tm = NULL) : string { // extern char *asctime_r(struct tm *tm, char *buf); function psi\asctime_r(array $tm = NULL) : string { let tm = arrval($tm); - let buf = calloc(32, char); + let buf = calloc(32, psi\SIZEOF_CHAR); return to_string(asctime_r); } @@ -48,7 +48,7 @@ function psi\gmtime(int $ts) : array { // extern struct tm *gmtime_r(time_t *t, struct tm *buf); function psi\gmtime_r(int $ts) : array { let t = &intval($ts); - let buf = calloc(1, struct tm); + let buf = calloc(1, psi\SIZEOF_STRUCT_TM); return to_array(*gmtime_r, to_int(tm_sec), to_int(tm_min), @@ -65,7 +65,7 @@ function psi\gmtime_r(int $ts) : array { // extern int nanosleep(struct timespec *rqts, struct timespec *rmts); function psi\nanosleep(array $rq = NULL, array &$rm = NULL) : int { let rqts = arrval($rq); - let rmts = calloc(1, struct timespec); + let rmts = calloc(1, psi\SIZEOF_STRUCT_TIMESPEC); return to_int(nanosleep); set $rm = to_array(*rmts, to_int(tv_sec), @@ -75,7 +75,7 @@ function psi\nanosleep(array $rq = NULL, array &$rm = NULL) : int { // extern clock_t times(struct tms *buf); function psi\times(array &$tms = NULL) : int { - let buf = calloc(1, struct tms); + let buf = calloc(1, psi\SIZEOF_STRUCT_TMS); return to_int(times); set $tms = to_array(*buf, to_int(tms_utime), diff --git a/psi.d/uname.psi b/psi.d/uname.psi index c79cc8e..6c6a6b0 100644 --- a/psi.d/uname.psi +++ b/psi.d/uname.psi @@ -1,5 +1,5 @@ function psi\uname(array &$u = NULL) : int { - let name = calloc(1, struct utsname); + let name = calloc(1, psi\SIZEOF_STRUCT_UTSNAME); return to_int(uname); set $u = to_array(*name, to_string(sysname), diff --git a/src/context.c b/src/context.c index 134acdd..1e8204a 100644 --- a/src/context.c +++ b/src/context.c @@ -548,6 +548,42 @@ static inline int validate_impl_ret_stmt(PSI_Data *data, impl *impl) { return 1; } +static inline constant *locate_num_exp_constant(num_exp *exp, constants *consts) { + size_t i; + + for (i = 0; i < consts->count; ++i) { + constant *cnst = consts->list[i]; + + if (!strcmp(cnst->name, exp->u.numb)) { + free(exp->u.numb); + return exp->u.cnst = cnst; + } + } + + return NULL; +} +static inline int validate_num_exp(PSI_Data *data, impl *impl, num_exp *exp) { + switch (exp->t) { + case PSI_T_NAME: + if (!locate_decl_var_arg(exp->u.dvar, impl->decl->args)) { + data->error(PSI_WARNING, "Unknown variable '%s' in numeric expression" + " of implementation '%s'", exp->u.dvar->name, impl->func->name); + return 0; + } + return 1; + case PSI_T_NSNAME: + if (!locate_num_exp_constant(exp, data->consts)) { + data->error(PSI_WARNING, "Unknown constant '%s' in numeric expression" + " of implementation '%s'", exp->u.numb, impl->func->name); + return 0; + } + return 1; + case PSI_T_NUMBER: + return 1; + default: + return 0; + } +} static inline int validate_impl_let_stmts(PSI_Data *data, impl *impl) { size_t i, j; /* we can have multiple let stmts */ @@ -579,9 +615,10 @@ static inline int validate_impl_let_stmts(PSI_Data *data, impl *impl) { int check = 0; if (let->val && let->val->func && let->val->func->alloc) { - if (!validate_decl_type(data, let->val->func->alloc->type)) { - data->error(PSI_WARNING, "Cannot use '%s' as type for calloc in `let` statement", - let->val->func->alloc->type->name); + if (!validate_num_exp(data, impl, let->val->func->alloc->nmemb)) { + return 0; + } + if (!validate_num_exp(data, impl, let->val->func->alloc->size)) { return 0; } } @@ -1095,6 +1132,20 @@ static inline void dump_impl_set_value(int fd, set_value *set, unsigned level) { dprintf(fd, ");\n"); } } +static inline void dump_num_exp(int fd, num_exp *exp) { + switch (exp->t) { + case PSI_T_NUMBER: + dprintf(fd, "%s", exp->u.numb); + break; + case PSI_T_NAME: + dump_decl_var(fd, exp->u.dvar); + break; + case PSI_T_NSNAME: + dprintf(fd, "%s", exp->u.cnst->name); + break; + EMPTY_SWITCH_DEFAULT_CASE(); + } +} void PSI_ContextDump(PSI_Context *C, int fd) { size_t i, j, k, l; @@ -1198,8 +1249,9 @@ void PSI_ContextDump(PSI_Context *C, int fd) if (let->val->func) { dprintf(fd, "%s(", let->val->func->name); if (let->val->func->alloc) { - dprintf(fd, "%zu, ", let->val->func->alloc->n); - dump_decl_type(fd, let->val->func->alloc->type); + dump_num_exp(fd, let->val->func->alloc->nmemb); + dprintf(fd, ", "); + dump_num_exp(fd, let->val->func->alloc->size); } else { dprintf(fd, "$%s", let->val->var->name); } diff --git a/src/module.c b/src/module.c index da623b2..873d56b 100644 --- a/src/module.c +++ b/src/module.c @@ -7,6 +7,8 @@ #include "php_ini.h" #include "ext/standard/info.h" #include "zend_exceptions.h" +#include "zend_constants.h" +#include "zend_operators.h" #include "php_psi.h" #include "parser.h" @@ -550,17 +552,10 @@ static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, i static inline void *psi_do_calloc(let_calloc *alloc) { - decl_type *type = real_decl_type(alloc->type); - size_t size; - - if (type->type == PSI_T_STRUCT) { - /* psi_do_clean expects at least one NULL pointer after the struct */ - size = type->strct->size + sizeof(void *); - } else { - size = psi_t_size(type->type); - } - - return ecalloc(alloc->n, size); + zend_long n = psi_long_num_exp(alloc->nmemb), s = psi_long_num_exp(alloc->size); + void *mem = safe_emalloc(n, s, sizeof(void *)); + memset(mem, 0, n * s + sizeof(void *)); + return mem; } static inline void *psi_do_let(decl_arg *darg) @@ -734,6 +729,134 @@ static inline void psi_do_clean(impl *impl) } } + +#define PSI_CALC_OP(var) res->var = PSI_CALC(v1->var, v2->var) +#define PSI_CALC_OP2(vres, var1, var2) res->vres = PSI_CALC(v1->var1, v2->var2) + +int psi_calc_plus(unsigned char t1, impl_val *v1, unsigned char t2, impl_val *v2, impl_val *res) +{ +#undef PSI_CALC +#define PSI_CALC(var1, var2) (var1) + (var2) + if (t1 == t2) { + switch (t1) { + case PSI_T_FLOAT: PSI_CALC_OP(fval); break; + case PSI_T_DOUBLE: PSI_CALC_OP(dval); break; + case PSI_T_INT8: PSI_CALC_OP(i8); break; + case PSI_T_UINT8: PSI_CALC_OP(u8); break; + case PSI_T_INT16: PSI_CALC_OP(i16); break; + case PSI_T_UINT16: PSI_CALC_OP(u16); break; + case PSI_T_INT32: PSI_CALC_OP(i32); break; + case PSI_T_UINT32: PSI_CALC_OP(u32); break; + case PSI_T_INT64: PSI_CALC_OP(i64); break; + case PSI_T_UINT64: PSI_CALC_OP(u64); break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + return t1; + } else if (t1 == PSI_T_DOUBLE) { + switch (t2) { + case PSI_T_FLOAT: PSI_CALC_OP2(dval, dval, fval); break; + case PSI_T_INT8: PSI_CALC_OP2(dval, dval, i8); break; + case PSI_T_UINT8: PSI_CALC_OP2(dval, dval, u8); break; + case PSI_T_INT16: PSI_CALC_OP2(dval, dval, i16); break; + case PSI_T_UINT16: PSI_CALC_OP2(dval, dval, u16); break; + case PSI_T_INT32: PSI_CALC_OP2(dval, dval, i32); break; + case PSI_T_UINT32: PSI_CALC_OP2(dval, dval, u32); break; + case PSI_T_INT64: PSI_CALC_OP2(dval, dval, i64); break; + case PSI_T_UINT64: PSI_CALC_OP2(dval, dval, u64); break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + return t1; + } else if (t2 == PSI_T_DOUBLE) { + switch (t1) { + case PSI_T_FLOAT: PSI_CALC_OP2(dval, fval, dval); break; + case PSI_T_INT8: PSI_CALC_OP2(dval, i8, dval); break; + case PSI_T_UINT8: PSI_CALC_OP2(dval, u8, dval); break; + case PSI_T_INT16: PSI_CALC_OP2(dval, i16, dval); break; + case PSI_T_UINT16: PSI_CALC_OP2(dval, u16, dval); break; + case PSI_T_INT32: PSI_CALC_OP2(dval, i32, dval); break; + case PSI_T_UINT32: PSI_CALC_OP2(dval, u32, dval); break; + case PSI_T_INT64: PSI_CALC_OP2(dval, i64, dval); break; + case PSI_T_UINT64: PSI_CALC_OP2(dval, u64, dval); break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + return t2; + } else if (t1 == PSI_T_FLOAT) { + switch (t2) { + case PSI_T_DOUBLE: PSI_CALC_OP2(dval, fval, dval); return t2; + case PSI_T_INT8: PSI_CALC_OP2(fval, fval, i8); break; + case PSI_T_UINT8: PSI_CALC_OP2(fval, fval, u8); break; + case PSI_T_INT16: PSI_CALC_OP2(fval, fval, i16); break; + case PSI_T_UINT16: PSI_CALC_OP2(fval, fval, u16); break; + case PSI_T_INT32: PSI_CALC_OP2(fval, fval, i32); break; + case PSI_T_UINT32: PSI_CALC_OP2(fval, fval, u32); break; + case PSI_T_INT64: PSI_CALC_OP2(fval, fval, i64); break; + case PSI_T_UINT64: PSI_CALC_OP2(fval, fval, u64); break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + return t1; + } else if (t2 == PSI_T_FLOAT) { + switch (t1) { + case PSI_T_DOUBLE: PSI_CALC_OP2(dval, dval, fval); return t1; + case PSI_T_INT8: PSI_CALC_OP2(fval, i8, fval); break; + case PSI_T_UINT8: PSI_CALC_OP2(fval, u8, fval); break; + case PSI_T_INT16: PSI_CALC_OP2(fval, i16, fval); break; + case PSI_T_UINT16: PSI_CALC_OP2(fval, u16, fval); break; + case PSI_T_INT32: PSI_CALC_OP2(fval, i32, fval); break; + case PSI_T_UINT32: PSI_CALC_OP2(fval, u32, fval); break; + case PSI_T_INT64: PSI_CALC_OP2(fval, i64, fval); break; + case PSI_T_UINT64: PSI_CALC_OP2(fval, u64, fval); break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + return t2; + } else { + int64_t sval1 = v1->i64, sval2 = v2->i64; + uint64_t uval1 = v1->u64, uval2 = v2->u64; + + switch (t1) { + case PSI_T_INT8: sval1 >>= 8; + case PSI_T_INT16: sval1 >>= 8; + case PSI_T_INT32: sval1 >>= 8; + case PSI_T_INT64: + switch (t2) { + case PSI_T_INT8: sval2 >>= 8; + case PSI_T_INT16: sval2 >>= 8; + case PSI_T_INT32: sval2 >>= 8; + case PSI_T_INT64: + res->i64 = PSI_CALC(sval1 , sval2); + return PSI_T_INT64; + case PSI_T_UINT8: uval2 >>= 8; + case PSI_T_UINT16: uval2 >>= 8; + case PSI_T_UINT32: uval2 >>= 8; + case PSI_T_UINT64: + res->i64 = PSI_CALC(sval1, uval2); + return PSI_T_INT64; + } + break; + case PSI_T_UINT8: uval1 >>= 8; + case PSI_T_UINT16: uval1 >>= 8; + case PSI_T_UINT32: uval1 >>= 8; + case PSI_T_UINT64: + switch (t2) { + case PSI_T_INT8: sval2 >>= 8; + case PSI_T_INT16: sval2 >>= 8; + case PSI_T_INT32: sval2 >>= 8; + case PSI_T_INT64: + res->i64 = PSI_CALC(uval1, sval2); + return PSI_T_INT64; + case PSI_T_UINT8: uval2 >>= 8; + case PSI_T_UINT16: uval2 >>= 8; + case PSI_T_UINT32: uval2 >>= 8; + case PSI_T_UINT64: + res->u64 = PSI_CALC(uval1, uval2); + return PSI_T_UINT64; + } + break; + } + } + ZEND_ASSERT(0); + return 0; +} + void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl) { impl_val ret_val; diff --git a/src/parser.h b/src/parser.h index faa95e4..28f436f 100644 --- a/src/parser.h +++ b/src/parser.h @@ -576,10 +576,11 @@ typedef struct num_exp { token_t t; union { char *numb; - char *cnst; + constant *cnst; decl_var *dvar; } u; token_t operator; + int (*calculator)(int t1, impl_val *v1, int t2, impl_val *v2, impl_val *res); struct num_exp *operand; } num_exp; @@ -587,10 +588,8 @@ static inline num_exp *init_num_exp(token_t t, void *num) { num_exp *exp = calloc(1, sizeof(*exp)); switch (exp->t = t) { case PSI_T_NUMBER: - exp->u.numb = strdup(num); - break; case PSI_T_NSNAME: - exp->u.cnst = strdup(num); + exp->u.numb = strdup(num); break; case PSI_T_NAME: exp->u.dvar = num; @@ -606,7 +605,6 @@ static inline void free_num_exp(num_exp *exp) { free(exp->u.numb); break; case PSI_T_NSNAME: - free(exp->u.cnst); break; case PSI_T_NAME: free_decl_var(exp->u.dvar); diff --git a/src/parser_proc.y b/src/parser_proc.y index 0a7259e..0dc928f 100644 --- a/src/parser_proc.y +++ b/src/parser_proc.y @@ -23,7 +23,8 @@ } %nonassoc NAME. -%left PLUS MINUS SLASH ASTERISK. +%left PLUS MINUS. +%left SLASH ASTERISK. %fallback NAME FREE SET LET RETURN LIB INT UNSIGNED. file ::= blocks. -- 2.30.2