X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-psi;a=blobdiff_plain;f=src%2Fvalidator.c;h=128b2acb07e513639f29d0e62fac05a4a3c7973a;hp=5f6a6d36e73e81ec841cd047916a4d0efd119dd0;hb=7474b3e23338ea03bcd65551959e2582cc455f9f;hpb=3bca631112f4865510ea91c85e8c820c4465fc14 diff --git a/src/validator.c b/src/validator.c index 5f6a6d3..128b2ac 100644 --- a/src/validator.c +++ b/src/validator.c @@ -6,6 +6,8 @@ #include +#include "php.h" +#include "php_psi.h" #include "validator.h" PSI_Validator *PSI_ValidatorInit(PSI_Validator *V, PSI_Parser *P) @@ -43,8 +45,6 @@ static int validate_lib(PSI_Validator *V) { if (!ptr) { /* FIXME: assume stdlib */ return 1; - fprintf(stderr, "No import library defined;" - " use 'lib \"\";' statement.\n"); } else if (!strchr(ptr, '/')) { #ifdef DARWIN len = snprintf(lib, MAXPATHLEN, "lib%s.dylib", ptr); @@ -52,17 +52,18 @@ static int validate_lib(PSI_Validator *V) { len = snprintf(lib, MAXPATHLEN, "lib%s.so", ptr); #endif if (MAXPATHLEN == len) { - fprintf(stderr, "Library name too long: '%s'\n", ptr); + V->error(PSI_WARNING, "Library name too long: '%s'", ptr); } lib[len] = 0; ptr = lib; } if (!(V->dlopened = dlopen(ptr, RTLD_LAZY|RTLD_LOCAL))) { - fprintf(stderr, "Could not open library '%s': %s.\n", V->lib, dlerror()); + V->error(PSI_WARNING, "Could not open library '%s': %s.", V->lib, dlerror()); return 0; } return 1; } + static inline int locate_decl_type_alias(decl_typedefs *defs, decl_type *type) { size_t i; @@ -77,22 +78,39 @@ static inline int locate_decl_type_alias(decl_typedefs *defs, decl_type *type) { } return 0; } -static inline int validate_decl_type(PSI_Validator *V, decl_arg *arg, decl_type *type) { - if (type->type == PSI_T_NAME) { - size_t i; +static inline int locate_decl_type_struct(decl_structs *structs, decl_type *type) { + size_t i; + if (type->strct) { + return 1; + } + for (i = 0; i < structs->count; ++i) { + if (!strcmp(structs->list[i]->name, type->name)) { + type->strct = structs->list[i]; + return 1; + } + } + return 0; +} +static inline int validate_decl_type(PSI_Validator *V, decl_type *type) { + switch (type->type) { + case PSI_T_NAME: if (!V->defs || !locate_decl_type_alias(V->defs, type)) { - fprintf(stderr, "Cannot use '%s' as type for '%s';" - " Use 'typedef ;' statement.\n", - type->name, arg->var->name); + return 0; + } + return validate_decl_type(V, type->real); + case PSI_T_STRUCT: + if (!V->structs || !locate_decl_type_struct(V->structs, type)) { + return 0; } + break; } return 1; } static inline int validate_typedef(PSI_Validator *V, decl_typedef *def) { /* FIXME: check def->alias */ if (def->type->type == PSI_T_NAME) { - fprintf(stderr, "Type '%s' cannot be aliased to '%s'\n", + V->error(PSI_WARNING, "Type '%s' cannot be aliased to '%s'", def->type->name, def->alias); return 0; } @@ -109,67 +127,119 @@ static inline int validate_typedefs(PSI_Validator *V) { return 1; } +static const char * const abi_ccs[] = { + "default", /* \ */ + "extern", /* > - all the same */ + "cdecl", /* / */ + "stdcall", + "fastcall", +}; +static inline int validate_decl_abi(PSI_Validator *V, decl_abi *abi) { + size_t i; + + for (i = 0; i < sizeof(abi_ccs)/sizeof(char*); ++i) { + if (strcasecmp(abi->convention, abi_ccs[i])) { + return 1; + } + } + V->error(PSI_WARNING, "Invalid calling convention: '%s'", abi->convention); + return 0; +} +static inline int validate_decl_arg(PSI_Validator *V, decl_arg *arg) { + if (!validate_decl_type(V, arg->type)) { + V->error(PSI_WARNING, "Cannot use '%s' as type for '%s'", + arg->type->name, arg->var->name); + return 0; + } + return 1; +} +static inline int validate_decl_args(PSI_Validator *V, decl_args *args) { + size_t i; + + for (i = 0; i < args->count; ++i) { + if (!validate_decl_arg(V, args->args[i])) { + return 0; + } + } + return 1; +} static inline int validate_decl_func(PSI_Validator *V, decl *decl, decl_arg *func) { - void *dlptr; - if (!strcmp(func->var->name, "dlsym")) { - fprintf(stderr, "Cannot dlsym dlsym (sic!)\n"); + V->error(PSI_WARNING, "Cannot dlsym dlsym (sic!)"); return 0; } - if (!validate_decl_type(V, func, func->type)) { + if (!validate_decl_arg(V, func)) { return 0; } - - decl->dlptr = dlsym(V->dlopened, func->var->name); +#ifndef RTLD_NEXT +# define RTLD_NEXT ((void *) -1l) +#endif + decl->dlptr = dlsym(V->dlopened ?: RTLD_NEXT, func->var->name); if (!decl->dlptr) { - fprintf(stderr, "Failed to located symbol '%s': %s\n", + V->error(PSI_WARNING, "Failed to located symbol '%s': %s", func->var->name, dlerror()); } return 1; } -static inline int validate_decl_abi(PSI_Validator *V, decl_abi *abi) { - if (strcasecmp(abi->convention, "default")) { - fprintf(stderr, "Invalid calling convention: '%s'\n", abi->convention); +static inline int validate_decl(PSI_Validator *V, decl *decl) { + if (!validate_decl_abi(V, decl->abi)) { return 0; } - /* FIXME */ - return 1; -} -static inline int validate_decl_arg(PSI_Validator *V, decl *decl, decl_arg *arg) { - if (!validate_decl_type(V, arg, arg->type)) { + if (!validate_decl_func(V, decl, decl->func)) { + return 0; + } + if (decl->args && !validate_decl_args(V, decl->args)) { return 0; } return 1; } -static inline int validate_decl_args(PSI_Validator *V, decl *decl, decl_args *args) { +static inline int validate_decls(PSI_Validator *V) { size_t i; - for (i = 0; i < args->count; ++i) { - if (!validate_decl_arg(V, decl, args->args[i])) { + for (i = 0; i < V->decls->count; ++i) { + if (!validate_decl(V, V->decls->list[i])) { return 0; } } return 1; } -static inline int validate_decl(PSI_Validator *V, decl *decl) { - if (!validate_decl_abi(V, decl->abi)) { - return 0; - } - if (!validate_decl_func(V, decl, decl->func)) { +static inline int validate_struct(PSI_Validator *V, decl_struct *s) { + size_t i; + + if (!validate_decl_args(V, s->args)) { return 0; } - if (decl->args && !validate_decl_args(V, decl, decl->args)) { - return 0; + + s->layout = calloc(s->args->count, sizeof(*s->layout)); + for (i = 0; i < s->args->count; ++i) { + decl_arg *darg = s->args->args[i]; + token_t t; + + if (!validate_decl_arg(V, darg)) { + return 0; + } + + t = darg->var->pointer_level + ? PSI_T_POINTER + : real_decl_type(darg->type)->type; + + if (i) { + decl_struct_layout *l = &s->layout[i-1]; + s->layout[i].pos = psi_t_align(t, l->pos + l->len); + } else { + s->layout[i].pos = 0; + } + s->layout[i].len = psi_t_size(t); } return 1; } -static inline int validate_decls(PSI_Validator *V) { +static inline int validate_structs(PSI_Validator *V) { size_t i; - for (i = 0; i < V->decls->count; ++i) { - if (!validate_decl(V, V->decls->list[i])) { + for (i = 0; i < V->structs->count; ++i) { + if (!validate_struct(V, V->structs->list[i])) { return 0; } } @@ -203,71 +273,198 @@ static inline int validate_impl_func(PSI_Validator *V, impl *impl, impl_func *fu } return 1; } -static inline decl *locate_impl_decl(decls *decls, ret_stmt *ret) { + +static inline decl *locate_impl_decl(decls *decls, return_stmt *ret) { size_t i; for (i = 0; i < decls->count; ++i) { if (!strcmp(decls->list[i]->func->var->name, ret->decl->name)) { + ret->decl->arg = decls->list[i]->func; return decls->list[i]; } } return NULL; } -static inline int validate_impl_stmts(PSI_Validator *V, impl *impl, impl_stmts *stmts) { - /* okay, - * - we must have exactly one ret stmt delcaring the native func to call and which type cast to apply - * - we can have multiple let stmts; every arg of the ret stmts var (the function to call) must have one - * - we can have any count of set stmts; processing out vars, etc. - */ - size_t i, j; - ret_stmt *ret; - decl *decl; - int *check; - - if (!stmts) { - fprintf(stderr, "Missing body for implementation %s!\n", impl->func->name); - return 0; - } - if (stmts->ret.count != 1) { - if (stmts->ret.count > 1) { - fprintf(stderr, "Too many `ret` statements for implmentation %s; found %zu, exactly one is needed.\n", - impl->func->name, stmts->ret.count); +static inline int validate_impl_ret_stmt(PSI_Validator *V, impl *impl) { + /* we must have exactly one ret stmt delcaring the native func to call */ + /* and which type cast to apply */ + if (impl->stmts->ret.count != 1) { + if (impl->stmts->ret.count > 1) { + V->error(PSI_WARNING, "Too many `return` statements for implmentation %s;" + " found %zu, exactly one is needed", + impl->func->name, impl->stmts->ret.count); } else { - fprintf(stderr, "Missing `ret` statement for implementation %s.\n", impl->func->name); + V->error(PSI_WARNING, "Missing `return` statement for implementation %s", + impl->func->name); } return 0; } - - ret = stmts->ret.list[0]; - decl = locate_impl_decl(V->decls, ret); - if (!decl) { - fprintf(stderr, "Missing declaration for implementation %s.\n", impl->func->name); + if (!(impl->decl = locate_impl_decl(V->decls, impl->stmts->ret.list[0]))) { + V->error(PSI_WARNING, "Missing declaration for implementation %s", + impl->func->name); return 0; } + return 1; +} +static inline int validate_impl_let_stmts(PSI_Validator *V, impl *impl) { + size_t i, j; + /* we can have multiple let stmts */ /* check that we have a let stmt for every decl arg */ - check = calloc(decl->args->count, sizeof(int)); - for (i = 0; i < stmts->let.count; ++i) { - let_stmt *let = stmts->let.list[i]; + if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) { + decl_arg *darg = impl->decl->args->args[i]; + int check = 0; - for (j = 0; j < decl->args->count; ++j) { - if (!strcmp(decl->args->args[j]->var->name, let->var->name)) { - check[j] = 1; + for (j = 0; j < impl->stmts->let.count; ++j) { + let_stmt *let = impl->stmts->let.list[j]; + + if (!strcmp(let->var->name, darg->var->name)) { + darg->let = let; + check = 1; break; } } + if (!check) { + V->error(PSI_WARNING, "Missing `let` statement for arg '%s %.*s%s'" + " of declaration '%s' for implementation '%s'", + darg->type->name, (int) darg->var->pointer_level, "*****", + darg->var->name, impl->decl->func->var->name, impl->func->name); + return 0; + } + } + /* check that the let_value references a known variable or NULL */ + for (i = 0; i < impl->stmts->let.count; ++i) { + let_stmt *let = impl->stmts->let.list[i]; + int check = 0; + + if (let->val && let->val->func && let->val->func->alloc) { + if (!validate_decl_type(V, let->val->func->alloc->type)) { + V->error(PSI_WARNING, "Cannot use '%s' as type for calloc in `let` statement", + let->val->func->alloc->type->name); + return 0; + } + } + if (let->val && let->val->var) { + if (impl->func->args) for (j = 0; j < impl->func->args->count; ++j) { + impl_arg *iarg = impl->func->args->args[j]; + + if (!strcmp(let->val->var->name, iarg->var->name)) { + let->arg = iarg; + check = 1; + break; + } + } + if (!check) { + V->error(PSI_WARNING, "Unknown value '$%s' of `let` statement" + " for variable '%s' of implementation '%s'", + let->val->var->name, let->var->name, impl->func->name); + return 0; + } + } } - for (i = 0; i < decl->args->count; ++i) { - if (!check[i]) { - fprintf(stderr, "Missing `let` statement for arg '%s %.*s%s' of declaration '%s' for implementation '%s'.\n", - decl->args->args[i]->type->name, (int) decl->args->args[i]->var->pointer_level, "*****", decl->args->args[i]->var->name, decl->func->var->name, impl->func->name); - free(check); + return 1; +} +static inline int validate_impl_set_stmts(PSI_Validator *V, impl *impl) { + size_t i, j, k; + /* we can have any count of set stmts; processing out vars */ + /* check that set stmts reference known variables */ + for (i = 0; i < impl->stmts->set.count; ++i) { + set_stmt *set = impl->stmts->set.list[i]; + int check = 0; + + if (impl->func->args) for (j = 0; j < impl->func->args->count; ++j) { + impl_arg *iarg = impl->func->args->args[j]; + + if (!strcmp(set->var->name, iarg->var->name)) { + set->arg = iarg; + check = 1; + break; + } + } + if (!check) { + V->error(PSI_WARNING, "Unknown variable '$%s' of `set` statement" + " of implementation '%s'", + set->var->name, impl->func->name); return 0; } + + for (j = 0; j < set->val->vars->count; ++j) { + decl_var *set_var = set->val->vars->vars[j]; + + check = 0; + if (impl->decl->args) for (k = 0; k < impl->decl->args->count; ++k) { + decl_arg *set_arg = impl->decl->args->args[k]; + + if (!strcmp(set_var->name, set_arg->var->name)) { + check = 1; + set_var->arg = set_arg; + break; + } + } + + if (!check) { + V->error(PSI_WARNING, "Unknown value '%s' of `set` statement" + " for variable '$%s' of implementation '%s'", + set_var->name, set->arg->var->name, impl->func->name); + return 0; + } + } } - free(check); + return 1; +} +static inline int validate_impl_free_stmts(PSI_Validator *V, impl *impl) { + size_t i, j, k; + /* we can have any count of free stmts; freeing any out vars */ + for (i = 0; i < impl->stmts->fre.count; ++i) { + free_stmt *fre = impl->stmts->fre.list[i]; + + for (j = 0; j < fre->vars->count; ++j) { + decl_var *free_var = fre->vars->vars[j]; + int check = 0; - impl->decl = decl; + if (!strcmp(free_var->name, impl->decl->func->var->name)) { + continue; + } + if (impl->decl->args) for (k = 0; k < impl->decl->args->count; ++k) { + decl_arg *free_arg = impl->decl->args->args[k]; + + if (!strcmp(free_var->name, free_arg->var->name)) { + check = 1; + free_var->arg = free_arg; + break; + } + } + + if (!check) { + V->error(PSI_WARNING, "Unknown variable '%s' of `free` statement" + " of implementation '%s'", + free_var->name, impl->func->name); + return 0; + } + } + } + return 1; +} +static inline int validate_impl_stmts(PSI_Validator *V, impl *impl) { + if (!impl->stmts) { + V->error(PSI_WARNING, "Missing body for implementation %s!", + impl->func->name); + return 0; + } + + if (!validate_impl_ret_stmt(V, impl)) { + return 0; + } + + if (!validate_impl_let_stmts(V, impl)) { + return 0; + } + if (!validate_impl_set_stmts(V, impl)) { + return 0; + } + if (!validate_impl_free_stmts(V, impl)) { + return 0; + } return 1; } @@ -276,7 +473,7 @@ static inline int validate_impl(PSI_Validator *V, impl *impl) { if (!validate_impl_func(V, impl, impl->func)) { return 0; } - if (!validate_impl_stmts(V, impl, impl->stmts)) { + if (!validate_impl_stmts(V, impl)) { return 0; } return 1; @@ -300,10 +497,13 @@ int PSI_ValidatorValidate(PSI_Validator *V) if (V->defs && !validate_typedefs(V)) { return 0; } + if (V->structs && !validate_structs(V)) { + return 0; + } if (V->decls && !validate_decls(V)) { return 0; } - if (V->impls && !validate_impls(V)) { + if (!V->impls || !validate_impls(V)) { return 0; } return 1;