mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Error if a stack allocated variable is too big (configurable with --max-stack-object-size).
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
- Fix max module name to 31 chars and the entire module path to 63 characters.
|
||||
- Improve error message for missing `$endif`.
|
||||
- `foo[x][y] = b` now interpreted as `(*&foo[x])[y] = b` which allows overloads to do chained [] accesses.
|
||||
- Error if a stack allocated variable is too big (configurable with `--max-stack-object-size`).
|
||||
|
||||
### Fixes
|
||||
- List.remove_at would incorrectly trigger ASAN.
|
||||
|
||||
@@ -585,6 +585,7 @@ typedef struct BuildOptions_
|
||||
MemoryEnvironment memory_environment;
|
||||
SanitizeMode sanitize_mode;
|
||||
uint32_t max_vector_size;
|
||||
uint32_t max_stack_object_size;
|
||||
bool print_keywords;
|
||||
bool print_attributes;
|
||||
bool print_builtins;
|
||||
@@ -725,6 +726,7 @@ typedef struct
|
||||
LinkerType linker_type;
|
||||
uint32_t symtab_size;
|
||||
uint32_t max_vector_size;
|
||||
uint32_t max_stack_object_size;
|
||||
uint32_t switchrange_max_size;
|
||||
uint32_t switchjump_max_size;
|
||||
const char **args;
|
||||
|
||||
@@ -177,6 +177,7 @@ static void usage(bool full)
|
||||
print_opt("--win64-simd=<option>", "Win64 SIMD ABI: array, full.");
|
||||
print_opt("--win-debug=<option>", "Select debug output on Windows: codeview or dwarf (default: codeview).");
|
||||
print_opt("--max-vector-size <number>", "Set the maximum vector bit size to allow (default: 4096).");
|
||||
print_opt("--max-stack-object-size <number>", "Set the maximum size of a stack object in KB (default: 128).");
|
||||
PRINTF("");
|
||||
print_opt("--print-linking", "Print linker arguments.");
|
||||
PRINTF("");
|
||||
@@ -943,6 +944,14 @@ static void parse_option(BuildOptions *options)
|
||||
options->riscv_float_capability = parse_opt_select(RiscvFloatCapability, argopt, riscv_capability);
|
||||
return;
|
||||
}
|
||||
if (match_longopt("max-stack-object-size"))
|
||||
{
|
||||
int size = (at_end() || next_is_opt()) ? 0 : atoi(next_arg());
|
||||
if (size < 1) error_exit("Expected a valid positive integer >= 1 for --max-stack-object-size.");
|
||||
if (size > MAX_STACK_OBJECT_SIZE) error_exit("Expected a valid positive integer <= %u for --max-vector-size.", (unsigned)MAX_STACK_OBJECT_SIZE);
|
||||
options->max_stack_object_size = size;
|
||||
return;
|
||||
}
|
||||
if (match_longopt("max-vector-size"))
|
||||
{
|
||||
int size = (at_end() || next_is_opt()) ? 0 : atoi(next_arg());
|
||||
@@ -952,6 +961,7 @@ static void parse_option(BuildOptions *options)
|
||||
{
|
||||
error_exit("The --max-vector-size value must be a power of 2, try using %u instead.", next_highest_power_of_2(size));
|
||||
}
|
||||
options->max_vector_size = size;
|
||||
return;
|
||||
}
|
||||
if ((argopt = match_argopt("memory-env")))
|
||||
|
||||
@@ -431,6 +431,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
OVERRIDE_IF_SET(benchfn);
|
||||
OVERRIDE_IF_SET(symtab_size);
|
||||
OVERRIDE_IF_SET(max_vector_size);
|
||||
OVERRIDE_IF_SET(max_stack_object_size);
|
||||
OVERRIDE_IF_SET(win.def);
|
||||
OVERRIDE_IF_SET(no_entry);
|
||||
OVERRIDE_IF_SET(echo_prefix);
|
||||
@@ -446,6 +447,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
OVERRIDE_IF_SET(android.api_version);
|
||||
|
||||
if (!target->max_vector_size) target->max_vector_size = DEFAULT_VECTOR_WIDTH;
|
||||
if (!target->max_stack_object_size) target->max_stack_object_size = DEFAULT_STACK_OBJECT_SIZE;
|
||||
|
||||
if (target->quiet && !options->verbosity_level) options->verbosity_level = -1;
|
||||
|
||||
|
||||
@@ -407,7 +407,7 @@ static bool parse_param_path(ParseContext *c, DesignatorElement ***path)
|
||||
}
|
||||
}
|
||||
|
||||
static Expr *parse_lambda(ParseContext *c, Expr *left, SourceSpan lhs_span)
|
||||
static Expr *parse_lambda(ParseContext *c, Expr *left, SourceSpan lhs_span UNUSED)
|
||||
{
|
||||
ASSERT(!left && "Unexpected left hand side");
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_LAMBDA);
|
||||
@@ -622,9 +622,10 @@ Expr *parse_ct_expression_list(ParseContext *c, bool allow_decl)
|
||||
*
|
||||
* @param c the context
|
||||
* @param left must be null.
|
||||
* @param lhs_start unused
|
||||
* @return Expr *
|
||||
*/
|
||||
static Expr *parse_type_identifier(ParseContext *c, Expr *left, SourceSpan lhs_start)
|
||||
static Expr *parse_type_identifier(ParseContext *c, Expr *left, SourceSpan lhs_start UNUSED)
|
||||
{
|
||||
ASSERT(!left && "Unexpected left hand side");
|
||||
return parse_type_expression_with_path(c, NULL);
|
||||
@@ -635,9 +636,10 @@ static Expr *parse_type_identifier(ParseContext *c, Expr *left, SourceSpan lhs_s
|
||||
*
|
||||
* @param c the context
|
||||
* @param left must be null.
|
||||
* @param lhs_start unused
|
||||
* @return Expr *
|
||||
*/
|
||||
static Expr *parse_splat(ParseContext *c, Expr *left, SourceSpan lhs_start)
|
||||
static Expr *parse_splat(ParseContext *c, Expr *left, SourceSpan lhs_start UNUSED)
|
||||
{
|
||||
ASSERT(!left && "Unexpected left hand side");
|
||||
Expr *expr = expr_new(EXPR_SPLAT, c->span);
|
||||
@@ -671,9 +673,10 @@ static Expr *parse_type_expr(ParseContext *c, Expr *left, SourceSpan lhs_start U
|
||||
*
|
||||
* @param c the context
|
||||
* @param left must be null
|
||||
* @param lhs_start unused
|
||||
* @return Expr *
|
||||
*/
|
||||
static Expr *parse_ct_stringify(ParseContext *c, Expr *left, SourceSpan lhs_start)
|
||||
static Expr *parse_ct_stringify(ParseContext *c, Expr *left, SourceSpan lhs_start UNUSED)
|
||||
{
|
||||
ASSERT(!left && "Unexpected left hand side");
|
||||
SourceSpan start_span = c->span;
|
||||
|
||||
@@ -764,7 +764,8 @@ INLINE bool parse_rethrow_bracket(ParseContext *c, SourceSpan start)
|
||||
/**
|
||||
* optional_type ::= type '!'?
|
||||
* @param c
|
||||
* @return
|
||||
* @param allow_generic should generic be allowed
|
||||
* @return The resulting type
|
||||
*/
|
||||
static inline TypeInfo *parse_optional_type_maybe_generic(ParseContext *c, bool allow_generic)
|
||||
{
|
||||
|
||||
@@ -545,7 +545,7 @@ RETRY:
|
||||
}
|
||||
default:
|
||||
// Check type sizes
|
||||
goto CHECK_SIZE;
|
||||
break;
|
||||
}
|
||||
CHECK_SIZE:
|
||||
if (type_size(expr->type) > type_size(type)) return expr;
|
||||
@@ -721,14 +721,10 @@ static bool report_cast_error(CastContext *cc, bool may_cast_explicit)
|
||||
type_quoted_error_string(to),
|
||||
type_to_error_string(type_no_optional(to)));
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN_CAST_ERROR(expr,
|
||||
"It is not possible to cast %s to the inner type %s.",
|
||||
type_quoted_error_string(type_no_optional(expr->type)), type_quoted_error_string(to));
|
||||
}
|
||||
|
||||
}
|
||||
if (may_cast_explicit)
|
||||
{
|
||||
if (expr->type->canonical->type_kind == TYPE_DISTINCT
|
||||
@@ -837,7 +833,7 @@ static bool rule_ptr_to_ptr(CastContext *cc, bool is_explicit, bool is_silent)
|
||||
}
|
||||
|
||||
|
||||
static bool rule_all_ok(CastContext *cc, bool is_explicit, bool silent)
|
||||
static bool rule_all_ok(CastContext *cc UNUSED, bool is_explicit UNUSED, bool silent UNUSED)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4789,6 +4789,16 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
|
||||
{
|
||||
if (!sema_set_alloca_alignment(context, decl->type, &decl->alignment)) return false;
|
||||
}
|
||||
if (decl->var.kind == VARDECL_LOCAL && type_size(decl->type) > compiler.build.max_stack_object_size * 1024)
|
||||
{
|
||||
size_t size = type_size(decl->type);
|
||||
RETURN_SEMA_ERROR(
|
||||
decl, "The size of this local variable (%s%d Kb) exceeds the maximum allowed stack object size (%d Kb), "
|
||||
"you can increase this limit with --max-stack-object-size, but be aware that too large objects "
|
||||
"allocated on the stack may lead to the stack running out of memory.", size % 1024 == 0 ? "" : "over ",
|
||||
size / 1024,
|
||||
compiler.build.max_stack_object_size);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ bool sema_analyse_expr_value(SemaContext *context, Expr *expr);
|
||||
Expr *expr_access_inline_member(Expr *parent, Decl *parent_decl);
|
||||
bool sema_analyse_ct_expr(SemaContext *context, Expr *expr);
|
||||
Decl *sema_find_typed_operator(SemaContext *context, OperatorOverload operator_overload, SourceSpan span, Expr *lhs, Expr *rhs, bool *reverse);
|
||||
OverloadMatch sema_find_typed_operator_type(SemaContext *context, OperatorOverload operator_overload, OverloadType overloat_type, Type *lhs_type, Type *rhs_type, Expr *rhs, Decl **candidate_ref, OverloadMatch last_match, Decl **ambiguous_ref);
|
||||
OverloadMatch sema_find_typed_operator_type(SemaContext *context, OperatorOverload operator_overload, OverloadType overload_type, Type *lhs_type, Type *rhs_type, Expr *rhs, Decl **candidate_ref, OverloadMatch last_match, Decl **ambiguous_ref);
|
||||
BoolErr sema_type_has_equality_overload(SemaContext *context, Type *type);
|
||||
Decl *sema_find_untyped_operator(Type *type, OperatorOverload operator_overload, Decl *skipped);
|
||||
bool sema_insert_method_call(SemaContext *context, Expr *method_call, Decl *method_decl, Expr *parent, Expr **arguments, bool reverse_overload);
|
||||
|
||||
@@ -49,7 +49,7 @@ static inline bool sema_check_value_case(SemaContext *context, Type *switch_type
|
||||
static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, SourceSpan expr_span, CanonicalType *switch_type, Ast **cases);
|
||||
|
||||
static inline bool sema_analyse_statement_inner(SemaContext *context, Ast *statement);
|
||||
static bool sema_analyse_require(SemaContext *context, Ast *directive, AstId **asserts, SourceSpan source);
|
||||
static bool sema_analyse_require(SemaContext *context, Ast *directive, AstId **asserts, SourceSpan span);
|
||||
static bool sema_analyse_ensure(SemaContext *context, Ast *directive);
|
||||
static bool sema_analyse_optional_returns(SemaContext *context, Ast *directive);
|
||||
|
||||
@@ -880,11 +880,9 @@ static inline bool sema_analyse_try_unwrap(SemaContext *context, Expr *expr)
|
||||
{
|
||||
if (decl->var.kind == VARDECL_UNWRAPPED)
|
||||
{
|
||||
SEMA_ERROR(ident, "This variable is already unwrapped, so you cannot use 'try' on it again, please remove the 'try'.");
|
||||
return false;
|
||||
RETURN_SEMA_ERROR(ident, "This variable is already unwrapped, so you cannot use 'try' on it again, please remove the 'try'.");
|
||||
}
|
||||
SEMA_ERROR(ident, "Expected this variable to be an optional, otherwise it can't be used for unwrap, maybe you didn't intend to use 'try'?");
|
||||
return false;
|
||||
RETURN_SEMA_ERROR(ident, "Expected this variable to be an optional, otherwise it can't be used for unwrap, maybe you didn't intend to use 'try'?");
|
||||
}
|
||||
expr->expr_kind = EXPR_TRY;
|
||||
expr->try_expr = (ExprTry) { .decl = decl };
|
||||
@@ -929,7 +927,6 @@ static inline bool sema_analyse_try_unwrap(SemaContext *context, Expr *expr)
|
||||
if (!IS_OPTIONAL(optional))
|
||||
{
|
||||
RETURN_SEMA_ERROR(optional, "Expected an optional expression to 'try' here. If it isn't an optional, remove 'try'.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (var_type)
|
||||
@@ -959,9 +956,8 @@ static inline bool sema_analyse_try_unwrap(SemaContext *context, Expr *expr)
|
||||
|
||||
static inline bool sema_analyse_try_unwrap_chain(SemaContext *context, Expr *expr, CondType cond_type, CondResult *result)
|
||||
{
|
||||
ASSERT(cond_type == COND_TYPE_UNWRAP_BOOL);
|
||||
|
||||
ASSERT(expr->expr_kind == EXPR_TRY_UNWRAP_CHAIN);
|
||||
ASSERT_SPAN(expr, cond_type == COND_TYPE_UNWRAP_BOOL);
|
||||
ASSERT_SPAN(expr, expr->expr_kind == EXPR_TRY_UNWRAP_CHAIN);
|
||||
|
||||
FOREACH(Expr *, chain_element, expr->try_unwrap_chain_expr)
|
||||
{
|
||||
@@ -3239,8 +3235,7 @@ static bool sema_analyse_ensure(SemaContext *context, Ast *directive)
|
||||
{
|
||||
if (expr->expr_kind == EXPR_DECL)
|
||||
{
|
||||
SEMA_ERROR(expr, "Only expressions are allowed.");
|
||||
return false;
|
||||
RETURN_SEMA_ERROR(expr, "Only expressions are allowed.");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
|
||||
#define NO_ARENA 0
|
||||
#define MAX_VECTOR_WIDTH 65536
|
||||
#define MAX_STACK_OBJECT_SIZE (256 * 1024)
|
||||
#define DEFAULT_VECTOR_WIDTH 4096
|
||||
#define DEFAULT_STACK_OBJECT_SIZE 64
|
||||
#define MAX_ARRAY_SIZE INT64_MAX
|
||||
#define MAX_SOURCE_LOCATION_LEN 255
|
||||
#define PROJECT_JSON "project.json"
|
||||
|
||||
6
test/test_suite/statements/big_locals.c3
Normal file
6
test/test_suite/statements/big_locals.c3
Normal file
@@ -0,0 +1,6 @@
|
||||
import std;
|
||||
fn int main(String[] args)
|
||||
{
|
||||
int[1024 * 1024] x; // #error: The size of this local variable (4096 Kb) exceeds the maximum allowed stack object size (128 Kb)
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user