Commit d4d2718bca

Andrew Kelley <andrew@ziglang.org>
2019-02-14 06:40:39
comptime detection of casting null to pointer
See #1059
1 parent 5699ab5
Changed files (2)
src/ir.cpp
@@ -20645,12 +20645,23 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
     }
 
     if (instr_is_comptime(ptr)) {
-        // Undefined is OK here; @ptrCast is defined to reinterpret the bit pattern
-        // of the pointer as the new pointer type.
-        ConstExprValue *val = ir_resolve_const(ira, ptr, UndefOk);
+        bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type);
+        UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad;
+        ConstExprValue *val = ir_resolve_const(ira, ptr, is_undef_allowed);
         if (!val)
             return ira->codegen->invalid_instruction;
 
+        if (val->special == ConstValSpecialStatic) {
+            bool is_addr_zero = val->data.x_ptr.special == ConstPtrSpecialNull ||
+                (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr &&
+                    val->data.x_ptr.data.hard_coded_addr.addr == 0);
+            if (is_addr_zero && !dest_allows_addr_zero) {
+                ir_add_error(ira, source_instr,
+                        buf_sprintf("null pointer casted to type '%s'", buf_ptr(&dest_type->name)));
+                return ira->codegen->invalid_instruction;
+            }
+        }
+
         IrInstruction *result = ir_const(ira, source_instr, dest_type);
         copy_const_val(&result->value, val, false);
         result->value.type = dest_type;
test/compile_errors.zig
@@ -1,6 +1,26 @@
 const tests = @import("tests.zig");
 
 pub fn addCases(cases: *tests.CompileErrorContext) void {
+    cases.addTest(
+        "implicit casting null c pointer to zig pointer",
+        \\comptime {
+        \\    var c_ptr: [*c]u8 = 0;
+        \\    var zig_ptr: *u8 = c_ptr;
+        \\}
+    ,
+        ".tmp_source.zig:3:24: error: null pointer casted to type '*u8'",
+    );
+
+    cases.addTest(
+        "implicit casting undefined c pointer to zig pointer",
+        \\comptime {
+        \\    var c_ptr: [*c]u8 = undefined;
+        \\    var zig_ptr: *u8 = c_ptr;
+        \\}
+    ,
+        ".tmp_source.zig:3:24: error: use of undefined value here causes undefined behavior",
+    );
+
     cases.addTest(
         "implicit casting C pointers which would mess up null semantics",
         \\export fn entry() void {