Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parser: don't issue a bounds warning for trailing one-element array access #330

Merged
merged 3 commits into from
Jul 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/Diagnostics.zig
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ pub const Options = packed struct {
@"designated-init": Kind = .default,
@"attribute-warning": Kind = .default,
@"invalid-noreturn": Kind = .default,
@"zero-length-array": Kind = .default,
@"old-style-flexible-struct": Kind = .default,
};

const messages = struct {
Expand Down Expand Up @@ -1982,6 +1984,19 @@ const messages = struct {
const extra = .str;
const kind = .@"error";
};
const zero_length_array = struct {
const msg = "zero size arrays are an extension";
const kind = .off;
const pedantic = true;
const opt = "zero-length-array";
};
const old_style_flexible_struct = struct {
const msg = "array index {d} is past the end of the array";
const extra = .unsigned;
const kind = .off;
const pedantic = true;
const opt = "old-style-flexible-struct";
};
};

list: std.ArrayListUnmanaged(Message) = .{},
Expand Down
42 changes: 34 additions & 8 deletions src/Parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2510,7 +2510,9 @@ fn directDeclarator(p: *Parser, base_type: Type, d: *Declarator, kind: Declarato
} else {
var size_val = size.val;
const size_t = p.comp.types.size;
if (size_val.compare(.lt, Value.int(0), size_t, p.comp)) {
if (size_val.isZero()) {
try p.errTok(.zero_length_array, l_bracket);
} else if (size_val.compare(.lt, Value.int(0), size_t, p.comp)) {
try p.errTok(.negative_array_size, l_bracket);
return error.ParsingFailed;
}
Expand Down Expand Up @@ -5565,7 +5567,7 @@ fn offsetofMemberDesignator(p: *Parser, base_ty: Type) Error!Result {
try index.lvalConversion(p);

if (!index.ty.isInt()) try p.errTok(.invalid_index, l_bracket_tok);
try p.checkArrayBounds(index, lhs.ty, l_bracket_tok);
try p.checkArrayBounds(index, lhs, l_bracket_tok);

try index.saveValue(p);
try ptr.bin(p, .array_access_expr, index);
Expand Down Expand Up @@ -5928,19 +5930,19 @@ fn suffixExpr(p: *Parser, lhs: Result) Error!Result {
try index.expect(p);
try p.expectClosing(l_bracket, .r_bracket);

const l_ty = lhs.ty;
const r_ty = index.ty;
const array_before_conversion = lhs;
const index_before_conversion = index;
var ptr = lhs;
try ptr.lvalConversion(p);
try index.lvalConversion(p);
if (ptr.ty.isPtr()) {
ptr.ty = ptr.ty.elemType();
if (!index.ty.isInt()) try p.errTok(.invalid_index, l_bracket);
try p.checkArrayBounds(index, l_ty, l_bracket);
try p.checkArrayBounds(index_before_conversion, array_before_conversion, l_bracket);
} else if (index.ty.isPtr()) {
index.ty = index.ty.elemType();
if (!ptr.ty.isInt()) try p.errTok(.invalid_index, l_bracket);
try p.checkArrayBounds(ptr, r_ty, l_bracket);
try p.checkArrayBounds(array_before_conversion, index_before_conversion, l_bracket);
std.mem.swap(Result, &ptr, &index);
} else {
try p.errTok(.invalid_subscript, l_bracket);
Expand Down Expand Up @@ -6162,9 +6164,33 @@ fn callExpr(p: *Parser, lhs: Result) Error!Result {
return Result{ .node = try p.addNode(call_node), .ty = call_node.ty };
}

fn checkArrayBounds(p: *Parser, index: Result, arr_ty: Type, tok: TokenIndex) !void {
fn checkArrayBounds(p: *Parser, index: Result, array: Result, tok: TokenIndex) !void {
if (index.val.tag == .unavailable) return;
const len = Value.int(arr_ty.arrayLen() orelse return);

const array_len = array.ty.arrayLen() orelse return;
if (array_len == 0) return;

if (array_len == 1) {
if (p.getNode(array.node, .member_access_expr) orelse p.getNode(array.node, .member_access_ptr_expr)) |node| {
const data = p.nodes.items(.data)[@enumToInt(node)];
var lhs = p.nodes.items(.ty)[@enumToInt(data.member.lhs)];
if (lhs.get(.pointer)) |ptr| {
lhs = ptr.data.sub_type.*;
}
if (lhs.is(.@"struct")) {
const record = lhs.getRecord().?;
if (data.member.index + 1 == record.fields.len) {
if (!index.val.isZero()) {
try p.errExtra(.old_style_flexible_struct, tok, .{
.unsigned = index.val.data.int,
});
}
return;
}
}
}
}
const len = Value.int(array_len);

if (index.ty.isUnsignedInt(p.comp)) {
if (index.val.compare(.gte, len, p.comp.types.size, p.comp))
Expand Down
53 changes: 53 additions & 0 deletions test/cases/old style flexible array.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
struct S1 {
int a[1];
int b[1];
};

struct S2 {
int x;
struct S1 s1[1];
};

void foo(struct S1 *p) {
struct S1 s1;
s1.a[1] = 0;
s1.b[1] = 0;
p->a[1] = 0;
p->b[1] = 0;

struct S2 s2;
s2.s1[2].a[1] = 0;
s2.s1[2].b[1] = 0;
}

struct S3 {
int w;
struct {
int x;
int y[1];
int z[1];
};
};

void bar(struct S3 *p) {
p->y[1] = 0;
p->z[1] = 0;
struct S3 s3;
s3.y[1] = 0;
s3.z[1] = 0;
}

#pragma GCC diagnostic warning "-Wold-style-flexible-struct"
void baz(void) {
struct S1 s1;
s1.b[0] = 1;
s1.b[1] = 1;
}

#define EXPECTED_ERRORS "old style flexible array.c:13:9: warning: array index 1 is past the end of the array [-Warray-bounds]" \
"old style flexible array.c:15:9: warning: array index 1 is past the end of the array [-Warray-bounds]" \
"old style flexible array.c:19:15: warning: array index 1 is past the end of the array [-Warray-bounds]" \
"old style flexible array.c:33:9: warning: array index 1 is past the end of the array [-Warray-bounds]" \
"old style flexible array.c:36:9: warning: array index 1 is past the end of the array [-Warray-bounds]" \
"old style flexible array.c:44:9: warning: array index 1 is past the end of the array [-Wold-style-flexible-struct]" \

17 changes: 17 additions & 0 deletions test/cases/zero length array.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//aro-args -Wzero-length-array

struct S {
int x;
int y[0];
};

void foo(void) {
struct S s;
s.y[2] = 5;
int z[0];
z[5] = 2;
}

#define EXPECTED_ERRORS "zero length array.c:5:10: warning: zero size arrays are an extension [-Wzero-length-array]" \
"zero length array.c:11:10: warning: zero size arrays are an extension [-Wzero-length-array]" \