-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[clang][bytecode] Improve error detection in BitCastPrim op #158575
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang Author: Timm Baeder (tbaederr) ChangesReject bitcasts to pointer types unless it's to Fixes #156174 Full diff: https://github.com/llvm/llvm-project/pull/158575.diff 4 Files Affected:
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 78b74acc3789d..75b3e22549f56 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -7394,7 +7394,7 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
uint32_t ResultBitWidth = std::max(Ctx.getBitWidth(ToType), 8u);
if (!this->emitBitCastPrim(*ToT, ToTypeIsUChar || ToType->isStdByteType(),
- ResultBitWidth, TargetSemantics, E))
+ ResultBitWidth, TargetSemantics, ToType.getTypePtr(), E))
return false;
if (DiscardResult)
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index d8362ee3176a0..7b9783398e733 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -3570,16 +3570,26 @@ bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);
template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
uint32_t ResultBitWidth,
- const llvm::fltSemantics *Sem) {
+ const llvm::fltSemantics *Sem,
+ const Type *TargetType) {
const Pointer &FromPtr = S.Stk.pop<Pointer>();
if (!CheckLoad(S, OpPC, FromPtr))
return false;
if constexpr (std::is_same_v<T, Pointer>) {
+ if (!TargetType->isNullPtrType()) {
+ S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_bit_cast_invalid_type)
+ << /*IsToType=*/true << /*IsReference=*/false << 1/*Pointer*/;
+ return false;
+ }
// The only pointer type we can validly bitcast to is nullptr_t.
S.Stk.push<Pointer>();
return true;
+ } else if constexpr (std::is_same_v<T, MemberPointer>) {
+ S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_bit_cast_invalid_type)
+ << /*IsToType=*/true << /*IsReference=*/false << 2/*MemberPointer*/;
+ return false;
} else {
size_t BuffSize = ResultBitWidth / 8;
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 95a44333e8e04..7af2df5318106 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -872,12 +872,12 @@ def CheckNull : Opcode;
def BitCastTypeClass : TypeClass {
let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64,
- IntAP, IntAPS, Bool, Float, Ptr];
+ IntAP, IntAPS, Bool, Float, Ptr, MemberPtr];
}
def BitCastPrim : Opcode {
let Types = [BitCastTypeClass];
- let Args = [ArgBool, ArgUint32, ArgFltSemantics];
+ let Args = [ArgBool, ArgUint32, ArgFltSemantics, ArgTypePtr];
let HasGroup = 1;
}
diff --git a/clang/test/AST/ByteCode/builtin-bit-cast.cpp b/clang/test/AST/ByteCode/builtin-bit-cast.cpp
index 32c1f41e0e059..0f06a1e58370e 100644
--- a/clang/test/AST/ByteCode/builtin-bit-cast.cpp
+++ b/clang/test/AST/ByteCode/builtin-bit-cast.cpp
@@ -530,7 +530,6 @@ constexpr const intptr_t &returns_local() { return 0L; }
// both-note@+1 {{read of temporary whose lifetime has ended}}
constexpr nullptr_t test_nullptr_bad = __builtin_bit_cast(nullptr_t, returns_local());
-
#ifdef __SIZEOF_INT128__
namespace VectorCast {
typedef unsigned X __attribute__ ((vector_size (64)));
@@ -572,3 +571,17 @@ namespace VectorCast {
#endif
}
#endif
+
+namespace ToPrimPtrs {
+ struct S { int foo () { return 0; } };
+ auto ptr = __builtin_bit_cast(int *, ((__INTPTR_TYPE__) 0));
+ auto nptr = __builtin_bit_cast(nullptr_t, ((__INTPTR_TYPE__)0));
+
+ constexpr auto cptr = __builtin_bit_cast(int *, ((__INTPTR_TYPE__) 0)); // both-error {{must be initialized by a constant expression}} \
+ // both-note {{bit_cast to a pointer type is not allowed in a constant expression}}
+ constexpr auto cnptr = __builtin_bit_cast(nullptr_t, ((__INTPTR_TYPE__)0));
+
+ auto memptr = __builtin_bit_cast(int S::*, ((__INTPTR_TYPE__) 0));
+ constexpr auto cmemptr = __builtin_bit_cast(int S::*, ((__INTPTR_TYPE__) 0)); // both-error {{must be initialized by a constant expression}} \
+ // both-note {{bit_cast to a member pointer type is not allowed in a constant expression}}
+}
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
693e1d6
to
0921670
Compare
0921670
to
b0dab0e
Compare
// both-note {{bit_cast to a pointer type is not allowed in a constant expression}} | ||
constexpr auto cnptr = __builtin_bit_cast(nullptr_t, ((__INTPTR_TYPE__)0)); | ||
|
||
#if !defined(_WIN32) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the Win32 carveout?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apparently member pointers have a different size on windows.
Reject bitcasts to pointer types unless it's to
nullptr_t
and always reject bitcasts to member pointer types.Fixes #156174