Skip to content

Commit dda84c8

Browse files
committed
[clang][bytecode] Check source pointer for bitcast validity
Unfortunately this is more dynamic than anticipated. Fixes #165006
1 parent ad8f6b4 commit dda84c8

File tree

6 files changed

+81
-19
lines changed

6 files changed

+81
-19
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -208,19 +208,6 @@ template <class Emitter> class LocOverrideScope final {
208208
} // namespace interp
209209
} // namespace clang
210210

211-
template <class Emitter>
212-
bool Compiler<Emitter>::isValidBitCast(const CastExpr *E) {
213-
QualType FromTy = E->getSubExpr()->getType()->getPointeeType();
214-
QualType ToTy = E->getType()->getPointeeType();
215-
216-
if (classify(FromTy) == classify(ToTy))
217-
return true;
218-
219-
if (FromTy->isVoidType() || ToTy->isVoidType())
220-
return true;
221-
return false;
222-
}
223-
224211
template <class Emitter>
225212
bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
226213
const Expr *SubExpr = CE->getSubExpr();
@@ -506,12 +493,9 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
506493
if (!FromT || !ToT)
507494
return false;
508495

509-
if (!this->isValidBitCast(CE) &&
510-
!this->emitInvalidCast(CastKind::ReinterpretLike, /*Fatal=*/false, CE))
511-
return false;
512-
513496
assert(isPtrType(*FromT));
514497
assert(isPtrType(*ToT));
498+
bool SrcIsVoidPtr = SubExprTy->isVoidPointerType();
515499
if (FromT == ToT) {
516500
if (CE->getType()->isVoidPointerType() &&
517501
!SubExprTy->isFunctionPointerType()) {
@@ -520,6 +504,10 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
520504

521505
if (!this->visit(SubExpr))
522506
return false;
507+
if (!this->emitCheckBitCast(CETy->getPointeeType().getTypePtr(),
508+
SrcIsVoidPtr, CE))
509+
return false;
510+
523511
if (CE->getType()->isFunctionPointerType() ||
524512
SubExprTy->isFunctionPointerType()) {
525513
return this->emitFnPtrCast(CE);

clang/lib/AST/ByteCode/Compiler.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,8 +425,6 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
425425

426426
bool refersToUnion(const Expr *E);
427427

428-
bool isValidBitCast(const CastExpr *E);
429-
430428
protected:
431429
/// Variable to storage mapping.
432430
llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;

clang/lib/AST/ByteCode/Interp.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3289,6 +3289,52 @@ inline bool SideEffect(InterpState &S, CodePtr OpPC) {
32893289
return S.noteSideEffect();
32903290
}
32913291

3292+
inline bool CheckBitCast(InterpState &S, CodePtr OpPC, const Type *TargetType,
3293+
bool SrcIsVoidPtr) {
3294+
const auto &Ptr = S.Stk.peek<Pointer>();
3295+
if (Ptr.isZero())
3296+
return true;
3297+
if (!Ptr.isBlockPointer())
3298+
return true;
3299+
3300+
if (TargetType->isIntegerType())
3301+
return true;
3302+
3303+
if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {
3304+
bool HasValidResult = !Ptr.isZero();
3305+
3306+
if (HasValidResult) {
3307+
if (S.getStdAllocatorCaller("allocate"))
3308+
return true;
3309+
3310+
const auto &E = cast<CastExpr>(S.Current->getExpr(OpPC));
3311+
if (S.getLangOpts().CPlusPlus26 &&
3312+
S.getASTContext().hasSimilarType(Ptr.getType(),
3313+
QualType(TargetType, 0)))
3314+
return true;
3315+
3316+
S.CCEDiag(E, diag::note_constexpr_invalid_void_star_cast)
3317+
<< E->getSubExpr()->getType() << S.getLangOpts().CPlusPlus26
3318+
<< Ptr.getType().getCanonicalType() << E->getType()->getPointeeType();
3319+
} else if (!S.getLangOpts().CPlusPlus26) {
3320+
const SourceInfo &E = S.Current->getSource(OpPC);
3321+
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
3322+
<< diag::ConstexprInvalidCastKind::CastFrom << "'void *'"
3323+
<< S.Current->getRange(OpPC);
3324+
}
3325+
}
3326+
3327+
QualType PtrType = Ptr.getType();
3328+
if (PtrType->isRecordType() &&
3329+
PtrType->getAsRecordDecl() != TargetType->getAsRecordDecl()) {
3330+
S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
3331+
<< diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
3332+
<< S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
3333+
return false;
3334+
}
3335+
return true;
3336+
}
3337+
32923338
/// Same here, but only for casts.
32933339
inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind,
32943340
bool Fatal) {

clang/lib/AST/ByteCode/Opcodes.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,8 @@ def CheckLiteralType : Opcode {
422422

423423
def CheckArraySize : Opcode { let Args = [ArgUint64]; }
424424

425+
def CheckBitCast : Opcode { let Args = [ArgTypePtr, ArgBool]; }
426+
425427
// [] -> [Value]
426428
def GetGlobal : AccessOpcode;
427429
def GetGlobalUnchecked : AccessOpcode;

clang/test/AST/ByteCode/cxx11.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,3 +379,13 @@ namespace DiscardedAddrLabel {
379379
}
380380
}
381381

382+
namespace PointerCast {
383+
/// The two interpreters disagree here.
384+
struct S { int x, y; } s;
385+
constexpr S* sptr = &s;
386+
struct U {};
387+
struct Str {
388+
int e : (Str*)(sptr) == (Str*)(sptr); // expected-error {{not an integral constant expression}} \
389+
// expected-note {{cast that performs the conversions of a reinterpret_cast}}
390+
};
391+
}

clang/test/AST/ByteCode/invalid.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,22 @@ namespace InvalidBitCast {
8888
// both-note {{in call to}}
8989

9090

91+
struct sockaddr
92+
{
93+
char sa_data[8];
94+
};
95+
struct in_addr
96+
{
97+
unsigned int s_addr;
98+
};
99+
struct sockaddr_in
100+
{
101+
unsigned short int sin_port;
102+
struct in_addr sin_addr;
103+
};
104+
/// Bitcast from sockaddr to sockaddr_in. Used to crash.
105+
unsigned int get_addr(sockaddr addr) {
106+
return ((sockaddr_in *)&addr)->sin_addr.s_addr;
107+
}
108+
91109
}

0 commit comments

Comments
 (0)