Skip to content

Commit

Permalink
Merge pull request #706 from ehaas/crash-fixes
Browse files Browse the repository at this point in the history
Fix assorted crashes found via fuzzing
  • Loading branch information
Vexu authored May 6, 2024
2 parents 43cb31f + f5db705 commit 3d5c852
Show file tree
Hide file tree
Showing 13 changed files with 106 additions and 19 deletions.
6 changes: 6 additions & 0 deletions src/aro/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,12 @@ pub fn nextLargestIntSameSign(comp: *const Compilation, ty: Type) ?Type {
return null;
}

/// Maximum size of an array, in bytes
pub fn maxArrayBytes(comp: *const Compilation) u64 {
const max_bits = @min(61, comp.target.ptrBitWidth());
return (@as(u64, 1) << @truncate(max_bits)) - 1;
}

/// If `enum E { ... }` syntax has a fixed underlying integer type regardless of the presence of
/// __attribute__((packed)) or the range of values of the corresponding enumerator constants,
/// specify it here.
Expand Down
5 changes: 5 additions & 0 deletions src/aro/Diagnostics/messages.def
Original file line number Diff line number Diff line change
Expand Up @@ -2487,3 +2487,8 @@ invalid_type_underlying_enum
.msg = "non-integral type '{s}' is an invalid underlying type"
.extra = .str
.kind = .@"error"

auto_type_self_initialized
.msg = "variable '{s}' declared with deduced type '__auto_type' cannot appear in its own initializer"
.extra = .str
.kind = .@"error"
72 changes: 54 additions & 18 deletions src/aro/Parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ const_decl_folding: ConstDeclFoldingMode = .fold_const_decls,
/// address-of-label expression (tracked with contains_address_of_label)
computed_goto_tok: ?TokenIndex = null,

/// __auto_type may only be used with a single declarator. Keep track of the name
/// so that it is not used in its own initializer.
auto_type_decl_name: StringId = .empty,

/// Various variables that are different for each function.
func: struct {
/// null if not in function, will always be plain func, var_args_func or old_style_func
Expand Down Expand Up @@ -1421,6 +1425,8 @@ fn typeof(p: *Parser) Error!?Type {
const l_paren = try p.expectToken(.l_paren);
if (try p.typeName()) |ty| {
try p.expectClosing(l_paren, .r_paren);
if (ty.is(.invalid)) return null;

const typeof_ty = try p.arena.create(Type);
typeof_ty.* = .{
.data = ty.data,
Expand All @@ -1442,6 +1448,8 @@ fn typeof(p: *Parser) Error!?Type {
.specifier = .nullptr_t,
.qual = if (unqual) .{} else typeof_expr.ty.qual.inheritFromTypeof(),
};
} else if (typeof_expr.ty.is(.invalid)) {
return null;
}

const inner = try p.arena.create(Type.Expr);
Expand Down Expand Up @@ -1788,6 +1796,8 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize) Error!?
} else {
apply_var_attributes = true;
}
const c23_auto = init_d.d.ty.is(.c23_auto);
const auto_type = init_d.d.ty.is(.auto_type);

if (p.eatToken(.equal)) |eq| init: {
if (decl_spec.storage_class == .typedef or
Expand Down Expand Up @@ -1815,6 +1825,11 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize) Error!?

const interned_name = try StrInt.intern(p.comp, p.tokSlice(init_d.d.name));
try p.syms.declareSymbol(p, interned_name, init_d.d.ty, init_d.d.name, .none);
if (c23_auto or auto_type) {
p.auto_type_decl_name = interned_name;
}
defer p.auto_type_decl_name = .empty;

var init_list_expr = try p.initializer(init_d.d.ty);
init_d.initializer = init_list_expr;
if (!init_list_expr.ty.isArray()) break :init;
Expand All @@ -1824,8 +1839,7 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize) Error!?
}

