- Detect unaligned loads #1951.

- Fix issue where aligned bitstructs did not store/load with the given alignment.
This commit is contained in:
Christoffer Lerno
2025-02-10 22:07:15 +01:00
parent 86680279fa
commit 79a4b6855b
11 changed files with 190 additions and 17 deletions

View File

@@ -13,7 +13,6 @@ enum IntrospectIndex
};
bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements);
static inline Type *type_reduced_from_expr(Expr *expr);
static inline bool abi_type_is_type(AbiType type);
static inline bool abi_type_is_valid(AbiType type);
@@ -90,11 +89,6 @@ static inline Type *type_lowering(Type *type)
}
}
static inline Type *type_reduced_from_expr(Expr *expr)
{
return type_lowering(expr->type);
}
static inline bool abi_type_is_type(AbiType type)
{
return !(type.int_bits_plus_1 & 0x01);

View File

@@ -160,12 +160,15 @@ INLINE void llvm_emit_atomic_store(GenContext *c, BEValue *result_value, Expr *e
INLINE void llvm_emit_unaligned_store(GenContext *c, BEValue *result_value, Expr *expr)
{
bool emit_check = c->emitting_load_store_check;
c->emitting_load_store_check = true;
BEValue value;
llvm_emit_expr(c, &value, expr->call_expr.arguments[0]);
llvm_emit_expr(c, result_value, expr->call_expr.arguments[1]);
llvm_value_deref(c, &value);
value.alignment = expr->call_expr.arguments[2]->const_expr.ixx.i.low;
llvm_store(c, &value, result_value);
c->emitting_load_store_check = emit_check;
}
INLINE void llvm_emit_atomic_fetch(GenContext *c, BuiltinFunction func, BEValue *result_value, Expr *expr)
@@ -241,10 +244,13 @@ INLINE void llvm_emit_atomic_load(GenContext *c, BEValue *result_value, Expr *ex
INLINE void llvm_emit_unaligned_load(GenContext *c, BEValue *result_value, Expr *expr)
{
bool emit_check = c->emitting_load_store_check;
c->emitting_load_store_check = true;
llvm_emit_expr(c, result_value, expr->call_expr.arguments[0]);
llvm_value_deref(c, result_value);
result_value->alignment = expr->call_expr.arguments[1]->const_expr.ixx.i.low;
llvm_value_rvalue(c, result_value);
c->emitting_load_store_check = emit_check;
}
static inline LLVMValueRef llvm_syscall_asm(LLVMTypeRef func_type, char *call)

View File

@@ -2286,6 +2286,7 @@ static inline void llvm_emit_deref(GenContext *c, BEValue *value, Expr *inner, T
}
llvm_emit_expr(c, value, inner);
llvm_value_rvalue(c, value);
AlignSize alignment = type_abi_alignment(type);
if (safe_mode_enabled())
{
LLVMValueRef check = LLVMBuildICmp(c->builder, LLVMIntEQ, value->value, llvm_get_zero(c, inner->type), "checknull");
@@ -2294,11 +2295,28 @@ static inline void llvm_emit_deref(GenContext *c, BEValue *value, Expr *inner, T
span_to_scratch(inner->span);
scratch_buffer_append("' was null.");
llvm_emit_panic_on_true(c, check, scratch_buffer_to_string(), inner->span, NULL, NULL, NULL);
if (alignment > 1 && !c->emitting_load_store_check)
{
LLVMValueRef as_int = LLVMBuildPtrToInt(c->builder, value->value, llvm_get_type(c, type_usz), "");
LLVMValueRef align = llvm_const_int(c, type_usz, alignment);
LLVMValueRef rem = LLVMBuildURem(c->builder, as_int, align, "");
LLVMValueRef is_not_zero = LLVMBuildICmp(c->builder, LLVMIntNE, rem, llvm_get_zero(c, type_usz), "");
c->emitting_load_store_check = true;
BEValue value1;
BEValue value2;
if (inner->type->name )
llvm_value_set(&value1, align, type_usz);
llvm_value_set(&value2, rem, type_usz);
llvm_emit_panic_on_true(c, is_not_zero, "Unaligned pointer access detected", inner->span, "Unaligned access: ptr %% %s = %s, use @unaligned_load / @unaligned_store for unaligned access.",
&value1, &value2);
c->emitting_load_store_check = false;
}
}
// Convert pointer to address
value->kind = BE_ADDRESS;
value->type = type;
value->alignment = type_abi_alignment(type);
value->type = type_lowering(type);
value->alignment = alignment;
}
/**
@@ -2342,7 +2360,7 @@ static void llvm_emit_dynamic_method_addr(GenContext *c, BEValue *value, Expr *e
static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr)
{
Type *type = type_reduced_from_expr(expr->unary_expr.expr);
Type *type = type_lowering(expr->unary_expr.expr->type);
Expr *inner = expr->unary_expr.expr;
switch (expr->unary_expr.operator)
@@ -2430,7 +2448,7 @@ static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr)
value->type = type_lowering(expr->type);
return;
case UNARYOP_DEREF:
llvm_emit_deref(c, value, inner, type_lowering(expr->type));
llvm_emit_deref(c, value, inner, expr->type);
return;
case UNARYOP_INC:
llvm_emit_pre_inc_dec(c, value, inner, 1, !expr->unary_expr.no_wrap);
@@ -4506,7 +4524,7 @@ static inline void llvm_emit_const_initializer_list_expr(GenContext *c, BEValue
static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr)
{
Type *type = type_reduced_from_expr(expr)->canonical;
Type *type = type_lowering(expr->type)->canonical;
bool is_bytes = false;
switch (expr->const_expr.const_kind)
{

View File

@@ -84,6 +84,7 @@ typedef struct GenContext_
bool shared_context;
bool in_init_ref;
bool weaken;
bool emitting_load_store_check;
LLVMModuleRef module;
LLVMBuilderRef global_builder;
LLVMTargetMachineRef machine;

View File

@@ -683,6 +683,7 @@ AlignSize type_abi_alignment(Type *type)
case TYPE_WILDCARD:
UNREACHABLE;
case TYPE_BITSTRUCT:
if (type->decl->alignment) return type->decl->alignment;
type = type->decl->strukt.container_type->type;
goto RETRY;
case TYPE_INFERRED_VECTOR: