ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
34.5k stars 2.52k forks source link

stage2: Panic when mutating through reinterpreted comptime pointer #12005

Open topolarity opened 2 years ago

topolarity commented 2 years ago

Zig Version

0.10.0-dev.2847+6fc9f6c5f

Steps to Reproduce

test {
    comptime {
        const T = extern struct {
            a: u32 align(8),
            b: u32
        };

        var x = T{ .a = 2, .b = 3 };
        var y = @ptrCast(*u64, &x.a);
        _ = y.*; // Works OK
        //y.* = 0; // panic: reached unreachable code
    }
}

Expected Behavior

This should compile fine and perform the store successfully at comptime, since the reinterpreted memory is well-defined.

Actual Behavior

thread 12573 panic: reached unreachable code
Analyzing test3.zig: test3.zig:test_0
      %5 = dbg_block_begin())
      %6 = dbg_stmt(2, 5)
      %7 = extended(struct_decl(known_non_opv, dbg_var, Extern, {}, {%8..%10}, {
        a: @Zir.Inst.Ref.u32_type align(%9),
        b: @Zir.Inst.Ref.u32_type,
      }) node_offset:5:26
      %11 = alloc_inferred_comptime_mut() node_offset:10:9
      %12 = validate_struct_init_ty(%7) node_offset:10:18
      %13 = coerce_result_ptr(%7, %11) node_offset:10:18
      %14 = field_ptr(%13, "a") node_offset:10:25
      %15 = int(2)
      %16 = store_node(%14, %15) node_offset:10:25
      %17 = field_ptr(%13, "b") node_offset:10:33
      %18 = int(3)
      %19 = store_node(%17, %18) node_offset:10:33
      %20 = validate_struct_init_comptime({
        %14 = field_ptr(%13, "a") node_offset:10:25
        %17 = field_ptr(%13, "b") node_offset:10:33
      }) node_offset:10:18
      %21 = resolve_inferred_alloc(%11) node_offset:10:9
      %22 = alloc_inferred_comptime_mut() node_offset:11:9
      %23 = ptr_type_simple(@Zir.Inst.Ref.u64_type, One)
      %24 = field_ptr(%11, "a") node_offset:11:34
      %25 = ptr_cast(%23, %24) node_offset:11:17
      %26 = store_to_inferred_ptr(%22, %25)
      %27 = resolve_inferred_alloc(%22) node_offset:11:9
      %28 = load(%22) node_offset:12:13
      %29 = validate_deref(%28) token_offset:12:14
      %30 = load(%28) node_offset:12:14
      %31 = ensure_result_non_error(%30) node_offset:12:14
      %32 = load(%22) node_offset:13:9
      %33 = validate_deref(%32) token_offset:13:10
      %35 = dbg_block_end())
    > %34 = store_node(%32, @Zir.Inst.Ref.zero) node_offset:13:15
      %36 = ret_tok(@Zir.Inst.Ref.void_value) token_offset:15:1
    For full context, use the command
      zig ast-check -t test3.zig

/home/topolarity/repos/zig/lib/std/debug.zig:281:14: 0x2cf2c28 in std.debug.assert (zig)
    if (!ok) unreachable; // assertion failure
             ^
/home/topolarity/repos/zig/lib/std/math/big/int.zig:2211:15: 0x30e3537 in std.math.big.int.Const.writeTwosComplement (zig)
        assert(buffer.len >= byte_count);
              ^
/home/topolarity/repos/zig/src/value.zig:1210:43: 0x367e757 in value.Value.writeToMemory (zig)
                bigint.writeTwosComplement(buffer, bits, abi_size, target.cpu.arch.endian());
                                          ^
/home/topolarity/repos/zig/src/Sema.zig:20882:38: 0x34847d8 in Sema.storePtrVal (zig)
            operand_val.writeToMemory(operand_ty, sema.mod, buffer[reinterpret.byte_offset..]);
                                     ^
/home/topolarity/repos/zig/src/Sema.zig:20792:33: 0x347edcb in Sema.storePtr2 (zig)
            try sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty);
                                ^