const name = init_d.d.name;
const c23_auto = init_d.d.ty.is(.c23_auto);
if (init_d.d.ty.is(.auto_type) or c23_auto) {
if (auto_type or c23_auto) {
if (init_d.initializer.node == .none) {
init_d.d.ty = Type.invalid;
if (c23_auto) {
Expand Down Expand Up @@ -3011,9 +3025,6 @@ fn directDeclarator(p: *Parser, base_type: Type, d: *Declarator, kind: Declarato
}

const outer = try p.directDeclarator(base_type, d, kind);
var max_bits = p.comp.target.ptrBitWidth();
if (max_bits > 61) max_bits = 61;
const max_bytes = (@as(u64, 1) << @truncate(max_bits)) - 1;

if (!size.ty.isInt()) {
try p.errStr(.array_size_non_int, size_tok, try p.typeStr(size.ty));
Expand Down Expand Up @@ -3050,7 +3061,7 @@ fn directDeclarator(p: *Parser, base_type: Type, d: *Declarator, kind: Declarato
} else {
// `outer` is validated later so it may be invalid here
const outer_size = outer.sizeof(p.comp);
const max_elems = max_bytes / @max(1, outer_size orelse 1);
const max_elems = p.comp.maxArrayBytes() / @max(1, outer_size orelse 1);

var size_val = size.val;
if (size_val.isZero(p.comp)) {
Expand Down Expand Up @@ -3140,12 +3151,14 @@ fn directDeclarator(p: *Parser, base_type: Type, d: *Declarator, kind: Declarato
fn pointer(p: *Parser, base_ty: Type) Error!Type {
var ty = base_ty;
while (p.eatToken(.asterisk)) |_| {
const elem_ty = try p.arena.create(Type);
elem_ty.* = ty;
ty = Type{
.specifier = .pointer,
.data = .{ .sub_type = elem_ty },
};
if (!ty.is(.invalid)) {
const elem_ty = try p.arena.create(Type);
elem_ty.* = ty;
ty = Type{
.specifier = .pointer,
.data = .{ .sub_type = elem_ty },
};
}
var quals = Type.Qualifiers.Builder{};
_ = try p.typeQual(&quals);
try quals.finish(p, &ty);
Expand Down Expand Up @@ -3848,6 +3861,12 @@ fn convertInitList(p: *Parser, il: InitList, init_ty: Type) Error!NodeIndex {
.data = .{ .bin = .{ .lhs = .none, .rhs = .none } },
};

const max_elems = p.comp.maxArrayBytes() / (elem_ty.sizeof(p.comp) orelse 1);
if (start > max_elems) {
try p.errTok(.array_too_large, il.tok);
start = max_elems;
}

if (init_ty.specifier == .incomplete_array) {
arr_init_node.ty.specifier = .array;
arr_init_node.ty.data.array.len = start;
Expand Down Expand Up @@ -5114,6 +5133,8 @@ pub const Result = struct {
ty: Type = .{ .specifier = .int },
val: Value = .{},

const invalid: Result = .{ .ty = Type.invalid };

pub fn str(res: Result, p: *Parser) ![]const u8 {
switch (res.val.opt_ref) {
.none => return "(none)",
Expand Down Expand Up @@ -6932,8 +6953,11 @@ fn offsetofMemberDesignator(p: *Parser, base_ty: Type, want_bits: bool) Error!Re
try ptr.lvalConversion(p);
try index.lvalConversion(p);

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

try index.saveValue(p);
try ptr.bin(p, .array_access_expr, index);
Expand Down Expand Up @@ -7260,6 +7284,7 @@ fn unExpr(p: *Parser) Error!Result {
var operand = try p.castExpr();
try operand.expect(p);
try operand.lvalConversion(p);
if (operand.ty.is(.invalid)) return Result.invalid;
if (!operand.ty.isInt() and !operand.ty.isFloat()) {
try p.errStr(.invalid_imag, imag_tok, try p.typeStr(operand.ty));
}
Expand Down Expand Up @@ -7290,6 +7315,7 @@ fn unExpr(p: *Parser) Error!Result {
var operand = try p.castExpr();
try operand.expect(p);
try operand.lvalConversion(p);
if (operand.ty.is(.invalid)) return Result.invalid;
if (!operand.ty.isInt() and !operand.ty.isFloat()) {
try p.errStr(.invalid_real, real_tok, try p.typeStr(operand.ty));
}
Expand Down Expand Up @@ -7435,12 +7461,18 @@ fn suffixExpr(p: *Parser, lhs: Result) Error!Result {
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_before_conversion, array_before_conversion, l_bracket);
if (index.ty.isInt()) {
try p.checkArrayBounds(index_before_conversion, array_before_conversion, l_bracket);
} else {
try p.errTok(.invalid_index, 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(array_before_conversion, index_before_conversion, l_bracket);
if (ptr.ty.isInt()) {
try p.checkArrayBounds(array_before_conversion, index_before_conversion, l_bracket);
} else {
try p.errTok(.invalid_index, l_bracket);
}
std.mem.swap(Result, &ptr, &index);
} else {
try p.errTok(.invalid_subscript, l_bracket);
Expand Down Expand Up @@ -7742,6 +7774,10 @@ fn primaryExpr(p: *Parser) Error!Result {
const name_tok = try p.expectIdentifier();
const name = p.tokSlice(name_tok);
const interned_name = try StrInt.intern(p.comp, name);
if (interned_name == p.auto_type_decl_name) {
try p.errStr(.auto_type_self_initialized, name_tok, name);
return error.ParsingFailed;
}
if (p.syms.findSymbol(interned_name)) |sym| {
try p.checkDeprecatedUnavailable(sym.ty, name_tok, sym.tok);
if (sym.kind == .constexpr) {
Expand Down
3 changes: 2 additions & 1 deletion src/aro/Tokenizer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,8 @@ pub const Token = struct {

pub fn symbol(id: Id) []const u8 {
return switch (id) {
.macro_string, .invalid => unreachable,
.macro_string => unreachable,
.invalid => "invalid bytes",
.identifier,
.extended_identifier,
.macro_func,
Expand Down
2 changes: 2 additions & 0 deletions src/aro/Type.zig
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,8 @@ pub fn integerPromotion(ty: Type, comp: *Compilation) Type {
switch (specifier) {
.@"enum" => {
if (ty.hasIncompleteSize()) return .{ .specifier = .int };
if (ty.data.@"enum".fixed) return ty.data.@"enum".tag_ty.integerPromotion(comp);

specifier = ty.data.@"enum".tag_ty.specifier;
},
.bit_int, .complex_bit_int => return .{ .specifier = specifier, .data = ty.data },
Expand Down
14 changes: 14 additions & 0 deletions test/cases/__auto_type self init.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//aro-args -std=c23
void foo(void) {
int x;
__auto_type x = x;

__auto_type y = (int []){1, y};

auto z = z + 1;
}

#define EXPECTED_ERRORS "__auto_type self init.c:4:21: error: variable 'x' declared with deduced type '__auto_type' cannot appear in its own initializer" \
"__auto_type self init.c:6:33: error: variable 'y' declared with deduced type '__auto_type' cannot appear in its own initializer" \
"__auto_type self init.c:8:14: error: variable 'z' declared with deduced type '__auto_type' cannot appear in its own initializer" \

7 changes: 7 additions & 0 deletions test/cases/array designator too large.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
int arr1[] = { [0x800000000000000 - 1] = 0 };
int arr2[] = { [0x800000000000000 - 2] = 0 };
_Static_assert(sizeof(arr1), "");
_Static_assert(sizeof(arr2), "");

#define EXPECTED_ERRORS "array designator too large.c:1:14: error: array is too large" \

3 changes: 3 additions & 0 deletions test/cases/array subscript with string.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#define NO_ERROR_VALIDATION
int x[2];
x[""[""]
Binary file added test/cases/assembly invalid token.c
Binary file not shown.
8 changes: 8 additions & 0 deletions test/cases/enum fixed _BitInt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
enum E: _BitInt(20) {
A,
};

void foo(void) {
enum E e = 1;
int x = -e;
}
3 changes: 3 additions & 0 deletions test/cases/invalid _BitInt pointer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#define NO_ERROR_VALIDATION

_BitInt(1) *e= __real__ e;
File renamed without changes.
2 changes: 2 additions & 0 deletions test/cases/typeof invalid pointer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#define NO_ERROR_VALIDATION
typeof((void)0 + 0) *a = 2;

0 comments on commit 3d5c852

Please sign in to comment.