tbaeder created this revision. tbaeder added reviewers: aaron.ballman, erichkeane, shafik, cor3ntin. Herald added a project: All. tbaeder requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
This commit is a bit ugly at the moment since I'm gathering feedback. The APFloats we use to implement the `Floating` type might heap-allocate stuff to represent large values. When we then later write those to bytecode (via `BytecodeEmitter`, not `EvalEmitter`), that heap allocation is dangling. So, for code like constexpr long double f() { const long double L = __LDBL_MAX__; return L; }; static_assert(f() == __LDBL_MAX__); asan would complain: READ of size 8 at 0x602000001610 thread T0 #0 0x7f525300b911 in llvm::APInt::tcAssign(unsigned long*, unsigned long const*, unsigned int) /home/tbaeder/code/llvm-project/llvm/lib/Support/APInt.cpp:2331:14 #1 0x7f5252f3f640 in llvm::detail::IEEEFloat::copySignificand(llvm::detail::IEEEFloat const&) /home/tbaeder/code/llvm-project/llvm/lib/Support/APFloat.cpp:878:3 #2 0x7f5252f3f42c in llvm::detail::IEEEFloat::assign(llvm::detail::IEEEFloat const&) /home/tbaeder/code/llvm-project/llvm/lib/Support/APFloat.cpp:871:5 #3 0x7f5252f46828 in llvm::detail::IEEEFloat::IEEEFloat(llvm::detail::IEEEFloat const&) /home/tbaeder/code/llvm-project/llvm/lib/Support/APFloat.cpp:1143:3 #4 0x7f5295e12913 in llvm::APFloat::Storage::Storage(llvm::APFloat::Storage const&) /home/tbaeder/code/llvm-project/llvm/include/llvm/ADT/APFloat.h:805:20 #5 0x7f5295e01d3a in llvm::APFloat::APFloat(llvm::APFloat const&) /home/tbaeder/code/llvm-project/llvm/include/llvm/ADT/APFloat.h:928:3 #6 0x7f5297d56584 in clang::interp::Floating::Floating(clang::interp::Floating const&) /home/tbaeder/code/llvm-project/clang/lib/AST/Interp/Floating.h:27:7 #7 0x7f5297ea1fa0 in clang::interp::Floating llvm::support::endian::read<clang::interp::Floating, 1ul>(void const*, llvm::support::endianness) /home/tbaeder/code/llvm-project/llvm/include/llvm/Support/Endian.h:70:32 #8 0x7f5297ea1e14 in clang::interp::Floating llvm::support::endian::read<clang::interp::Floating, (llvm::support::endianness)2, 1ul>(void const*) /home/tbaeder/code/llvm-project/llvm/include/llvm/Support/Endian.h:77:10 #9 0x7f5297ea1d06 in std::enable_if<!std::is_pointer<clang::interp::Floating>::value, clang::interp::Floating>::type clang::interp::CodePtr::read<clang::interp::Floating>() /home/tbaeder/code/llvm-project/clang/lib/AST/Interp/Source.h:53:15 #10 0x7f52981e7601 in clang::interp::Floating clang::interp::ReadArg<clang::interp::Floating>(clang::interp::InterpState&, clang::interp::CodePtr&) /home/tbaeder/code/llvm-project/clang/lib/AST/Interp/Interp.h:1894:17 [...] freed by thread T0 here: #0 0x3d2511 in operator delete[](void*) (/home/tbaeder/code/llvm-project/build/bin/clang-17+0x3d2511) (BuildId: 88c1d01099b49a9ebf7bd913e201002fedf14f9b) #1 0x7f5252f3eff9 in llvm::detail::IEEEFloat::freeSignificand() /home/tbaeder/code/llvm-project/llvm/lib/Support/APFloat.cpp:861:5 #2 0x7f5252f46968 in llvm::detail::IEEEFloat::~IEEEFloat() /home/tbaeder/code/llvm-project/llvm/lib/Support/APFloat.cpp:1150:27 #3 0x7f5295e11ad1 in llvm::APFloat::Storage::~Storage() /home/tbaeder/code/llvm-project/llvm/include/llvm/ADT/APFloat.h:793:14 #4 0x7f5295e01d9c in llvm::APFloat::~APFloat() /home/tbaeder/code/llvm-project/llvm/include/llvm/ADT/APFloat.h:931:22 #5 0x7f5297d5ddb8 in clang::interp::Floating::~Floating() /home/tbaeder/code/llvm-project/clang/lib/AST/Interp/Floating.h:27:7 #6 0x7f5297ea1fe7 in clang::interp::Floating llvm::support::endian::read<clang::interp::Floating, 1ul>(void const*, llvm::support::endianness) /home/tbaeder/code/llvm-project/llvm/include/llvm/Support/Endian.h:71:1 [...] previously allocated by thread T0 here: #0 0x3d1cb1 in operator new[](unsigned long) (/home/tbaeder/code/llvm-project/build/bin/clang-17+0x3d1cb1) (BuildId: 88c1d01099b49a9ebf7bd913e201002fedf14f9b) #1 0x7f5252f3ed6a in llvm::detail::IEEEFloat::initialize(llvm::fltSemantics const*) /home/tbaeder/code/llvm-project/llvm/lib/Support/APFloat.cpp:856:25 #2 0x7f5252f467e7 in llvm::detail::IEEEFloat::IEEEFloat(llvm::detail::IEEEFloat const&) /home/tbaeder/code/llvm-project/llvm/lib/Support/APFloat.cpp:1142:3 #3 0x7f5295e12913 in llvm::APFloat::Storage::Storage(llvm::APFloat::Storage const&) /home/tbaeder/code/llvm-project/llvm/include/llvm/ADT/APFloat.h:805:20 #4 0x7f5295e01d3a in llvm::APFloat::APFloat(llvm::APFloat const&) /home/tbaeder/code/llvm-project/llvm/include/llvm/ADT/APFloat.h:928:3 #5 0x7f5297d56584 in clang::interp::Floating::Floating(clang::interp::Floating const&) /home/tbaeder/code/llvm-project/clang/lib/AST/Interp/Floating.h:27:7 #6 0x7f5297d17f93 in void emit<clang::interp::Floating>(clang::interp::Program&, std::__debug::vector<std::byte, std::allocator<std::byte>>&, clang::interp::Floating const&, bool&) /home/tbaeder/code/llvm-project/clang/lib/AST/Interp/ByteCodeEmitter.cpp:202:32 So, this patch adds specialized `readArg()` and `emit()` versions for `Floating` that serializes the `APFloat`. I'm not really sure if this is the best way to go though. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D155165 Files: clang/lib/AST/Interp/ByteCodeEmitter.cpp clang/lib/AST/Interp/Floating.h clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/Source.h clang/test/AST/Interp/floats.cpp
Index: clang/test/AST/Interp/floats.cpp =================================================================== --- clang/test/AST/Interp/floats.cpp +++ clang/test/AST/Interp/floats.cpp @@ -140,4 +140,11 @@ namespace LongDouble { constexpr long double ld = 3.1425926539; + + constexpr long double f() { + const long double L = __LDBL_MAX__; + + return L; + }; + static_assert(f() == __LDBL_MAX__); } Index: clang/lib/AST/Interp/Source.h =================================================================== --- clang/lib/AST/Interp/Source.h +++ clang/lib/AST/Interp/Source.h @@ -60,6 +60,7 @@ /// Constructor used by Function to generate pointers. CodePtr(const std::byte *Ptr) : Ptr(Ptr) {} /// Pointer into the code owned by a function. +public: const std::byte *Ptr; }; Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -1895,6 +1895,12 @@ } } +template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) { + Floating F = Floating::deserialize(OpPC.Ptr); + OpPC += align(F.bytesToSerialize()); + return F; +} + } // namespace interp } // namespace clang Index: clang/lib/AST/Interp/Floating.h =================================================================== --- clang/lib/AST/Interp/Floating.h +++ clang/lib/AST/Interp/Floating.h @@ -124,6 +124,26 @@ llvm::StoreIntToMemory(API, (uint8_t *)Buff, bitWidth() / 8); } + size_t bytesToSerialize() const { + return sizeof(llvm::fltSemantics *) + + (APFloat::semanticsSizeInBits(F.getSemantics()) / 8); + } + + void serialize(std::byte *Buff) const { + // Semantics followed by an APInt. + *reinterpret_cast<const llvm::fltSemantics **>(Buff) = &F.getSemantics(); + + llvm::APInt API = F.bitcastToAPInt(); + llvm::StoreIntToMemory(API, (uint8_t *)(Buff + sizeof(void *)), + bitWidth() / 8); + } + + static Floating deserialize(const std::byte *Buff) { + const llvm::fltSemantics *Sem; + std::memcpy((void *)&Sem, Buff, sizeof(void *)); + return bitcastFromMemory(Buff + sizeof(void *), *Sem); + } + // ------- static APFloat::opStatus add(const Floating &A, const Floating &B, Index: clang/lib/AST/Interp/ByteCodeEmitter.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeEmitter.cpp +++ clang/lib/AST/Interp/ByteCodeEmitter.cpp @@ -206,6 +206,25 @@ } } +template <> +void emit(Program &P, std::vector<std::byte> &Code, const Floating &Val, + bool &Success) { + size_t Size = Val.bytesToSerialize(); + + if (Code.size() + Size > std::numeric_limits<unsigned>::max()) { + Success = false; + return; + } + + // Access must be aligned! + size_t ValPos = align(Code.size()); + Size = align(Size); + assert(aligned(ValPos + Size)); + Code.resize(ValPos + Size); + + Val.serialize(Code.data() + ValPos); +} + template <typename... Tys> bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) { bool Success = true;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits