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;
|
||||
uint32_t start_node = stree->extra_data.arr[nd.rhs];
|
||||
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];
|
||||
// slice_length optimization (AstGen.zig:887-906).
|
||||
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
|
||||
|| tag == AST_NODE_GLOBAL_VAR_DECL) {
|
||||
type_node = tree->extra_data.arr[nd.lhs];
|
||||
if (type_node == UINT32_MAX)
|
||||
type_node = 0; // OPT() sentinel
|
||||
init_node = nd.rhs;
|
||||
} else { // ALIGNED_VAR_DECL
|
||||
init_node = nd.rhs;
|
||||
@@ -14498,6 +14502,8 @@ static bool rlExpr(
|
||||
body_node = tree->extra_data.arr[nd.rhs + 1];
|
||||
} else {
|
||||
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];
|
||||
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.sentinel = tree->extra_data.arr[nd.rhs + 2];
|
||||
(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.sentinel, block, RL_RI_NONE);
|
||||
return false;
|
||||
@@ -15047,16 +15053,16 @@ static bool rlExpr(
|
||||
fp.addrspace_expr = tree->extra_data.arr[pnd.lhs + 2];
|
||||
fp.section_expr = tree->extra_data.arr[pnd.lhs + 3];
|
||||
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);
|
||||
if (fp.align_expr != 0)
|
||||
if (fp.align_expr != UINT32_MAX)
|
||||
(void)rlExpr(ag, fp.align_expr, block, RL_RI_TYPE_ONLY);
|
||||
if (fp.addrspace_expr != 0)
|
||||
if (fp.addrspace_expr != UINT32_MAX)
|
||||
(void)rlExpr(
|
||||
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);
|
||||
if (fp.callconv_expr != 0)
|
||||
if (fp.callconv_expr != UINT32_MAX)
|
||||
(void)rlExpr(ag, fp.callconv_expr, block, RL_RI_TYPE_ONLY);
|
||||
} else if (ptag == AST_NODE_FN_PROTO) {
|
||||
return_type = pnd.rhs;
|
||||
@@ -15070,14 +15076,14 @@ static bool rlExpr(
|
||||
for (uint32_t i = fp.params_start; i < fp.params_end; i++)
|
||||
(void)rlExpr(
|
||||
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);
|
||||
if (fp.addrspace_expr != 0)
|
||||
if (fp.addrspace_expr != UINT32_MAX)
|
||||
(void)rlExpr(
|
||||
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);
|
||||
if (fp.callconv_expr != 0)
|
||||
if (fp.callconv_expr != UINT32_MAX)
|
||||
(void)rlExpr(ag, fp.callconv_expr, block, RL_RI_TYPE_ONLY);
|
||||
}
|
||||
} else {
|
||||
@@ -15101,16 +15107,16 @@ static bool rlExpr(
|
||||
fp.addrspace_expr = tree->extra_data.arr[nd.lhs + 2];
|
||||
fp.section_expr = tree->extra_data.arr[nd.lhs + 3];
|
||||
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);
|
||||
if (fp.align_expr != 0)
|
||||
if (fp.align_expr != UINT32_MAX)
|
||||
(void)rlExpr(ag, fp.align_expr, block, RL_RI_TYPE_ONLY);
|
||||
if (fp.addrspace_expr != 0)
|
||||
if (fp.addrspace_expr != UINT32_MAX)
|
||||
(void)rlExpr(
|
||||
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);
|
||||
if (fp.callconv_expr != 0)
|
||||
if (fp.callconv_expr != UINT32_MAX)
|
||||
(void)rlExpr(ag, fp.callconv_expr, block, RL_RI_TYPE_ONLY);
|
||||
} else if (tag == AST_NODE_FN_PROTO) {
|
||||
return_type = nd.rhs;
|
||||
@@ -15124,14 +15130,14 @@ static bool rlExpr(
|
||||
for (uint32_t i = fp.params_start; i < fp.params_end; i++)
|
||||
(void)rlExpr(
|
||||
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);
|
||||
if (fp.addrspace_expr != 0)
|
||||
if (fp.addrspace_expr != UINT32_MAX)
|
||||
(void)rlExpr(
|
||||
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);
|
||||
if (fp.callconv_expr != 0)
|
||||
if (fp.callconv_expr != UINT32_MAX)
|
||||
(void)rlExpr(ag, fp.callconv_expr, block, RL_RI_TYPE_ONLY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -787,6 +787,27 @@ const corpus_files = .{
|
||||
.{ "parser_test.zig", @embedFile("parser_test.zig") },
|
||||
.{ "test_all.zig", @embedFile("test_all.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 {
|
||||
@@ -941,11 +962,12 @@ test "astgen: corpus multi_array_list.zig" {
|
||||
try corpusCheck(gpa, @embedFile("../lib/std/multi_array_list.zig"));
|
||||
}
|
||||
|
||||
test "astgen: corpus Sema.zig" {
|
||||
if (true) return error.SkipZigTest; // TODO: too large, work on smaller files first
|
||||
const gpa = std.testing.allocator;
|
||||
try corpusCheck(gpa, @embedFile("../src/Sema.zig"));
|
||||
}
|
||||
// Later much later
|
||||
//test "astgen: corpus Sema.zig" {
|
||||
// if (true) return error.SkipZigTest; // TODO: too large, work on smaller files first
|
||||
// const gpa = std.testing.allocator;
|
||||
// try corpusCheck(gpa, @embedFile("../src/Sema.zig"));
|
||||
//}
|
||||
|
||||
test "astgen: enum decl" {
|
||||
const gpa = std.testing.allocator;
|
||||
@@ -981,6 +1003,7 @@ test "astgen: corpus" {
|
||||
var any_fail = false;
|
||||
inline for (corpus_files) |entry| {
|
||||
corpusCheck(gpa, entry[1]) catch {
|
||||
std.debug.print("FAIL: {s}\n", .{entry[0]});
|
||||
any_fail = true;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user