diff --git a/releasenotes.md b/releasenotes.md index a5fde39d0..c1f54cac9 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -38,7 +38,7 @@ - Converting between simd/non-simd bool vector would hit a compiler assert. #2691 - `i` suffixes were not caught when n < 8, causing an assert. - Parse error in `$defined` was not handled correctly, leading to an assertion. -- Assert when struct size would exceed 4 GB. +- Assert when struct/array size would exceed 4 GB. - Assert when encountering a malformed module alias. - Assert when encountering a test function with raw vaarg parameters. - `foo.x` was not always handled correctly when `foo` was optional. diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 5a3042816..4e27a2f67 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -48,7 +48,7 @@ typedef uint16_t FileId; #define MAX_ALIGNMENT ((ArrayIndex)(((uint64_t)2) << 28)) #define MAX_GENERIC_DEPTH 32 #define MAX_PRIORITY 0xFFFF -#define MAX_TYPE_SIZE UINT32_MAX +#define MAX_TYPE_SIZE (2U << 30) #define MAX_GLOBAL_DECL_STACK (65536) #define MAX_MODULE_NAME 31 #define MAX_MODULE_PATH 63 diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 8e8725ce2..913a02147 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -4586,7 +4586,63 @@ static bool sema_analyse_attributes_for_var(SemaContext *context, Decl *decl, bo if (!sema_analyse_attributes(context, decl, decl->attributes, domain, erase_decl)) return decl_poison(decl); return true; } - +static bool sema_type_is_valid_size(SemaContext *context, Type *type, SourceSpan span) +{ + Int128 size = i128_from_unsigned(1); +RETRY: + if (size.high || size.low > (uint64_t)MAX_TYPE_SIZE) + { + RETURN_SEMA_ERROR_AT(span, "This type would exceed max type size of %u GB.", MAX_TYPE_SIZE >> 30); + } + switch (type->type_kind) + { + case TYPE_BITSTRUCT: + ASSERT(type->decl->resolve_status == RESOLVE_DONE); + type = type->decl->strukt.container_type->type; + goto RETRY; + case TYPE_TYPEDEF: + type = type->decl->distinct->type; + goto RETRY; + case TYPE_ALIAS: + type = type->canonical; + goto RETRY; + case CT_TYPES: + case TYPE_FUNC_RAW: + case TYPE_FLEXIBLE_ARRAY: + return true; + case TYPE_OPTIONAL: + type = type->optional; + goto RETRY; + case TYPE_VOID: + return true; + case TYPE_BOOL: + case TYPE_TYPEID: + case ALL_INTS: + case ALL_FLOATS: + case TYPE_ANYFAULT: + case TYPE_INTERFACE: + case TYPE_ANY: + case TYPE_FUNC_PTR: + case TYPE_POINTER: + case TYPE_STRUCT: + case TYPE_UNION: + case TYPE_ENUM: + case TYPE_CONST_ENUM: + case TYPE_SLICE: + size = i128_mult64(size, type_size(type)); + break; + case VECTORS: + case TYPE_ARRAY: + size = i128_mult64(size, type->array.len); + type = type->array.base; + goto RETRY; + } + if (size.high || size.low > (uint64_t)MAX_TYPE_SIZE) + { + RETURN_SEMA_ERROR_AT(span, "This type would exceed max type size of %u GB.", MAX_TYPE_SIZE >> 30); + } + return true; +} static bool sema_analyse_variable_type(SemaContext *context, Type *type, SourceSpan span) { switch (sema_resolve_storage_type(context, type)) @@ -4975,6 +5031,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local, bool *c { if (!sema_set_alloca_alignment(context, decl->type, &decl->alignment)) return false; } + if (decl->type && !sema_type_is_valid_size(context, decl->type, decl->var.type_info ? type_infoptr(decl->var.type_info)->span : decl->span)) return false; if (decl->var.kind == VARDECL_LOCAL && !is_static && type_size(decl->type) > compiler.build.max_stack_object_size * 1024) { size_t size = type_size(decl->type); diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index 42d746a9e..3a84b1c6b 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -87,7 +87,7 @@ bool sema_resolve_array_like_len(SemaContext *context, TypeInfo *type_info, Arra { RETURN_VAL_SEMA_ERROR(type_info_poison(type_info), len_expr, "A vector may not exceed %d in bit width.", compiler.build.max_vector_size); } - RETURN_VAL_SEMA_ERROR(type_info_poison(type_info), len_expr, "The array length may not exceed %lld.", MAX_ARRAY_SIZE); + RETURN_VAL_SEMA_ERROR(type_info_poison(type_info), len_expr, "The array length may not exceed %lld.", (long long)MAX_ARRAY_SIZE); } // We're done, return the size and mark it as a success. *len_ref = (ArraySize)len.i.low; diff --git a/src/utils/common.h b/src/utils/common.h index 6b86cc982..a9798671b 100644 --- a/src/utils/common.h +++ b/src/utils/common.h @@ -27,7 +27,7 @@ #define DEFAULT_MAX_MACRO_ITERATIONS 0xFFFFF #define DEFAULT_VECTOR_WIDTH 4096 #define DEFAULT_STACK_OBJECT_SIZE 64 -#define MAX_ARRAY_SIZE INT64_MAX +#define MAX_ARRAY_SIZE (2U * 1024U * 1024U * 1024U) #define MAX_SOURCE_LOCATION_LEN 255 #define MAX_STRUCT_SIZE (2U * 1024U * 1024U * 1024U) #define PROJECT_JSON "project.json" diff --git a/test/test_suite/arrays/array_limit.c3 b/test/test_suite/arrays/array_limit.c3 new file mode 100644 index 000000000..8f9745856 --- /dev/null +++ b/test/test_suite/arrays/array_limit.c3 @@ -0,0 +1,5 @@ +fn int main() +{ + int[0x80000000][1] x; // #error: This type would exceed max type size of 2 GB. + return 0; +} \ No newline at end of file diff --git a/test/test_suite/arrays/array_limit_const.c3 b/test/test_suite/arrays/array_limit_const.c3 new file mode 100644 index 000000000..4f8d1e533 --- /dev/null +++ b/test/test_suite/arrays/array_limit_const.c3 @@ -0,0 +1,6 @@ +const FOO = (int[0x80000000][1]) {}; // #error: This type would exceed max type size of 2 GB. + +fn int main() +{ + return 0; +}