ziglang / zig

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

Sema: `@splat` when vector type has a zero-sized element type causes compiler segfault #21204

Open burgerindividual opened 1 month ago

burgerindividual commented 1 month ago

Zig Version

0.14.0-dev.1307+849c31a6c

Steps to Reproduce and Observed Behavior

The following code causes a hard crash (or SIGSEGV in release builds of the compiler) when compilation is attempted:

const Elem = u0; // can also be i0
const vector_len = 1; // can be any size other than 0

_ = @as(@Vector(vector_len, Elem), @splat(0));

During my debugging, I found that it happens because Sema.zirSplat has a code path for when the runtime bits of the destination is 0. An aggregate is created to be interned, but the intern doesn't have any checks for if the child element type has 0 bits. A hash is attempted on the value, but the value doesn't exist, and a segfault happens.

Expected Behavior

The compiler should be able to compile this, as it is valid code.

Vexu commented 4 weeks ago

Related to #19455, the fix for it in #19828 only works when the type is zero-sized because of the length.

Stack trace

``` thread 32402 panic: index out of bounds: index 1, len 0 Analyzing a.zig %23 = dbg_stmt(2, 5) %24 = int_type(u0) node_offset:8:18 to :8:20 %25 = dbg_var_val(%24, "Elem") %26 = dbg_stmt(3, 5) %27 = dbg_var_val(@one, "vector_len") %28 = dbg_stmt(5, 5) %29 = block_comptime({ %30 = vector_type(@one, %24) node_offset:11:13 to :11:38 %31 = break(%29, %30) }) node_offset:11:13 to :11:38 %32 = vector_elem_type(%29) node_offset:11:40 to :11:49 %33 = as_node(%32, @zero) node_offset:11:47 to :11:48 > %34 = splat(%29, %33) node_offset:11:40 to :11:49 %35 = as_node(%29, %34) node_offset:11:40 to :11:49 %36 = ensure_result_non_error(%35) node_offset:11:9 to :11:50 %37 = restore_err_ret_index_unconditional(.none) node_offset:7:1 to :7:5 %38 = ret_implicit(@void_value) token_offset:12:1 to :12:1 For full context, use the command zig ast-check -t a.zig /home/vexu/Documents/zig/zig/src/InternPool.zig:2575:49: 0xa81631a in hash64 (zig) .elems => |elems| for (elems[0..@intCast(len)]) |elem| ^ /home/vexu/Documents/zig/zig/src/InternPool.zig:7041:33: 0xa539e64 in getOrPutKeyEnsuringAdditionalCapacity (zig) const full_hash = key.hash64(ip); ^ /home/vexu/Documents/zig/zig/src/InternPool.zig:7032:52: 0xa2bdeb0 in getOrPutKey (zig) return ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, tid, key, 0); ^ /home/vexu/Documents/zig/zig/src/InternPool.zig:7168:33: 0xa0a247d in get (zig) var gop = try ip.getOrPutKey(gpa, tid, key); ^ /home/vexu/Documents/zig/zig/src/Zcu/PerThread.zig:2697:34: 0xa139e4d in intern (zig) return pt.zcu.intern_pool.get(pt.zcu.gpa, pt.tid, key); ^ /home/vexu/Documents/zig/zig/src/Sema.zig:24463:46: 0xb1a7048 in zirSplat (zig) const empty_aggregate = try pt.intern(.{ .aggregate = .{ ^ /home/vexu/Documents/zig/zig/src/Sema.zig:1157:63: 0xad30fff in analyzeBodyInner (zig) .splat => try sema.zirSplat(block, inst), ```