commit fc7c103e72f5358142ed8a0492f06a74447fcdcf
parent 10543441a8d95e78299fbc77ceb56fd9b61d0baf
Author: Sebastian <sebastian@sebsite.pw>
Date: Tue, 17 Jan 2023 01:04:37 -0500
check: fix NULL-dereference bugs
type_dereference returns NULL if the pointer is nullable. Some parts of
check didn't properly test for this, resulting in a segfault when a
nullable pointer was used. In particular, append/insert and delete
expressions. Furthermore, type_dereference was used on the type hint of
an object allocation expression, which was unnecessary and was also
susceptible to the segfault.
Signed-off-by: Sebastian <sebastian@sebsite.pw>
Diffstat:
2 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/src/check.c b/src/check.c
@@ -354,7 +354,7 @@ check_expr_alloc_init(struct context *ctx,
"Cannot infer expandable array length without type hint");
return;
}
- const struct type *htype = type_dealias(type_dereference(inithint));
+ const struct type *htype = type_dealias(inithint);
if (htype->storage != STORAGE_ARRAY) {
error(ctx, aexpr->loc, expr,
"Cannot assign expandable array from non-array type");
@@ -522,7 +522,14 @@ check_expr_append_insert(struct context *ctx,
default:
abort(); // Invariant
}
- sltype = type_dealias(type_dereference(sltypename));
+ sltype = type_dereference(sltypename);
+ if (!sltype) {
+ error(ctx, aexpr->access.tuple->loc, expr,
+ "Cannot dereference nullable pointer for %s expression",
+ exprtype_name);
+ return;
+ }
+ sltype = type_dealias(sltype);
if (sltype->storage != STORAGE_SLICE) {
char *typename = gen_typename(sltypename);
@@ -556,6 +563,12 @@ check_expr_append_insert(struct context *ctx,
check_expression(ctx, aexpr->append.value, expr->append.value, sltype);
const struct type *valtype = type_dereference(expr->append.value->result);
+ if (!valtype) {
+ error(ctx, aexpr->loc, expr,
+ "Cannot dereference nullable pointer for %s expression",
+ exprtype_name);
+ return;
+ }
valtype = type_dealias(valtype);
if (aexpr->append.length) {
if (valtype->storage != STORAGE_ARRAY
@@ -1832,7 +1845,13 @@ check_expr_delete(struct context *ctx,
"Deleted expression must be slicing or indexing expression");
return;
}
- otype = type_dealias(type_dereference(otype));
+ otype = type_dereference(otype);
+ if (!otype) {
+ error(ctx, aexpr->loc, expr,
+ "Cannot dereference nullable pointer for delete expression");
+ return;
+ }
+ otype = type_dealias(otype);
if (otype->storage != STORAGE_SLICE) {
error(ctx, aexpr->delete.expr->loc, expr,
"delete must operate on a slice");
diff --git a/tests/19-append.ha b/tests/19-append.ha
@@ -95,6 +95,11 @@ fn reject() void = {
let x: []u8 = [0u8];
append(x, [42], 3);
") as exited != EXIT_SUCCESS); // must be an expandable array
+ assert(compile("
+ let x: []u8 = [0u8];
+ let x: nullable *[]u8 = &x;
+ append(x, 42);
+ ") as exited != EXIT_SUCCESS); // object member type is nullable pointer
};
export fn main() void = {