From 229fdd6193b8832be1730533b0b45db5ff282c7e Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Tue, 5 Aug 2025 02:55:32 +0200 Subject: [PATCH] Detect recursive creation of generics #2366. --- releasenotes.md | 1 + src/compiler/compiler_internal.h | 2 ++ src/compiler/sema_types.c | 6 ++++++ test/test_suite/generic/recursive_generic.c3 | 14 ++++++++++++++ 4 files changed, 23 insertions(+) create mode 100644 test/test_suite/generic/recursive_generic.c3 diff --git a/releasenotes.md b/releasenotes.md index 33b0a51de..750fcdcbd 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -14,6 +14,7 @@ - Reduce allocated Vmem for the compiler on 32 bit machines. - Bug causing a compiler error when parsing a broken lambda inside of an expression. - Fixed: regression in comments for `@deprecated` and `@pure`. +- Detect recursive creation of generics #2366. ### Stdlib changes - Add `==` to `Pair`, `Triple` and TzDateTime. Add print to `Pair` and `Triple`. diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index b6946b9b2..273efa1c6 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -48,6 +48,7 @@ typedef uint16_t FileId; #define MAX_BITSTRUCT 0x1000 #define MAX_MEMBERS ((StructIndex)1) << 15 #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_GLOBAL_DECL_STACK (65536) @@ -1931,6 +1932,7 @@ typedef struct Linking linking; GlobalContext context; const char *obj_output; + int generic_depth; } CompilerState; extern CompilerState compiler; diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index a2e9f1f1d..8054d7071 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -450,8 +450,14 @@ INLINE bool sema_resolve_generic_type(SemaContext *context, TypeInfo *type_info) ASSERT_SPAN(inner, inner->resolve_status == RESOLVE_NOT_DONE); bool was_recursive = false; + if (compiler.generic_depth >= MAX_GENERIC_DEPTH) + { + RETURN_SEMA_ERROR(type_info, "Generic resolution of this type has become deeply nested, it was aborted after reaching %d recursions.", compiler.generic_depth); + } + compiler.generic_depth++; Decl *type = sema_analyse_parameterized_identifier(context, inner->unresolved.path, inner->unresolved.name, inner->span, type_info->generic.params, &was_recursive); + compiler.generic_depth--; if (!decl_ok(type)) return false; if (!sema_analyse_decl(context, type)) return false; type_info->type = type->type; diff --git a/test/test_suite/generic/recursive_generic.c3 b/test/test_suite/generic/recursive_generic.c3 new file mode 100644 index 000000000..0cdf3475a --- /dev/null +++ b/test/test_suite/generic/recursive_generic.c3 @@ -0,0 +1,14 @@ +module test; +import test1; + +fn int main() => 0; + +Aa {int} a; + +module test1 {Type}; +import test2; +alias Cc = Aa {Bb {Type}}; // #error: Generic resolution of this type has become deeply nested +struct Aa {Type a;} + +module test2 {Type}; +struct Bb {Type b;} \ No newline at end of file