Commit 160367e0dd

Andrew Kelley <andrew@ziglang.org>
2020-03-19 22:23:53
fix compile error for reading past end of pointer casted array
1 parent 6b6f2fc
Changed files (2)
src/ir.cpp
@@ -19971,6 +19971,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
         buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf), pointee);
         if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val)))
             return err;
+        buf_deinit(&buf);
         return ErrorNone;
     }
 
@@ -19990,7 +19991,31 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
                 dst_size, buf_ptr(&pointee->type->name), src_size));
             return ErrorSemanticAnalyzeFail;
         }
-        case ConstPtrSpecialSubArray:
+        case ConstPtrSpecialSubArray: {
+            ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val;
+            assert(array_val->type->id == ZigTypeIdArray);
+            if (array_val->data.x_array.special != ConstArraySpecialNone)
+                zig_panic("TODO");
+            if (dst_size > src_size) {
+                size_t elem_index = ptr_val->data.x_ptr.data.base_array.elem_index;
+                opt_ir_add_error_node(ira, codegen, source_node,
+                    buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from %s at index %" ZIG_PRI_usize " which is %" ZIG_PRI_usize " bytes",
+                        dst_size, buf_ptr(&array_val->type->name), elem_index, src_size));
+                return ErrorSemanticAnalyzeFail;
+            }
+            size_t elem_size = src_size;
+            size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1);
+            Buf buf = BUF_INIT;
+            buf_resize(&buf, elem_count * elem_size);
+            for (size_t i = 0; i < elem_count; i += 1) {
+                ZigValue *elem_val = &array_val->data.x_array.data.s_none.elements[i];
+                buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val);
+            }
+            if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val)))
+                return err;
+            buf_deinit(&buf);
+            return ErrorNone;
+        }
         case ConstPtrSpecialBaseArray: {
             ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val;
             assert(array_val->type->id == ZigTypeIdArray);
@@ -20014,6 +20039,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
             }
             if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val)))
                 return err;
+            buf_deinit(&buf);
             return ErrorNone;
         }
         case ConstPtrSpecialBaseStruct:
test/compile_errors.zig
@@ -1903,17 +1903,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         "tmp.zig:7:15: error: switch must handle all possibilities",
     });
 
-    // TODO uncomment before merging branch
-    //cases.add("reading past end of pointer casted array",
-    //    \\comptime {
-    //    \\    const array: [4]u8 = "aoeu".*;
-    //    \\    const sub_array = array[1..];
-    //    \\    const int_ptr = @ptrCast(*const u24, sub_array);
-    //    \\    const deref = int_ptr.*;
-    //    \\}
-    //, &[_][]const u8{
-    //    "tmp.zig:5:26: error: attempt to read 4 bytes from [4]u8 at index 1 which is 3 bytes",
-    //});
+    cases.add("reading past end of pointer casted array",
+        \\comptime {
+        \\    const array: [4]u8 = "aoeu".*;
+        \\    const sub_array = array[1..];
+        \\    const int_ptr = @ptrCast(*const u24, sub_array);
+        \\    const deref = int_ptr.*;
+        \\}
+    , &[_][]const u8{
+        "tmp.zig:5:26: error: attempt to read 4 bytes from [4]u8 at index 1 which is 3 bytes",
+    });
 
     cases.add("error note for function parameter incompatibility",
         \\fn do_the_thing(func: fn (arg: i32) void) void {}