astgen: fix OPT() sentinel crashes in rlExpr and exprRl
The C parser uses OPT() macro which stores UINT32_MAX as the "none" sentinel for optional AST node indices in extra_data. The rlExpr (AstRlAnnotate) and exprRl functions were checking `!= 0` for these fields, treating UINT32_MAX as a valid node index and causing segfaults. Fixed optional field checks for fn_proto_one, fn_proto extra data (param, align, addrspace, section, callconv), while cont_expr, global_var_decl type_node, and slice_sentinel end_node. Also added behavior test corpus files and FAIL: diagnostic to the corpus test runner. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5866,6 +5866,8 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
|
|||||||
const Ast* stree = ag->tree;
|
const Ast* stree = ag->tree;
|
||||||
uint32_t start_node = stree->extra_data.arr[nd.rhs];
|
uint32_t start_node = stree->extra_data.arr[nd.rhs];
|
||||||
uint32_t end_node = stree->extra_data.arr[nd.rhs + 1];
|
uint32_t end_node = stree->extra_data.arr[nd.rhs + 1];
|
||||||
|
if (end_node == UINT32_MAX)
|
||||||
|
end_node = 0; // OPT() sentinel
|
||||||
uint32_t sentinel_node = stree->extra_data.arr[nd.rhs + 2];
|
uint32_t sentinel_node = stree->extra_data.arr[nd.rhs + 2];
|
||||||
// slice_length optimization (AstGen.zig:887-906).
|
// slice_length optimization (AstGen.zig:887-906).
|
||||||
if (end_node != 0 && stree->nodes.tags[nd.lhs] == AST_NODE_SLICE_OPEN
|
if (end_node != 0 && stree->nodes.tags[nd.lhs] == AST_NODE_SLICE_OPEN
|
||||||
@@ -14258,6 +14260,8 @@ static bool rlExpr(
|
|||||||
} else if (tag == AST_NODE_LOCAL_VAR_DECL
|
} else if (tag == AST_NODE_LOCAL_VAR_DECL
|
||||||
|| tag == AST_NODE_GLOBAL_VAR_DECL) {
|
|| tag == AST_NODE_GLOBAL_VAR_DECL) {
|
||||||
type_node = tree->extra_data.arr[nd.lhs];
|
type_node = tree->extra_data.arr[nd.lhs];
|
||||||
|
if (type_node == UINT32_MAX)
|
||||||
|
type_node = 0; // OPT() sentinel
|
||||||
init_node = nd.rhs;
|
init_node = nd.rhs;
|
||||||
} else { // ALIGNED_VAR_DECL
|
} else { // ALIGNED_VAR_DECL
|
||||||
init_node = nd.rhs;
|
init_node = nd.rhs;
|
||||||
@@ -14498,6 +14502,8 @@ static bool rlExpr(
|
|||||||
body_node = tree->extra_data.arr[nd.rhs + 1];
|
body_node = tree->extra_data.arr[nd.rhs + 1];
|
||||||
} else {
|
} else {
|
||||||
cont_node = tree->extra_data.arr[nd.rhs];
|
cont_node = tree->extra_data.arr[nd.rhs];
|
||||||
|
if (cont_node == UINT32_MAX)
|
||||||
|
cont_node = 0; // OPT() sentinel
|
||||||
body_node = tree->extra_data.arr[nd.rhs + 1];
|
body_node = tree->extra_data.arr[nd.rhs + 1];
|
||||||
else_node = tree->extra_data.arr[nd.rhs + 2];
|
else_node = tree->extra_data.arr[nd.rhs + 2];
|
||||||
}
|
}
|
||||||
@@ -14635,7 +14641,7 @@ static bool rlExpr(
|
|||||||
ss.end = tree->extra_data.arr[nd.rhs + 1];
|
ss.end = tree->extra_data.arr[nd.rhs + 1];
|
||||||
ss.sentinel = tree->extra_data.arr[nd.rhs + 2];
|
ss.sentinel = tree->extra_data.arr[nd.rhs + 2];
|
||||||
(void)rlExpr(ag, ss.start, block, RL_RI_TYPE_ONLY);
|
(void)rlExpr(ag, ss.start, block, RL_RI_TYPE_ONLY);
|
||||||
if (ss.end != 0)
|
if (ss.end != UINT32_MAX)
|
||||||
(void)rlExpr(ag, ss.end, block, RL_RI_TYPE_ONLY);
|
(void)rlExpr(ag, ss.end, block, RL_RI_TYPE_ONLY);
|
||||||
(void)rlExpr(ag, ss.sentinel, block, RL_RI_NONE);
|
(void)rlExpr(ag, ss.sentinel, block, RL_RI_NONE);
|
||||||
return false;
|
return false;
|
||||||
@@ -15047,16 +15053,16 @@ static bool rlExpr(
|
|||||||
fp.addrspace_expr = tree->extra_data.arr[pnd.lhs + 2];
|
fp.addrspace_expr = tree->extra_data.arr[pnd.lhs + 2];
|
||||||
fp.section_expr = tree->extra_data.arr[pnd.lhs + 3];
|
fp.section_expr = tree->extra_data.arr[pnd.lhs + 3];
|
||||||
fp.callconv_expr = tree->extra_data.arr[pnd.lhs + 4];
|
fp.callconv_expr = tree->extra_data.arr[pnd.lhs + 4];
|
||||||
if (fp.param != 0)
|
if (fp.param != UINT32_MAX)
|
||||||
(void)rlExpr(ag, fp.param, block, RL_RI_TYPE_ONLY);
|
(void)rlExpr(ag, fp.param, block, RL_RI_TYPE_ONLY);
|
||||||
if (fp.align_expr != 0)
|
if (fp.align_expr != UINT32_MAX)
|
||||||
(void)rlExpr(ag, fp.align_expr, block, RL_RI_TYPE_ONLY);
|
(void)rlExpr(ag, fp.align_expr, block, RL_RI_TYPE_ONLY);
|
||||||
if (fp.addrspace_expr != 0)
|
if (fp.addrspace_expr != UINT32_MAX)
|
||||||
(void)rlExpr(
|
(void)rlExpr(
|
||||||
ag, fp.addrspace_expr, block, RL_RI_TYPE_ONLY);
|
ag, fp.addrspace_expr, block, RL_RI_TYPE_ONLY);
|
||||||
if (fp.section_expr != 0)
|
if (fp.section_expr != UINT32_MAX)
|
||||||
(void)rlExpr(ag, fp.section_expr, block, RL_RI_TYPE_ONLY);
|
(void)rlExpr(ag, fp.section_expr, block, RL_RI_TYPE_ONLY);
|
||||||
if (fp.callconv_expr != 0)
|
if (fp.callconv_expr != UINT32_MAX)
|
||||||
(void)rlExpr(ag, fp.callconv_expr, block, RL_RI_TYPE_ONLY);
|
(void)rlExpr(ag, fp.callconv_expr, block, RL_RI_TYPE_ONLY);
|
||||||
} else if (ptag == AST_NODE_FN_PROTO) {
|
} else if (ptag == AST_NODE_FN_PROTO) {
|
||||||
return_type = pnd.rhs;
|
return_type = pnd.rhs;
|
||||||
@@ -15070,14 +15076,14 @@ static bool rlExpr(
|
|||||||
for (uint32_t i = fp.params_start; i < fp.params_end; i++)
|
for (uint32_t i = fp.params_start; i < fp.params_end; i++)
|
||||||
(void)rlExpr(
|
(void)rlExpr(
|
||||||
ag, tree->extra_data.arr[i], block, RL_RI_TYPE_ONLY);
|
ag, tree->extra_data.arr[i], block, RL_RI_TYPE_ONLY);
|
||||||
if (fp.align_expr != 0)
|
if (fp.align_expr != UINT32_MAX)
|
||||||
(void)rlExpr(ag, fp.align_expr, block, RL_RI_TYPE_ONLY);
|
(void)rlExpr(ag, fp.align_expr, block, RL_RI_TYPE_ONLY);
|
||||||
if (fp.addrspace_expr != 0)
|
if (fp.addrspace_expr != UINT32_MAX)
|
||||||
(void)rlExpr(
|
(void)rlExpr(
|
||||||
ag, fp.addrspace_expr, block, RL_RI_TYPE_ONLY);
|
ag, fp.addrspace_expr, block, RL_RI_TYPE_ONLY);
|
||||||
if (fp.section_expr != 0)
|
if (fp.section_expr != UINT32_MAX)
|
||||||
(void)rlExpr(ag, fp.section_expr, block, RL_RI_TYPE_ONLY);
|
(void)rlExpr(ag, fp.section_expr, block, RL_RI_TYPE_ONLY);
|
||||||
if (fp.callconv_expr != 0)
|
if (fp.callconv_expr != UINT32_MAX)
|
||||||
(void)rlExpr(ag, fp.callconv_expr, block, RL_RI_TYPE_ONLY);
|
(void)rlExpr(ag, fp.callconv_expr, block, RL_RI_TYPE_ONLY);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -15101,16 +15107,16 @@ static bool rlExpr(
|
|||||||
fp.addrspace_expr = tree->extra_data.arr[nd.lhs + 2];
|
fp.addrspace_expr = tree->extra_data.arr[nd.lhs + 2];
|
||||||
fp.section_expr = tree->extra_data.arr[nd.lhs + 3];
|
fp.section_expr = tree->extra_data.arr[nd.lhs + 3];
|
||||||
fp.callconv_expr = tree->extra_data.arr[nd.lhs + 4];
|
fp.callconv_expr = tree->extra_data.arr[nd.lhs + 4];
|
||||||
if (fp.param != 0)
|
if (fp.param != UINT32_MAX)
|
||||||
(void)rlExpr(ag, fp.param, block, RL_RI_TYPE_ONLY);
|
(void)rlExpr(ag, fp.param, block, RL_RI_TYPE_ONLY);
|
||||||
if (fp.align_expr != 0)
|
if (fp.align_expr != UINT32_MAX)
|
||||||
(void)rlExpr(ag, fp.align_expr, block, RL_RI_TYPE_ONLY);
|
(void)rlExpr(ag, fp.align_expr, block, RL_RI_TYPE_ONLY);
|
||||||
if (fp.addrspace_expr != 0)
|
if (fp.addrspace_expr != UINT32_MAX)
|
||||||
(void)rlExpr(
|
(void)rlExpr(
|
||||||
ag, fp.addrspace_expr, block, RL_RI_TYPE_ONLY);
|
ag, fp.addrspace_expr, block, RL_RI_TYPE_ONLY);
|
||||||
if (fp.section_expr != 0)
|
if (fp.section_expr != UINT32_MAX)
|
||||||
(void)rlExpr(ag, fp.section_expr, block, RL_RI_TYPE_ONLY);
|
(void)rlExpr(ag, fp.section_expr, block, RL_RI_TYPE_ONLY);
|
||||||
if (fp.callconv_expr != 0)
|
if (fp.callconv_expr != UINT32_MAX)
|
||||||
(void)rlExpr(ag, fp.callconv_expr, block, RL_RI_TYPE_ONLY);
|
(void)rlExpr(ag, fp.callconv_expr, block, RL_RI_TYPE_ONLY);
|
||||||
} else if (tag == AST_NODE_FN_PROTO) {
|
} else if (tag == AST_NODE_FN_PROTO) {
|
||||||
return_type = nd.rhs;
|
return_type = nd.rhs;
|
||||||
@@ -15124,14 +15130,14 @@ static bool rlExpr(
|
|||||||
for (uint32_t i = fp.params_start; i < fp.params_end; i++)
|
for (uint32_t i = fp.params_start; i < fp.params_end; i++)
|
||||||
(void)rlExpr(
|
(void)rlExpr(
|
||||||
ag, tree->extra_data.arr[i], block, RL_RI_TYPE_ONLY);
|
ag, tree->extra_data.arr[i], block, RL_RI_TYPE_ONLY);
|
||||||
if (fp.align_expr != 0)
|
if (fp.align_expr != UINT32_MAX)
|
||||||
(void)rlExpr(ag, fp.align_expr, block, RL_RI_TYPE_ONLY);
|
(void)rlExpr(ag, fp.align_expr, block, RL_RI_TYPE_ONLY);
|
||||||
if (fp.addrspace_expr != 0)
|
if (fp.addrspace_expr != UINT32_MAX)
|
||||||
(void)rlExpr(
|
(void)rlExpr(
|
||||||
ag, fp.addrspace_expr, block, RL_RI_TYPE_ONLY);
|
ag, fp.addrspace_expr, block, RL_RI_TYPE_ONLY);
|
||||||
if (fp.section_expr != 0)
|
if (fp.section_expr != UINT32_MAX)
|
||||||
(void)rlExpr(ag, fp.section_expr, block, RL_RI_TYPE_ONLY);
|
(void)rlExpr(ag, fp.section_expr, block, RL_RI_TYPE_ONLY);
|
||||||
if (fp.callconv_expr != 0)
|
if (fp.callconv_expr != UINT32_MAX)
|
||||||
(void)rlExpr(ag, fp.callconv_expr, block, RL_RI_TYPE_ONLY);
|
(void)rlExpr(ag, fp.callconv_expr, block, RL_RI_TYPE_ONLY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -286,7 +286,7 @@ fn expectEqualZir(gpa: Allocator, ref: Zir, got: c.Zir) !void {
|
|||||||
for (0..265) |t| {
|
for (0..265) |t| {
|
||||||
if (ref_counts[t] != got_counts[t])
|
if (ref_counts[t] != got_counts[t])
|
||||||
std.debug.print("tag {d}: ref={d} got={d} (diff={d})\n", .{
|
std.debug.print("tag {d}: ref={d} got={d} (diff={d})\n", .{
|
||||||
t, ref_counts[t], got_counts[t],
|
t, ref_counts[t], got_counts[t],
|
||||||
@as(i32, @intCast(got_counts[t])) - @as(i32, @intCast(ref_counts[t])),
|
@as(i32, @intCast(got_counts[t])) - @as(i32, @intCast(ref_counts[t])),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -787,6 +787,27 @@ const corpus_files = .{
|
|||||||
.{ "parser_test.zig", @embedFile("parser_test.zig") },
|
.{ "parser_test.zig", @embedFile("parser_test.zig") },
|
||||||
.{ "test_all.zig", @embedFile("test_all.zig") },
|
.{ "test_all.zig", @embedFile("test_all.zig") },
|
||||||
.{ "tokenizer_test.zig", @embedFile("tokenizer_test.zig") },
|
.{ "tokenizer_test.zig", @embedFile("tokenizer_test.zig") },
|
||||||
|
|
||||||
|
.{ "optional.zig", @embedFile("../test/behavior/optional.zig") },
|
||||||
|
.{ "call.zig", @embedFile("../test/behavior/call.zig") },
|
||||||
|
.{ "pointers.zig", @embedFile("../test/behavior/pointers.zig") },
|
||||||
|
.{ "type.zig", @embedFile("../test/behavior/type.zig") },
|
||||||
|
.{ "enum.zig", @embedFile("../test/behavior/enum.zig") },
|
||||||
|
.{ "switch_on_captured_error.zig", @embedFile("../test/behavior/switch_on_captured_error.zig") },
|
||||||
|
.{ "error.zig", @embedFile("../test/behavior/error.zig") },
|
||||||
|
.{ "switch.zig", @embedFile("../test/behavior/switch.zig") },
|
||||||
|
.{ "array.zig", @embedFile("../test/behavior/array.zig") },
|
||||||
|
.{ "slice.zig", @embedFile("../test/behavior/slice.zig") },
|
||||||
|
.{ "basic.zig", @embedFile("../test/behavior/basic.zig") },
|
||||||
|
.{ "packed-struct.zig", @embedFile("../test/behavior/packed-struct.zig") },
|
||||||
|
.{ "eval.zig", @embedFile("../test/behavior/eval.zig") },
|
||||||
|
.{ "field_parent_ptr.zig", @embedFile("../test/behavior/field_parent_ptr.zig") },
|
||||||
|
.{ "struct.zig", @embedFile("../test/behavior/struct.zig") },
|
||||||
|
.{ "floatop.zig", @embedFile("../test/behavior/floatop.zig") },
|
||||||
|
.{ "union.zig", @embedFile("../test/behavior/union.zig") },
|
||||||
|
.{ "math.zig", @embedFile("../test/behavior/math.zig") },
|
||||||
|
.{ "vector.zig", @embedFile("../test/behavior/vector.zig") },
|
||||||
|
.{ "cast.zig", @embedFile("../test/behavior/cast.zig") },
|
||||||
};
|
};
|
||||||
|
|
||||||
fn corpusCheck(gpa: Allocator, source: [:0]const u8) !void {
|
fn corpusCheck(gpa: Allocator, source: [:0]const u8) !void {
|
||||||
@@ -941,11 +962,12 @@ test "astgen: corpus multi_array_list.zig" {
|
|||||||
try corpusCheck(gpa, @embedFile("../lib/std/multi_array_list.zig"));
|
try corpusCheck(gpa, @embedFile("../lib/std/multi_array_list.zig"));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "astgen: corpus Sema.zig" {
|
// Later much later
|
||||||
if (true) return error.SkipZigTest; // TODO: too large, work on smaller files first
|
//test "astgen: corpus Sema.zig" {
|
||||||
const gpa = std.testing.allocator;
|
// if (true) return error.SkipZigTest; // TODO: too large, work on smaller files first
|
||||||
try corpusCheck(gpa, @embedFile("../src/Sema.zig"));
|
// const gpa = std.testing.allocator;
|
||||||
}
|
// try corpusCheck(gpa, @embedFile("../src/Sema.zig"));
|
||||||
|
//}
|
||||||
|
|
||||||
test "astgen: enum decl" {
|
test "astgen: enum decl" {
|
||||||
const gpa = std.testing.allocator;
|
const gpa = std.testing.allocator;
|
||||||
@@ -981,6 +1003,7 @@ test "astgen: corpus" {
|
|||||||
var any_fail = false;
|
var any_fail = false;
|
||||||
inline for (corpus_files) |entry| {
|
inline for (corpus_files) |entry| {
|
||||||
corpusCheck(gpa, entry[1]) catch {
|
corpusCheck(gpa, entry[1]) catch {
|
||||||
|
std.debug.print("FAIL: {s}\n", .{entry[0]});
|
||||||
any_fail = true;
|
any_fail = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user