diff --git a/releasenotes.md b/releasenotes.md index b16146ee5..cec8db846 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -18,6 +18,7 @@ - Defer resolution of declarations when looked up in `def` aliased #1559. - Adding constants to the Json AST #1540 - Adding info to the globals inside Json AST #1541 +- Null-check function pointer invocation #1573. ### Fixes - `Unsupported int[*] $x = { 1, 2, 3, 4 }` #1489. diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 3e4eb4d65..368a92961 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -6206,6 +6206,16 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr // 1d. Load it as a value func = llvm_load_value_store(c, &func_value); + if (safe_mode_enabled()) + { + LLVMValueRef check = LLVMBuildICmp(c->builder, LLVMIntEQ, func, LLVMConstNull(c->ptr_type), "checknull"); + scratch_buffer_clear(); + scratch_buffer_append("Calling null function pointer, '"); + span_to_scratch(function->span); + scratch_buffer_append("' was null."); + llvm_emit_panic_on_true(c, check, scratch_buffer_to_string(), function->span, NULL, NULL, NULL); + } + // 1e. Calculate the function type func_type = llvm_get_type(c, type); } diff --git a/test/test_suite/functions/func_ptr_null.check.c3t b/test/test_suite/functions/func_ptr_null.check.c3t new file mode 100644 index 000000000..5b30e0e23 --- /dev/null +++ b/test/test_suite/functions/func_ptr_null.check.c3t @@ -0,0 +1,43 @@ +// #target: macos-aarch64 +// #safe: yes +module test; +def TestFn = fn void(); + +fn int main() +{ + TestFn foo; + foo(); + return 0; +} + +/* #expect: test.ll + + +define i32 @main() #0 { +entry: + %foo = alloca ptr, align 8 + %taddr = alloca %"char[]", align 8 + %taddr1 = alloca %"char[]", align 8 + %taddr2 = alloca %"char[]", align 8 + store ptr null, ptr %foo, align 8 + %0 = load ptr, ptr %foo, align 8 + %checknull = icmp eq ptr %0, null + %1 = call i1 @llvm.expect.i1(i1 %checknull, i1 false) + br i1 %1, label %panic, label %checkok + +checkok: ; preds = %entry + call void %0() + ret i32 0 + +panic: ; preds = %entry + store %"char[]" { ptr @.panic_msg, i64 46 }, ptr %taddr, align 8 + %2 = load [2 x i64], ptr %taddr, align 8 + store %"char[]" { ptr @.file, i64 22 }, ptr %taddr1, align 8 + %3 = load [2 x i64], ptr %taddr1, align 8 + store %"char[]" { ptr @.func, i64 4 }, ptr %taddr2, align 8 + %4 = load [2 x i64], ptr %taddr2, align 8 + %5 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %5([2 x i64] %2, [2 x i64] %3, [2 x i64] %4, i32 7) + unreachable +} +