From: Michael Wallner Date: Tue, 2 May 2017 15:55:50 +0000 (+0200) Subject: improved type validation X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-psi;a=commitdiff_plain;h=18ca609e4fa08a1c8fcdbb58e9aeb5fe55538b3c improved type validation --- diff --git a/src/data.c b/src/data.c index 9c2cefb..102c022 100644 --- a/src/data.c +++ b/src/data.c @@ -243,12 +243,15 @@ bool psi_data_validate(struct psi_data *dst, struct psi_data *src) struct psi_plist *check_enums = src->enums; unsigned flags = dst->flags; unsigned errors = src->errors; + struct psi_validate_stack type_stack; /* fail early if library is not found */ if (!psi_decl_file_validate(dst, src, &dlopened)) { return false; } + psi_validate_stack_ctor(&type_stack); + dst->flags |= PSI_SILENT; while (check_count) { @@ -293,13 +296,14 @@ bool psi_data_validate(struct psi_data *dst, struct psi_data *src) while (psi_plist_get(check_types, i++, &def)) { *dst->last_error = 0; + dst->types = psi_plist_add(dst->types, &def); PSI_DEBUG_PRINT(dst, "PSI: validate typedef %s ", def->var->name); - if (psi_decl_arg_validate_typedef(PSI_DATA(dst), def)) { + if (psi_decl_arg_validate_typedef(PSI_DATA(dst), def, &type_stack)) { PSI_DEBUG_PRINT(dst, "%s\n", "✔"); - dst->types = psi_plist_add(dst->types, &def); } else { PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error); recheck_types = psi_plist_add(recheck_types, &def); + psi_plist_pop(dst->types, NULL); } } } @@ -311,7 +315,7 @@ bool psi_data_validate(struct psi_data *dst, struct psi_data *src) *dst->last_error = 0; dst->structs = psi_plist_add(dst->structs, &str); PSI_DEBUG_PRINT(dst, "PSI: validate struct %s ", str->name); - if (psi_decl_struct_validate(PSI_DATA(dst), str)) { + if (psi_decl_struct_validate(PSI_DATA(dst), str, &type_stack)) { PSI_DEBUG_PRINT(dst, "%s ::(%zu, %zu)\n", "✔", str->align, str->size); } else { PSI_DEBUG_PRINT(dst, "%s (%s)\n", "✘", dst->last_error); @@ -328,7 +332,7 @@ bool psi_data_validate(struct psi_data *dst, struct psi_data *src) *dst->last_error = 0; dst->unions = psi_plist_add(dst->unions, &unn); PSI_DEBUG_PRINT(dst, "PSI: validate union %s ", unn->name); - if (psi_decl_union_validate(PSI_DATA(dst), unn)) { + if (psi_decl_union_validate(PSI_DATA(dst), unn, &type_stack)) { PSI_DEBUG_PRINT(dst, "%s ::(%zu, %zu)\n", "✔", unn->align, unn->size); } else { @@ -401,7 +405,7 @@ bool psi_data_validate(struct psi_data *dst, struct psi_data *src) while (psi_plist_get(src->decls, i++, &decl)) { *dst->last_error = 0; PSI_DEBUG_PRINT(dst, "PSI: validate decl %s ", decl->func->var->name); - if (psi_decl_validate(PSI_DATA(dst), decl, dlopened)) { + if (psi_decl_validate(PSI_DATA(dst), decl, dlopened, &type_stack)) { PSI_DEBUG_PRINT(dst, "%s\n", "✔"); dst->decls = psi_plist_add(dst->decls, &decl); } else { @@ -428,6 +432,8 @@ bool psi_data_validate(struct psi_data *dst, struct psi_data *src) } } + psi_validate_stack_dtor(&type_stack); + return true; } diff --git a/src/data.h b/src/data.h index 5356a7e..57bc5c5 100644 --- a/src/data.h +++ b/src/data.h @@ -70,4 +70,52 @@ bool psi_data_validate(struct psi_data *dst, struct psi_data *src); void psi_data_dtor(struct psi_data *data); void psi_data_dump(int fd, struct psi_data *data); +struct psi_validate_stack { + HashTable types; + HashTable structs; + HashTable unions; +}; + +static inline void psi_validate_stack_ctor(struct psi_validate_stack *stack) +{ + zend_hash_init(&stack->types, 0, NULL, NULL, 0); + zend_hash_init(&stack->structs, 0, NULL, NULL, 0); + zend_hash_init(&stack->unions, 0, NULL, NULL, 0); +} + +static inline void psi_validate_stack_dtor(struct psi_validate_stack *stack) +{ + zend_hash_destroy(&stack->types); + zend_hash_destroy(&stack->structs); + zend_hash_destroy(&stack->unions); +} + +#define psi_validate_stack_has_type(s, t) \ + ((s) ? zend_hash_str_exists(&(s)->types, (t), strlen(t)) : false) +#define psi_validate_stack_has_struct(s, t) \ + ((s) ? zend_hash_str_exists(&(s)->structs, (t), strlen(t)) : false) +#define psi_validate_stack_has_union(s, t) \ + ((s) ? zend_hash_str_exists(&(s)->unions, (t), strlen(t)) : false) + +#define psi_validate_stack_add_type(s, t, p) \ + do { if (s) zend_hash_str_add_ptr(&(s)->types, (t), strlen(t), (p)); } while(0) +#define psi_validate_stack_add_struct(s, t, p) \ + do { if (s) zend_hash_str_add_ptr(&(s)->structs, (t), strlen(t), (p)); } while(0) +#define psi_validate_stack_add_union(s, t, p) \ + do { if (s) zend_hash_str_add_ptr(&(s)->unions, (t), strlen(t), (p)); } while(0) + +#define psi_validate_stack_get_type(s, t) \ + ((s) ? zend_hash_str_find_ptr(&(s)->types, (t), strlen(t)) : NULL) +#define psi_validate_stack_get_struct(s, t) \ + ((s) ? zend_hash_str_find_ptr(&(s)->structs, (t), strlen(t)) : NULL) +#define psi_validate_stack_get_union(s, t) \ + ((s) ? zend_hash_str_find_ptr(&(s)->unions, (t), strlen(t)) : NULL) + +#define psi_validate_stack_del_type(s, t) \ + do { if (s) zend_hash_str_del(&(s)->types, (t), strlen(t)); } while(0) +#define psi_validate_stack_del_struct(s, t) \ + do { if (s) zend_hash_str_del(&(s)->structs, (t), strlen(t)); } while(0) +#define psi_validate_stack_del_union(s, t) \ + do { if (s) zend_hash_str_del(&(s)->unions, (t), strlen(t)); } while(0) + #endif diff --git a/src/marshal.c b/src/marshal.c index e7ffc67..fcd107f 100644 --- a/src/marshal.c +++ b/src/marshal.c @@ -154,7 +154,7 @@ void psi_set_void(zval *return_value, struct psi_set_exp *set, impl_val *ret_val /* * ? */ -impl_val *psi_let_void(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) +impl_val *psi_let_void(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) { return tmp; } @@ -169,7 +169,7 @@ void psi_set_zval(zval *return_value, struct psi_set_exp *set, impl_val *ret_val /* * let dvar = zval($ivar) */ -impl_val *psi_let_zval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) +impl_val *psi_let_zval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) { *to_free = tmp->ptr = emalloc(sizeof(zval)); ZVAL_COPY_VALUE(tmp->ptr, zvalue); @@ -208,10 +208,10 @@ static inline impl_val *psi_val_boolval(impl_val *tmp, token_t real_type, zend_b /* * let dvar = boolval($ivar) */ -impl_val *psi_let_boolval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) +impl_val *psi_let_boolval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) { zend_bool boolval; - token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_UINT8; + token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_UINT8; if (ival && impl_type == PSI_T_BOOL) { boolval = ival->zend.bval; @@ -248,15 +248,22 @@ void psi_set_to_int(zval *return_value, struct psi_set_exp *set, impl_val *ret_v case PSI_T_UINT32: RETVAL_LONG(v->u32); break; case PSI_T_INT64: RETVAL_LONG(v->i64); break; case PSI_T_UINT64: RETVAL_LONG_U64(v->u64); break; - case PSI_T_FLOAT: RETVAL_DOUBLE((double) v->fval); break; - case PSI_T_DOUBLE: RETVAL_DOUBLE(v->dval); break; + case PSI_T_FLOAT: + RETVAL_DOUBLE((double) v->fval); + convert_to_long(return_value); + break; + case PSI_T_DOUBLE: + RETVAL_DOUBLE(v->dval); + convert_to_long(return_value); + break; #ifdef HAVE_LONG_DOUBLE - case PSI_T_LONG_DOUBLE: RETVAL_DOUBLE((double) v->ldval); break; + case PSI_T_LONG_DOUBLE: + RETVAL_DOUBLE((double) v->ldval); + convert_to_long(return_value); + break; #endif EMPTY_SWITCH_DEFAULT_CASE(); } - - convert_to_long(return_value); } static inline impl_val *psi_val_intval(impl_val *tmp, token_t real_type, zend_long intval) { @@ -285,10 +292,10 @@ static inline impl_val *psi_val_intval(impl_val *tmp, token_t real_type, zend_lo /* * let dvar = intval($ivar) */ -impl_val *psi_let_intval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) +impl_val *psi_let_intval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) { zend_long intval; - token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_LONG; + token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_LONG; if (ival && impl_type == PSI_T_INT) { intval = ival->zend.lval; @@ -350,10 +357,10 @@ static inline impl_val *psi_val_floatval(impl_val *tmp, token_t real_type, doubl /* * let dvar = floatval($ivar) */ -impl_val *psi_let_floatval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) +impl_val *psi_let_floatval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) { double floatval; - token_t real_type = spec ? psi_decl_type_get_real(spec)->type : PSI_T_DOUBLE; + token_t real_type = spec ? psi_decl_type_get_real(spec->type)->type : PSI_T_DOUBLE; if (ival && (impl_type == PSI_T_FLOAT || impl_type == PSI_T_DOUBLE)) { floatval = ival->dval; @@ -407,7 +414,7 @@ void psi_set_to_stringl(zval *return_value, struct psi_set_exp *set, impl_val *r /* * let dvar = strval($ivar) */ -impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) +impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) { if (ival && impl_type == PSI_T_STRING) { if (ival->zend.str) { @@ -428,7 +435,7 @@ impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_type *spec, token_t impl /* * let dvar = pathval($ivar) */ -impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) +impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) { tmp = psi_let_strval(tmp, spec, impl_type, ival, zvalue, to_free); if (SUCCESS != php_check_open_basedir(tmp->ptr)) { @@ -442,7 +449,7 @@ impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_type *spec, token_t imp /* * let dvar = strlen($ivar) */ -impl_val *psi_let_strlen(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) +impl_val *psi_let_strlen(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) { if (ival && impl_type == PSI_T_STRING) { if (ival->zend.str) { @@ -580,49 +587,12 @@ void psi_set_to_array(zval *return_value, struct psi_set_exp *set, impl_val *r_v } } -//impl_val *psi_let_arrval(impl_val *tmp, decl_type *spec, decl_var *spec_var, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) -//{ -// decl_type *real = real_decl_type(spec); -// HashTable *arr; -// zval *zv; -// size_t i, sz; -// decl_arg tmp_arg = {0}; -// -// if (impl_type != PSI_T_ARRAY) { -// SEPARATE_ARG_IF_REF(zvalue); -// convert_to_array(zvalue); -// } -// arr = HASH_OF(zvalue); -// -// switch (real->type) { -// case PSI_T_STRUCT: -// *to_free = tmp = psi_array_to_struct(real->real.strct, arr); -// break; -// case PSI_T_UNION: -// *to_free = tmp = psi_array_to_union(real->real.unn, arr); -// break; -// default: -// sz = psi_t_size(real->type); -// tmp = *to_free = ecalloc(zend_hash_num_elements(arr), sz); -// tmp_arg.type = spec; -// tmp_arg.var = spec_var; -// ZEND_HASH_FOREACH_VAL_IND(arr, zv) -// { -// void *ptr = ((char *) tmp) + (i++ * sz); -// psi_from_zval_ex(NULL, (impl_val **) &ptr, &tmp_arg, 0, zv, NULL); -// } -// ZEND_HASH_FOREACH_END(); -// } -// -// return tmp; -//} - /* * let dvar = count($ivar) */ -impl_val *psi_let_count(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) +impl_val *psi_let_count(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) { - return psi_val_intval(tmp, psi_decl_type_get_real(spec)->type, psi_zval_count(zvalue)); + return psi_val_intval(tmp, psi_decl_type_get_real(spec->type)->type, psi_zval_count(zvalue)); } /* @@ -644,7 +614,7 @@ void psi_set_to_object(zval *return_value, struct psi_set_exp *set, impl_val *r_ /* * let dvar = objval($ivar) */ -impl_val *psi_let_objval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) +impl_val *psi_let_objval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free) { psi_object *obj; diff --git a/src/marshal.h b/src/marshal.h index 8067fb3..be5b3c6 100644 --- a/src/marshal.h +++ b/src/marshal.h @@ -31,7 +31,7 @@ struct psi_let_exp; struct psi_set_exp; -struct psi_decl_type; +struct psi_decl_arg; struct psi_call_frame; struct psi_impl; struct psi_impl_type; @@ -41,7 +41,7 @@ zend_internal_arg_info *psi_internal_arginfo(struct psi_impl *impl); int psi_internal_type(struct psi_impl_type *type); typedef void (*psi_marshal_set)(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame); -typedef impl_val *(*psi_marshal_let)(impl_val *tmp, struct psi_decl_type *psi_decl_type, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +typedef impl_val *(*psi_marshal_let)(impl_val *tmp, struct psi_decl_arg *type_spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); void psi_set_void(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame); void psi_set_to_bool(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame); @@ -56,15 +56,15 @@ void psi_set_to_array(zval *return_value, struct psi_set_exp *set, impl_val *ret void psi_set_to_object(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame); void psi_set_zval(zval *return_value, struct psi_set_exp *set, impl_val *ret_val, struct psi_call_frame *frame); -impl_val *psi_let_void(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); -impl_val *psi_let_boolval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); -impl_val *psi_let_intval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); -impl_val *psi_let_floatval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); -impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); -impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); -impl_val *psi_let_strlen(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); -impl_val *psi_let_objval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); -impl_val *psi_let_zval(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); -impl_val *psi_let_count(impl_val *tmp, struct psi_decl_type *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free); +impl_val *psi_let_void(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_boolval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_intval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_floatval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_strval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_pathval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_strlen(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_objval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_zval(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ivalue, zval *zvalue, void **to_free); +impl_val *psi_let_count(impl_val *tmp, struct psi_decl_arg *spec, token_t impl_type, impl_val *ival, zval *zvalue, void **to_free); #endif diff --git a/src/types/decl.c b/src/types/decl.c index df04656..afad6be 100644 --- a/src/types/decl.c +++ b/src/types/decl.c @@ -114,9 +114,10 @@ static inline bool psi_decl_validate_func(struct psi_data *data, return true; } -bool psi_decl_validate(struct psi_data *data, struct psi_decl *decl, void *dl) +bool psi_decl_validate(struct psi_data *data, struct psi_decl *decl, void *dl, + struct psi_validate_stack *type_stack) { - if (!psi_decl_validate_nodl(data, decl)) { + if (!psi_decl_validate_nodl(data, decl, type_stack)) { return false; } if (!psi_decl_validate_func(data, decl, decl->func, dl)) { @@ -126,7 +127,8 @@ bool psi_decl_validate(struct psi_data *data, struct psi_decl *decl, void *dl) return true; } -bool psi_decl_validate_nodl(struct psi_data *data, struct psi_decl *decl) +bool psi_decl_validate_nodl(struct psi_data *data, struct psi_decl *decl, + struct psi_validate_stack *type_stack) { if (!decl->abi) { decl->abi = psi_decl_abi_init("default"); @@ -135,7 +137,7 @@ bool psi_decl_validate_nodl(struct psi_data *data, struct psi_decl *decl) "Invalid calling convention: '%s'", decl->abi->token->text); return false; } - if (!psi_decl_arg_validate(data, decl->func)) { + if (!psi_decl_arg_validate(data, decl->func, type_stack)) { return false; } if (decl->args) { @@ -143,7 +145,7 @@ bool psi_decl_validate_nodl(struct psi_data *data, struct psi_decl *decl) struct psi_decl_arg *arg; while (psi_plist_get(decl->args, i++, &arg)) { - if (!psi_decl_arg_validate(data, arg)) { + if (!psi_decl_arg_validate(data, arg, type_stack)) { return false; } } diff --git a/src/types/decl.h b/src/types/decl.h index 67529e8..1ca56d5 100644 --- a/src/types/decl.h +++ b/src/types/decl.h @@ -44,8 +44,8 @@ struct psi_decl *psi_decl_init(struct psi_decl_arg *func, struct psi_plist *args void psi_decl_free(struct psi_decl **d_ptr); void psi_decl_dump(int fd, struct psi_decl *decl); -bool psi_decl_validate(struct psi_data *data, struct psi_decl *decl, void *dl); -bool psi_decl_validate_nodl(struct psi_data *data, struct psi_decl *decl); +bool psi_decl_validate(struct psi_data *data, struct psi_decl *decl, void *dl, struct psi_validate_stack *type_stack); +bool psi_decl_validate_nodl(struct psi_data *data, struct psi_decl *decl, struct psi_validate_stack *type_stack); static inline struct psi_decl_arg *psi_decl_get_arg(struct psi_decl *decl, struct psi_decl_var *var) { return psi_decl_arg_get_by_var(var, decl->args, decl->func); diff --git a/src/types/decl_arg.c b/src/types/decl_arg.c index ba77e79..bec8ddc 100644 --- a/src/types/decl_arg.c +++ b/src/types/decl_arg.c @@ -92,9 +92,10 @@ void psi_decl_arg_dump(int fd, struct psi_decl_arg *arg, unsigned level) } } -bool psi_decl_arg_validate(struct psi_data *data, struct psi_decl_arg *arg) +bool psi_decl_arg_validate(struct psi_data *data, struct psi_decl_arg *arg, + struct psi_validate_stack *type_stack) { - if (!psi_decl_type_validate(data, arg->type, NULL)) { + if (!psi_decl_type_validate(data, arg->type, type_stack)) { data->error(data, arg->type->token, PSI_WARNING, "Cannot use '%s' as type for '%s': %s", arg->type->name, arg->var->name, data->last_error); @@ -103,30 +104,14 @@ bool psi_decl_arg_validate(struct psi_data *data, struct psi_decl_arg *arg) return true; } -bool psi_decl_arg_validate_typedef(struct psi_data *data, struct psi_decl_arg *def) +bool psi_decl_arg_validate_typedef(struct psi_data *data, + struct psi_decl_arg *def, struct psi_validate_stack *type_stack) { - if (!psi_decl_type_validate(data, def->type, def)) { - const char *pre; - - switch (def->type->type) { - case PSI_T_STRUCT: - pre = "struct "; - break; - case PSI_T_UNION: - pre = "union "; - break; - case PSI_T_ENUM: - pre = "enum "; - break; - default: - pre = ""; - break; - } - data->error(data, def->token, PSI_WARNING, - "Type '%s' cannot be aliased to '%s%s': %s", def->var->name, pre, - def->type->name, data->last_error); - return false; + if (psi_validate_stack_has_type(type_stack, def->var->name)) { + return true; } + psi_validate_stack_add_type(type_stack, def->var->name, def); + if (def->type->type == PSI_T_VOID) { if (def->var->pointer_level) { def->type->type = PSI_T_POINTER; @@ -135,6 +120,29 @@ bool psi_decl_arg_validate_typedef(struct psi_data *data, struct psi_decl_arg *d "Type '%s' cannot be aliased to 'void'", def->type->name); return false; } + } else if (!def->var->pointer_level) { + if (!psi_decl_type_validate(data, def->type, type_stack)) { + const char *pre; + + switch (def->type->type) { + case PSI_T_STRUCT: + pre = "struct "; + break; + case PSI_T_UNION: + pre = "union "; + break; + case PSI_T_ENUM: + pre = "enum "; + break; + default: + pre = ""; + break; + } + data->error(data, def->token, PSI_WARNING, + "Type '%s' cannot be aliased to '%s%s': %s", def->var->name, pre, + def->type->name, data->last_error); + return false; + } } return true; @@ -144,10 +152,10 @@ size_t psi_decl_arg_align(struct psi_decl_arg *darg, size_t *pos, size_t *len) { size_t align = psi_decl_arg_get_align(darg); - assert(align > 0); - - *len = psi_decl_arg_get_size(darg); - *pos = psi_align(align, *pos); + if (align) { + *len = psi_decl_arg_get_size(darg); + *pos = psi_align(align, *pos); + } return align; } diff --git a/src/types/decl_arg.h b/src/types/decl_arg.h index 0ac1fc2..17033f0 100644 --- a/src/types/decl_arg.h +++ b/src/types/decl_arg.h @@ -32,6 +32,7 @@ struct psi_plist; struct psi_decl_type; struct psi_decl_var; struct psi_layout; +struct psi_validate_stack; struct psi_decl_arg { struct psi_token *token; @@ -44,8 +45,8 @@ struct psi_decl_arg *psi_decl_arg_init(struct psi_decl_type *type, struct psi_de void psi_decl_arg_free(struct psi_decl_arg **arg_ptr); void psi_decl_arg_dump(int fd, struct psi_decl_arg *arg, unsigned level); -bool psi_decl_arg_validate(struct psi_data *data, struct psi_decl_arg *arg); -bool psi_decl_arg_validate_typedef(struct psi_data *data, struct psi_decl_arg *def); +bool psi_decl_arg_validate(struct psi_data *data, struct psi_decl_arg *arg, struct psi_validate_stack *type_stack); +bool psi_decl_arg_validate_typedef(struct psi_data *data, struct psi_decl_arg *def, struct psi_validate_stack *type_stack); size_t psi_decl_arg_align(struct psi_decl_arg *darg, size_t *pos, size_t *len); size_t psi_decl_arg_get_align(struct psi_decl_arg *darg); diff --git a/src/types/decl_struct.c b/src/types/decl_struct.c index ab0d9a1..973f633 100644 --- a/src/types/decl_struct.c +++ b/src/types/decl_struct.c @@ -78,11 +78,17 @@ struct psi_decl_arg *psi_decl_struct_get_arg(struct psi_decl_struct *s, return NULL; } -bool psi_decl_struct_validate(struct psi_data *data, struct psi_decl_struct *s) +bool psi_decl_struct_validate(struct psi_data *data, struct psi_decl_struct *s, + struct psi_validate_stack *type_stack) { size_t i, pos, len, size, align; struct psi_decl_arg *darg, *prev_arg; + if (psi_validate_stack_has_struct(type_stack, s->name)) { + return true; + } + psi_validate_stack_add_struct(type_stack, s->name, s); + if (!s->size && !psi_plist_count(s->args)) { data->error(data, s->token, PSI_WARNING, "Cannot compute size of empty struct '%s'", s->name); @@ -92,7 +98,7 @@ bool psi_decl_struct_validate(struct psi_data *data, struct psi_decl_struct *s) for (i = 0; psi_plist_get(s->args, i, &darg); ++i) { darg->var->arg = darg; - if (!psi_decl_arg_validate(data, darg)) { + if (!psi_decl_arg_validate(data, darg, type_stack)) { return false; } @@ -100,6 +106,13 @@ bool psi_decl_struct_validate(struct psi_data *data, struct psi_decl_struct *s) pos = darg->layout->pos; align = psi_decl_arg_align(darg, &pos, &len); + if (!align) { + data->error(data, darg->token, PSI_WARNING, + "Computed zero alignment of %s.%s of type '%s'", + len, s->name, darg->var->name, darg->type->name); + return false; + } + if (darg->layout->len != len) { data->error(data, darg->token, PSI_WARNING, "Computed size %zu of %s.%s does not match" diff --git a/src/types/decl_struct.h b/src/types/decl_struct.h index 4ac9e8c..ca22f3b 100644 --- a/src/types/decl_struct.h +++ b/src/types/decl_struct.h @@ -30,6 +30,7 @@ struct psi_data; struct psi_token; struct psi_plist; struct psi_decl_var; +struct psi_validate_stack; struct psi_decl_struct { struct psi_token *token; @@ -47,7 +48,7 @@ struct psi_decl_struct *psi_decl_struct_init(const char *name, struct psi_plist void psi_decl_struct_free(struct psi_decl_struct **s_ptr); void psi_decl_struct_dump(int fd, struct psi_decl_struct *strct); -bool psi_decl_struct_validate(struct psi_data *data, struct psi_decl_struct *s); +bool psi_decl_struct_validate(struct psi_data *data, struct psi_decl_struct *s, struct psi_validate_stack *type_stack); struct psi_decl_arg *psi_decl_struct_get_arg(struct psi_decl_struct *s, struct psi_decl_var *var); size_t psi_decl_struct_get_align(struct psi_decl_struct *s); diff --git a/src/types/decl_type.c b/src/types/decl_type.c index c3901ca..73e8959 100644 --- a/src/types/decl_type.c +++ b/src/types/decl_type.c @@ -213,36 +213,53 @@ bool psi_decl_type_get_decl(struct psi_decl_type *type, struct psi_plist *decls) } bool psi_decl_type_validate(struct psi_data *data, struct psi_decl_type *type, - struct psi_decl_arg *def) + struct psi_validate_stack *type_stack) { if (psi_decl_type_is_weak(type)) { if (!psi_decl_type_get_alias(type, data->types)) { - return false; + if (!psi_validate_stack_has_type(type_stack, type->name)) { + return false; + } + type->real.def = psi_validate_stack_get_type(type_stack, type->name); } if (type->real.def) { return psi_decl_type_validate(data, type->real.def->type, - type->real.def); + type_stack); } return true; } switch (type->type) { case PSI_T_STRUCT: - if (!psi_decl_type_get_struct(type, data->structs) && !def) { - data->error(data, type->token, PSI_WARNING, - "Unknown struct '%s'", type->name); + if (!psi_decl_type_get_struct(type, data->structs)) { + if (psi_validate_stack_has_struct(type_stack, type->name)) { + type->real.strct = psi_validate_stack_get_struct(type_stack, type->name); + } else { + data->error(data, type->token, PSI_WARNING, + "Unknown struct '%s'", type->name); + return false; + } + } + if (!psi_decl_struct_validate(data, type->real.strct, type_stack)) { return false; } break; case PSI_T_UNION: - if (!psi_decl_type_get_union(type, data->unions) && !def) { - data->error(data, type->token, PSI_WARNING, - "Unknown union '%s'", type->name); + if (!psi_decl_type_get_union(type, data->unions)) { + if (psi_validate_stack_has_union(type_stack, type->name)) { + type->real.unn = psi_validate_stack_get_union(type_stack, type->name); + } else { + data->error(data, type->token, PSI_WARNING, + "Unknown union '%s'", type->name); + return false; + } + } + if (!psi_decl_union_validate(data, type->real.unn, type_stack)) { return false; } break; case PSI_T_ENUM: - if (!psi_decl_type_get_enum(type, data->enums) && !def) { + if (!psi_decl_type_get_enum(type, data->enums)) { data->error(data, type->token, PSI_WARNING, "Unknown enum '%s'", type->name); return false; @@ -254,11 +271,14 @@ bool psi_decl_type_validate(struct psi_data *data, struct psi_decl_type *type, "Unknown decl '%s'", type->name); return false; } - if (!psi_decl_validate_nodl(data, type->real.func)) { + if (!psi_decl_validate_nodl(data, type->real.func, type_stack)) { return false; } break; + default: + break; } + return true; } diff --git a/src/types/decl_type.h b/src/types/decl_type.h index e7c341f..a31f317 100644 --- a/src/types/decl_type.h +++ b/src/types/decl_type.h @@ -36,6 +36,7 @@ struct psi_decl_struct; struct psi_decl_union; struct psi_decl_enum; struct psi_decl; +struct psi_validate_stack; struct psi_decl_type { struct psi_token *token; @@ -57,7 +58,7 @@ struct psi_decl_type *psi_decl_type_init(token_t type, const char *name); struct psi_decl_type *psi_decl_type_copy(struct psi_decl_type *src); void psi_decl_type_free(struct psi_decl_type **type_ptr); void psi_decl_type_dump(int fd, struct psi_decl_type *t, unsigned level); -bool psi_decl_type_validate(struct psi_data *data, struct psi_decl_type *type, struct psi_decl_arg *def); +bool psi_decl_type_validate(struct psi_data *data, struct psi_decl_type *type, struct psi_validate_stack *type_stack); bool psi_decl_type_validate_args(struct psi_data *data, struct psi_decl_type *decl_type, token_t type, void *current); diff --git a/src/types/decl_union.c b/src/types/decl_union.c index 71e70eb..1d24f95 100644 --- a/src/types/decl_union.c +++ b/src/types/decl_union.c @@ -74,11 +74,17 @@ struct psi_decl_arg *psi_decl_union_get_arg(struct psi_decl_union *u, return NULL; } -bool psi_decl_union_validate(struct psi_data *data, struct psi_decl_union *u) +bool psi_decl_union_validate(struct psi_data *data, struct psi_decl_union *u, + struct psi_validate_stack *type_stack) { size_t i, pos, len, size = 0, align; struct psi_decl_arg *darg; + if (psi_validate_stack_has_union(type_stack, u->name)) { + return true; + } + psi_validate_stack_add_union(type_stack, u->name, u); + if (!u->size && !psi_plist_count(u->args)) { data->error(data, u->token, PSI_WARNING, "Cannot compute size of empty union %s", u->name); @@ -88,7 +94,7 @@ bool psi_decl_union_validate(struct psi_data *data, struct psi_decl_union *u) for (i = 0; psi_plist_get(u->args, i, &darg); ++i) { darg->var->arg = darg; - if (!psi_decl_arg_validate(data, darg)) { + if (!psi_decl_arg_validate(data, darg, type_stack)) { return false; } diff --git a/src/types/decl_union.h b/src/types/decl_union.h index 619b3f5..95184e2 100644 --- a/src/types/decl_union.h +++ b/src/types/decl_union.h @@ -29,6 +29,7 @@ struct psi_data; struct psi_token; struct psi_plist; struct psi_decl_var; +struct psi_validate_stack; struct psi_decl_union { struct psi_token *token; @@ -42,7 +43,7 @@ struct psi_decl_union *psi_decl_union_init(const char *name, struct psi_plist *a void psi_decl_union_free(struct psi_decl_union **u_ptr); void psi_decl_union_dump(int fd, struct psi_decl_union *unn); -bool psi_decl_union_validate(struct psi_data *data, struct psi_decl_union *u); +bool psi_decl_union_validate(struct psi_data *data, struct psi_decl_union *u, struct psi_validate_stack *type_stack); size_t psi_decl_union_get_align(struct psi_decl_union *u); struct psi_decl_arg *psi_decl_union_get_arg(struct psi_decl_union *u, struct psi_decl_var *var); diff --git a/src/types/let_callback.c b/src/types/let_callback.c index f6b08ba..632289f 100644 --- a/src/types/let_callback.c +++ b/src/types/let_callback.c @@ -74,7 +74,7 @@ bool psi_let_callback_validate(struct psi_data *data, struct psi_let_exp *exp, } } - if (!psi_decl_validate_nodl(data, cb_func)) { + if (!psi_decl_validate_nodl(data, cb_func, NULL /* FIXME type_stack */)) { return false; } diff --git a/src/types/let_func.c b/src/types/let_func.c index 27c3702..abf69a4 100644 --- a/src/types/let_func.c +++ b/src/types/let_func.c @@ -255,7 +255,7 @@ static void *exec_let_func_arrval(struct psi_let_exp *val, struct psi_call_frame *frame); void exec_let_func_arrval_seq(struct psi_let_func *func, - struct psi_decl_arg *darg, struct psi_decl_type *darg_type, + struct psi_decl_arg *darg, struct psi_call_frame_argument *frame_arg, struct psi_let_exp *inner_let_exp, void *container, struct psi_call_frame *frame) @@ -287,7 +287,7 @@ void exec_let_func_arrval_seq(struct psi_let_func *func, impl_val val = {0}, *ptr, *sub; if (let_fn) { - ptr = let_fn(&val, darg_type, 0, NULL, zval_ptr, &temp); + ptr = let_fn(&val, darg, 0, NULL, zval_ptr, &temp); if (temp) { psi_call_frame_push_auto(frame, temp); } @@ -315,10 +315,9 @@ static void *exec_let_func_arrval(struct psi_let_exp *val, { void *container = NULL; struct psi_call_frame_argument *frame_arg; - struct psi_decl_type *darg_type; struct psi_plist *darg_members; - darg_members = psi_decl_type_get_args(darg->type, &darg_type); + darg_members = psi_decl_type_get_args(darg->type, NULL); frame_arg = psi_call_frame_get_argument(frame, func->var->fqn); if (frame_arg->zval_ptr && Z_TYPE_P(frame_arg->zval_ptr) != IS_ARRAY) { @@ -368,8 +367,7 @@ static void *exec_let_func_arrval(struct psi_let_exp *val, container = ecalloc(arcount + 1, psi_decl_var_get_size(inner->var)); inner->var->pointer_level -= inner->is_reference; - exec_let_func_arrval_seq(func, darg, darg_type, frame_arg, inner, - container, frame); + exec_let_func_arrval_seq(func, darg, frame_arg, inner, container, frame); } else { assert(0); } @@ -393,8 +391,7 @@ void *psi_let_func_exec(struct psi_let_exp *val, struct psi_let_func *func, assert(iarg); - frame_sym->ival_ptr = let_fn(&frame_sym->temp_val, - psi_decl_type_get_real(darg->type), + frame_sym->ival_ptr = let_fn(&frame_sym->temp_val, darg, iarg->spec ? iarg->spec->type->type : 0, iarg->ival_ptr, iarg->zval_ptr, &temp); if (temp) { diff --git a/tests/parser/validate004.phpt b/tests/parser/validate004.phpt index 31b8509..aa94c41 100644 --- a/tests/parser/validate004.phpt +++ b/tests/parser/validate004.phpt @@ -12,6 +12,4 @@ psi_validate_string("struct a; \ntypedef struct a a_t;"); ===DONE=== --EXPECTF-- ===TEST=== - -Warning: Cannot compute size of empty struct 'a' in %s on line 1 ===DONE===