From 527864dd4e73d34df7d85cf1bb5e71ac5bafc020 Mon Sep 17 00:00:00 2001 From: stefandd Date: Wed, 27 Jul 2022 15:35:29 +0200 Subject: [PATCH] Fix for crash involving the use of private types used as default values This attempts to fix issues #4130 and #4153. The issue was when a private type in another package was used as a default value in a method call. Fix to #4130 Since it has been decided to treat this as a bug instead of a missing error, this PR implements the fix suggested by @ergl, namely using `lookup_try()` instead of lookup() in call.c's `check_partial_function_call()` since it allows to permit private types. Fix to #4153 This is also a simply fix to lookup.c that prevents a potential segfault by a dereferencing of `opt` (`typecheck_t* t = &opt->check;`) *before* `opt != NULL` was checked. As pointed out by @SeanTAllen, opt should not be NULL to begin with when lookup_nominal is called, and instead, an assert should be added and the NULL checks in that function removed. --- src/libponyc/type/lookup.c | 43 ++++++++++++++++++-------------------- src/libponyc/verify/call.c | 4 ++-- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/libponyc/type/lookup.c b/src/libponyc/type/lookup.c index f0b75bda08..03ad5c4190 100644 --- a/src/libponyc/type/lookup.c +++ b/src/libponyc/type/lookup.c @@ -57,14 +57,14 @@ static deferred_reification_t* lookup_nominal(pass_opt_t* opt, ast_t* from, ast_t* orig, ast_t* type, const char* name, bool errors, bool allow_private) { pony_assert(ast_id(type) == TK_NOMINAL); + pony_assert(opt != NULL); typecheck_t* t = &opt->check; ast_t* def = (ast_t*)ast_data(type); AST_GET_CHILDREN(def, type_id, typeparams); const char* type_name = ast_name(type_id); - if(is_name_private(type_name) && (from != NULL) && (opt != NULL) - && !allow_private) + if(is_name_private(type_name) && (from != NULL) && !allow_private) { if(ast_nearest(def, TK_PACKAGE) != t->frame->package) { @@ -94,34 +94,31 @@ static deferred_reification_t* lookup_nominal(pass_opt_t* opt, ast_t* from, case TK_FUN: { // Typecheck default args immediately. - if(opt != NULL) + AST_GET_CHILDREN(find, cap, id, typeparams, params); + ast_t* param = ast_child(params); + + while(param != NULL) { - AST_GET_CHILDREN(find, cap, id, typeparams, params); - ast_t* param = ast_child(params); + AST_GET_CHILDREN(param, name, type, def_arg); - while(param != NULL) + if((ast_id(def_arg) != TK_NONE) && (ast_type(def_arg) == NULL)) { - AST_GET_CHILDREN(param, name, type, def_arg); - - if((ast_id(def_arg) != TK_NONE) && (ast_type(def_arg) == NULL)) - { - ast_t* child = ast_child(def_arg); + ast_t* child = ast_child(def_arg); - if(ast_id(child) == TK_CALL) - ast_settype(child, ast_from(child, TK_INFERTYPE)); + if(ast_id(child) == TK_CALL) + ast_settype(child, ast_from(child, TK_INFERTYPE)); - if(ast_visit_scope(¶m, pass_pre_expr, pass_expr, opt, - PASS_EXPR) != AST_OK) - return NULL; + if(ast_visit_scope(¶m, pass_pre_expr, pass_expr, opt, + PASS_EXPR) != AST_OK) + return NULL; - def_arg = ast_childidx(param, 2); + def_arg = ast_childidx(param, 2); - if(!coerce_literals(&def_arg, type, opt)) - return NULL; - } - - param = ast_sibling(param); + if(!coerce_literals(&def_arg, type, opt)) + return NULL; } + + param = ast_sibling(param); } break; } @@ -140,7 +137,7 @@ static deferred_reification_t* lookup_nominal(pass_opt_t* opt, ast_t* from, return NULL; } - if(is_name_private(name) && (from != NULL) && (opt != NULL) && !allow_private) + if(is_name_private(name) && (from != NULL) && !allow_private) { switch(ast_id(find)) { diff --git a/src/libponyc/verify/call.c b/src/libponyc/verify/call.c index 814d60e25d..c820819f9d 100644 --- a/src/libponyc/verify/call.c +++ b/src/libponyc/verify/call.c @@ -28,8 +28,8 @@ static bool check_partial_function_call(pass_opt_t* opt, ast_t* ast) ast_id(call_error) == TK_NONE || ast_id(call_error) == TK_DONTCARE); // Look up the original method definition for this method call. - deferred_reification_t* method_def = lookup(opt, receiver, ast_type(receiver), - ast_name(method)); + deferred_reification_t* method_def = lookup_try(opt, receiver, ast_type(receiver), + ast_name(method), true); // allow private types ast_t* method_ast = method_def->ast; deferred_reify_free(method_def);