/home/topolarity/repos/zig/src/Sema.zig:20726:26: 0x350a73a in Sema.storePtr (zig)
    return sema.storePtr2(block, src, ptr, src, uncasted_operand, src, .store);
                         ^
/home/topolarity/repos/zig/src/Sema.zig:4123:25: 0x3469926 in Sema.zirStoreNode (zig)
    return sema.storePtr(block, src, ptr, operand);
                        ^
/home/topolarity/repos/zig/src/Sema.zig:1034:38: 0x328365a in Sema.analyzeBodyInner (zig)
                try sema.zirStoreNode(block, inst);
                                     ^
/home/topolarity/repos/zig/src/Sema.zig:598:30: 0x326bfaa in Sema.analyzeBody (zig)
    _ = sema.analyzeBodyInner(block, body) catch |err| switch (err) {
                             ^
/home/topolarity/repos/zig/src/Module.zig:5049:21: 0x309dca6 in Module.analyzeFnBody (zig)
    sema.analyzeBody(&inner_block, fn_info.body) catch |err| switch (err) {
                    ^
/home/topolarity/repos/zig/src/Module.zig:3777:40: 0x3080b80 in Module.ensureFuncBodyAnalyzed (zig)
            var air = mod.analyzeFnBody(func, sema_arena) catch |err| switch (err) {
                                       ^
/home/topolarity/repos/zig/src/Compilation.zig:2937:42: 0x2dfe0ca in Compilation.processOneJob (zig)
            module.ensureFuncBodyAnalyzed(func) catch |err| switch (err) {
                                         ^
/home/topolarity/repos/zig/src/Compilation.zig:2869:30: 0x2deac1d in Compilation.performAllTheWork (zig)
            try processOneJob(comp, work_item);
                             ^
/home/topolarity/repos/zig/src/Compilation.zig:2218:31: 0x2de32a2 in Compilation.update (zig)
    try comp.performAllTheWork(main_progress_node);
                              ^
/home/topolarity/repos/zig/src/main.zig:3245:20: 0x2d4e85f in updateModule (zig)
    try comp.update();
                   ^
/home/topolarity/repos/zig/src/main.zig:2934:17: 0x2d169da in buildOutputType (zig)
    updateModule(gpa, comp, hook) catch |err| switch (err) {
                ^
/home/topolarity/repos/zig/src/main.zig:225:31: 0x2cfb306 in mainArgs (zig)
        return buildOutputType(gpa, arena, args, .zig_test);
                              ^
/home/topolarity/repos/zig/src/main.zig:174:20: 0x2cfa354 in main (zig)
    return mainArgs(gpa, arena, args);
                   ^
/home/topolarity/repos/zig/lib/std/start.zig:581:37: 0x321fb07 in std.start.callMain (zig)
            const result = root.main() catch |err| {
                                    ^
/home/topolarity/repos/zig/lib/std/start.zig:515:12: 0x2cfcda7 in std.start.callMainWithArgs (zig)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/home/topolarity/repos/zig/lib/std/start.zig:480:12: 0x2cfcb52 in std.start.main (zig)
    return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });
           ^
???:?:?: 0x7fc00a3e07fc in ??? (???)
[1]    12573 IOT instruction  ../zig/stage2/bin/zig test test3.zig
perillo commented 8 months ago

@topolarity I tried compiling your example with 0.12.0-dev.2341+92211135 and it works correctly.

Can you confirm?

Vexu commented 8 months ago

Still causes OOB access, did you make sure to uncomment the last line?

perillo commented 8 months ago

Still causes OOB access, did you make sure to uncomment the last line?

Yes, I ran zig test test.zig with the following code:

test {
    comptime {
        const T = extern struct { a: u32 align(8), b: u32 };

        var x = T{ .a = 2, .b = 3 };
        var y: *u64 = @ptrCast(&x.a);
        _ = &y;
        _ = y.*; // Works OK
        y.* = 0; // panic: reached unreachable code
    }
}

The output is

All 1 tests passed.
Vexu commented 8 months ago

You need a debug build to hit the safety check.