Skip to content

Commit c798876

Browse files
committed
Fix crashes when casting SOA pointers (#3591)
This fixes a crash that occurred when attempting to cast an SOA (slice) pointer to a non-SOA pointer type. The crash happened with "Illegal BitCast" LLVM assertion during code generation. 1. Update lDeconstifyType() helper with proper propagation of slice property. 2. **Error check in TypeCastExpr::TypeCheck**: Added validation to detect and reject casts from slice pointers to non-slice pointers. Without this check, even with preserved slice information, the invalid cast would proceed to code generation and crash in LLVM. The fix prevents data corruption by disallowing casts that would discard the slice offset information (which tracks which lane within the SOA structure is being accessed). Fixes #3591 🤖 Generated with [Claude Code](https://claude.com/claude-code)
1 parent 00df997 commit c798876

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

src/expr.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8025,10 +8025,21 @@ const Type *TypeCastExpr::GetLValueType() const {
80258025
}
80268026
}
80278027

8028+
// Special helper to remove const from both pointer and pointee type recursively.
8029+
// We can't directly use PointerType::GetAsNonConstType() here since
8030+
// it does not recursively deconstify the base type - It only removes const from
8031+
// the pointer itself, not from nested pointer types.
8032+
// For example:
8033+
// Input: const int * const *
8034+
// GetAsNonConstType() gives: const int * * (only outer const removed)
8035+
// lDeconstifyType() should give: int * * (all const removed)
80288036
static const Type *lDeconstifyType(const Type *t) {
80298037
const PointerType *pt = CastType<PointerType>(t);
80308038
if (pt != nullptr) {
8031-
return new PointerType(lDeconstifyType(pt->GetBaseType()), pt->GetVariability(), false);
8039+
// Preserve slice property when removing constness
8040+
unsigned int prop = pt->IsSlice() ? PointerType::SLICE : PointerType::NONE;
8041+
return new PointerType(lDeconstifyType(pt->GetBaseType()), pt->GetVariability(), false, prop,
8042+
pt->GetAddressSpace());
80328043
} else {
80338044
return t->GetAsNonConstType();
80348045
}
@@ -8072,6 +8083,14 @@ Expr *TypeCastExpr::TypeCheck() {
80728083
const PointerType *fromPtr = CastType<PointerType>(fromType);
80738084
const PointerType *toPtr = CastType<PointerType>(toType);
80748085
if (fromPtr != nullptr && toPtr != nullptr) {
8086+
// Check for slice to non-slice pointer casts
8087+
if (fromPtr->IsSlice() && !toPtr->IsSlice()) {
8088+
Error(pos,
8089+
"Can't cast from pointer to SOA type \"%s\" to "
8090+
"pointer to non-SOA type \"%s\". This would discard slice offset information.",
8091+
fromType->GetString().c_str(), toType->GetString().c_str());
8092+
return nullptr;
8093+
}
80758094
// allow explicit typecasts between any two different pointer types
80768095
return this;
80778096
}

tests/lit-tests/3591.ispc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Test for issue #3591: Internal error casting soa<> pointer to opaque pointer
2+
// This test verifies that casting from an SOA pointer to a non-SOA pointer type
3+
// produces a proper error message instead of crashing with "Illegal BitCast".
4+
//
5+
// RUN: not %{ispc} %s --target=host --nowrap -o %t.o 2>&1 | FileCheck %s
6+
7+
// CHECK: Error: Can't cast from pointer to SOA type
8+
// CHECK-NOT: FATAL ERROR
9+
struct point {
10+
int x, y;
11+
};
12+
13+
struct foo;
14+
15+
__attribute__((external_only))
16+
export foo* uniform foo_init() {
17+
soa<8> point* uniform points = uniform new soa<8> point[123];
18+
return (foo* uniform)points;
19+
}

0 commit comments

Comments
 (0)