From 9eccc6cce07b2af29db1836dabf3e2118908ee8d Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Fri, 10 Feb 2023 22:27:44 -0800 Subject: [PATCH] [JITLink] Add a predicate to test for C-string blocks. --- .../include/llvm/ExecutionEngine/JITLink/JITLink.h | 5 +++++ llvm/lib/ExecutionEngine/JITLink/JITLink.cpp | 15 +++++++++++++ .../JITLink/MachOLinkGraphBuilder.cpp | 7 +++++- .../ExecutionEngine/JITLink/LinkGraphTests.cpp | 25 ++++++++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h index f0528064..902c5ef 100644 --- a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h @@ -362,6 +362,11 @@ inline orc::ExecutorAddr alignToBlock(orc::ExecutorAddr Addr, Block &B) { return orc::ExecutorAddr(alignToBlock(Addr.getValue(), B)); } +// Returns true if the given blocks contains exactly one valid c-string. +// Zero-fill blocks of size 1 count as valid empty strings. Content blocks +// must end with a zero, and contain no zeros before the end. +bool isCStringBlock(Block &B); + /// Describes symbol linkage. This can be used to make resolve definition /// clashes. enum class Linkage : uint8_t { diff --git a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp index bd5b4d5..bc359a3 100644 --- a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp @@ -88,6 +88,21 @@ const char *getScopeName(Scope S) { llvm_unreachable("Unrecognized llvm.jitlink.Scope enum"); } +bool isCStringBlock(Block &B) { + if (B.getSize() == 0) // Empty blocks are not valid C-strings. + return false; + + // Zero-fill blocks of size one are valid empty strings. + if (B.isZeroFill()) + return B.getSize() == 1; + + for (size_t I = 0; I != B.getSize() - 1; ++I) + if (B.getContent()[I] == '\0') + return false; + + return B.getContent()[B.getSize() - 1] == '\0'; +} + raw_ostream &operator<<(raw_ostream &OS, const Block &B) { return OS << B.getAddress() << " -- " << (B.getAddress() + B.getSize()) << ": " diff --git a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp index a520008..fb32c02 100644 --- a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp @@ -660,7 +660,7 @@ Error MachOLinkGraphBuilder::graphifyCStringSection( orc::ExecutorAddrDiff BlockStart = 0; // Scan section for null characters. - for (size_t I = 0; I != NSec.Size; ++I) + for (size_t I = 0; I != NSec.Size; ++I) { if (NSec.Data[I] == '\0') { size_t BlockSize = I + 1 - BlockStart; // Create a block for this null terminated string. @@ -727,6 +727,11 @@ Error MachOLinkGraphBuilder::graphifyCStringSection( BlockStart += BlockSize; } + } + + assert(llvm::all_of(NSec.GraphSection->blocks(), + [](Block *B) { return isCStringBlock(*B); }) && + "All blocks in section should hold single c-strings"); return Error::success(); } diff --git a/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp b/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp index 6569bb0..86fc7bd 100644 --- a/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp +++ b/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp @@ -711,3 +711,28 @@ TEST(LinkGraphTest, SplitBlock) { EXPECT_EQ(E2->getOffset(), 4U); } } + +TEST(LinkGraphTest, IsCStringBlockTest) { + // Check that the LinkGraph::splitBlock test works as expected. + LinkGraph G("foo", Triple("x86_64-apple-darwin"), 8, support::little, + getGenericEdgeKindName); + auto &Sec = + G.createSection("__data", orc::MemProt::Read | orc::MemProt::Write); + + ArrayRef CString = "hello, world!"; + ArrayRef NotACString = {0, 1, 0, 1, 0}; + + auto &CStringBlock = + G.createContentBlock(Sec, CString, orc::ExecutorAddr(), 1, 0); + auto &NotACStringBlock = + G.createContentBlock(Sec, NotACString, orc::ExecutorAddr(), 1, 0); + auto &SizeOneZeroFillBlock = + G.createZeroFillBlock(Sec, 1, orc::ExecutorAddr(), 1, 0); + auto &LargerZeroFillBlock = + G.createZeroFillBlock(Sec, 2, orc::ExecutorAddr(), 1, 0); + + EXPECT_TRUE(isCStringBlock(CStringBlock)); + EXPECT_FALSE(isCStringBlock(NotACStringBlock)); + EXPECT_TRUE(isCStringBlock(SizeOneZeroFillBlock)); + EXPECT_FALSE(isCStringBlock(LargerZeroFillBlock)); +} -- 2.7.4