Skip to content

[llvm][llvm-objdump] Fix fatbin handling on 32-bit systems #141620

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

Merged
merged 1 commit into from
May 28, 2025

Conversation

DavidSpickett
Copy link
Collaborator

@DavidSpickett DavidSpickett commented May 27, 2025

Which fixes a test failure seen on the bots, introduced by #140286.

[ RUN      ] OffloadingBundleTest.checkExtractOffloadBundleFatBinary
ObjectTests: ../llvm/llvm/include/llvm/ADT/StringRef.h:618: StringRef llvm::StringRef::drop_front(size_t) const: Assertion `size() >= N && "Dropping more elements than exist"' failed.
0 0x0a24a990 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/tcwg-buildbot/worker/clang-armv8-quick/stage1/unittests/Object/./ObjectTests+0x31a990)
1 0x0a248364 llvm::sys::RunSignalHandlers() (/home/tcwg-buildbot/worker/clang-armv8-quick/stage1/unittests/Object/./ObjectTests+0x318364)
2 0x0a24b410 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
3 0xf46ed6f0 __default_rt_sa_restorer ./signal/../sysdeps/unix/sysv/linux/arm/sigrestorer.S:80:0
4 0xf46ddb06 ./csu/../sysdeps/unix/sysv/linux/arm/libc-do-syscall.S:47:0
5 0xf471d292 __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
6 0xf46ec840 gsignal ./signal/../sysdeps/posix/raise.c:27:6

Also reported on 32-bit x86.

I think the cause is the code was casting the result of StringRef.find into an int64_t. The failure value of find is StringRef::npos, which is defined as:
static constexpr size_t npos = ~size_t(0);

  • size_t(0) is 32 bits of 0s
  • the inverse of that is 32 bits of 1s
  • Cast to int64_t needs to widen this, and it will preserve the original value in doing so, which is 0xffffffff.
  • The result is 0x00000000ffffffff, which is >= 0, so we keep searching and try to go off the end of the file.

Or put another way, this equivalent function returns true when compiled for a 32-bit system:

bool fn() {
    size_t foo = ~size_t(0);
    int64_t foo64 = (int64_t)foo;
    return foo64 >= 0;
}

Using size_t throughout fixes the problem. Also I don't see a reason it needs to be a signed number, given that it always searches forward from the current offset.

Which fixes a test failure seen on the bots, introduced by
llvm#140286.

[ RUN      ] OffloadingBundleTest.checkExtractOffloadBundleFatBinary
ObjectTests: ../llvm/llvm/include/llvm/ADT/StringRef.h:618: StringRef llvm::StringRef::drop_front(size_t) const: Assertion `size() >= N && "Dropping more elements than exist"' failed.
0 0x0a24a990 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/tcwg-buildbot/worker/clang-armv8-quick/stage1/unittests/Object/./ObjectTests+0x31a990)
1 0x0a248364 llvm::sys::RunSignalHandlers() (/home/tcwg-buildbot/worker/clang-armv8-quick/stage1/unittests/Object/./ObjectTests+0x318364)
2 0x0a24b410 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
3 0xf46ed6f0 __default_rt_sa_restorer ./signal/../sysdeps/unix/sysv/linux/arm/sigrestorer.S:80:0
4 0xf46ddb06 ./csu/../sysdeps/unix/sysv/linux/arm/libc-do-syscall.S:47:0
5 0xf471d292 __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
6 0xf46ec840 gsignal ./signal/../sysdeps/posix/raise.c:27:6

Also reported on 32-bit x86.

The cause is that the code was casting the result of StringRef.find
into an int64_t. The failure value of find is StringRef::npos, which
is defined as:
static constexpr size_t npos = ~size_t(0);

So making that into an int64_t means it is > 0 and the code continued
to search for bundles that didn't exist, at an offset beyond the largest
file we could handle.

I have changed the code to use size_t throughout, as this matches the
APIs used, and it does not search backwards in the file so the offset
does not need to be signed.
@llvmbot
Copy link
Member

llvmbot commented May 27, 2025

@llvm/pr-subscribers-llvm-binary-utilities

Author: David Spickett (DavidSpickett)

Changes

Which fixes a test failure seen on the bots, introduced by #140286.

[ RUN      ] OffloadingBundleTest.checkExtractOffloadBundleFatBinary
ObjectTests: ../llvm/llvm/include/llvm/ADT/StringRef.h:618: StringRef llvm::StringRef::drop_front(size_t) const: Assertion `size() >= N && "Dropping more elements than exist"' failed.
0 0x0a24a990 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/tcwg-buildbot/worker/clang-armv8-quick/stage1/unittests/Object/./ObjectTests+0x31a990)
1 0x0a248364 llvm::sys::RunSignalHandlers() (/home/tcwg-buildbot/worker/clang-armv8-quick/stage1/unittests/Object/./ObjectTests+0x318364)
2 0x0a24b410 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
3 0xf46ed6f0 __default_rt_sa_restorer ./signal/../sysdeps/unix/sysv/linux/arm/sigrestorer.S:80:0
4 0xf46ddb06 ./csu/../sysdeps/unix/sysv/linux/arm/libc-do-syscall.S:47:0
5 0xf471d292 __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
6 0xf46ec840 gsignal ./signal/../sysdeps/posix/raise.c:27:6

Also reported on 32-bit x86.

I think the cause is the code was casting the result of StringRef.find into an int64_t. The failure value of find is StringRef::npos, which is defined as:
static constexpr size_t npos = ~size_t(0);

I think what happens is size_t(0) is 32 bits of 0s, inverted to 32 bits of 1s. This is then cast to int64_t, which you might think would sign extend from the most significant bit, but if it did not and just added 0s, then the result would always be > 0. So I could be wrong about the exact cause here, but switching to size_t throughout fixes the issue.

Also I don't see a reason it needs to be a signed number, given that it always searches forward from the current offset.


Full diff: https://github.com/llvm/llvm-project/pull/141620.diff

1 Files Affected:

  • (modified) llvm/lib/Object/OffloadBundle.cpp (+5-7)
diff --git a/llvm/lib/Object/OffloadBundle.cpp b/llvm/lib/Object/OffloadBundle.cpp
index 5f087a5c84e8d..239a3e2616ba5 100644
--- a/llvm/lib/Object/OffloadBundle.cpp
+++ b/llvm/lib/Object/OffloadBundle.cpp
@@ -38,12 +38,11 @@ Error extractOffloadBundle(MemoryBufferRef Contents, uint64_t SectionOffset,
                            StringRef FileName,
                            SmallVectorImpl<OffloadBundleFatBin> &Bundles) {
 
-  uint64_t Offset = 0;
-  int64_t NextbundleStart = 0;
+  size_t Offset = 0;
+  size_t NextbundleStart = 0;
 
   // There could be multiple offloading bundles stored at this section.
-  while (NextbundleStart >= 0) {
-
+  while (NextbundleStart != StringRef::npos) {
     std::unique_ptr<MemoryBuffer> Buffer =
         MemoryBuffer::getMemBuffer(Contents.getBuffer().drop_front(Offset), "",
                                    /*RequiresNullTerminator=*/false);
@@ -60,10 +59,9 @@ Error extractOffloadBundle(MemoryBufferRef Contents, uint64_t SectionOffset,
 
     // Find the next bundle by searching for the magic string
     StringRef Str = Buffer->getBuffer();
-    NextbundleStart =
-        (int64_t)Str.find(StringRef("__CLANG_OFFLOAD_BUNDLE__"), 24);
+    NextbundleStart = Str.find(StringRef("__CLANG_OFFLOAD_BUNDLE__"), 24);
 
-    if (NextbundleStart >= 0)
+    if (NextbundleStart != StringRef::npos)
       Offset += NextbundleStart;
   }
 

@DavidSpickett DavidSpickett requested a review from jhuber6 May 27, 2025 15:25
@DavidSpickett
Copy link
Collaborator Author

Still running the rest of the tests locally to confirm.

Also wondering if this was using 64 bit types because you expect files greater than 4GB. In which case we can keep it as it was but add a check for StringRef::npos before we do any conversions.

@mgorny
Copy link
Member

mgorny commented May 27, 2025

I've started a test run too, it should finish in 20 minutes or so.

@DavidSpickett
Copy link
Collaborator Author

With this PR I had no test failures on an Armv8 32-bit machine.

Copy link
Member

@mgorny mgorny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I can confirm that it fixed the problem for me.

Copy link
Contributor

@david-salinas david-salinas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@DavidSpickett DavidSpickett merged commit f8ca9e5 into llvm:main May 28, 2025
13 checks passed
@DavidSpickett DavidSpickett deleted the 32bit-bundle branch May 28, 2025 08:05
sivan-shani pushed a commit to sivan-shani/llvm-project that referenced this pull request Jun 3, 2025
Which fixes a test failure seen on the bots, introduced by
llvm#140286.
```
[ RUN      ] OffloadingBundleTest.checkExtractOffloadBundleFatBinary
ObjectTests: ../llvm/llvm/include/llvm/ADT/StringRef.h:618: StringRef llvm::StringRef::drop_front(size_t) const: Assertion `size() >= N && "Dropping more elements than exist"' failed.
0 0x0a24a990 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/tcwg-buildbot/worker/clang-armv8-quick/stage1/unittests/Object/./ObjectTests+0x31a990)
1 0x0a248364 llvm::sys::RunSignalHandlers() (/home/tcwg-buildbot/worker/clang-armv8-quick/stage1/unittests/Object/./ObjectTests+0x318364)
2 0x0a24b410 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
3 0xf46ed6f0 __default_rt_sa_restorer ./signal/../sysdeps/unix/sysv/linux/arm/sigrestorer.S:80:0
4 0xf46ddb06 ./csu/../sysdeps/unix/sysv/linux/arm/libc-do-syscall.S:47:0
5 0xf471d292 __pthread_kill_implementation ./nptl/pthread_kill.c:44:76
6 0xf46ec840 gsignal ./signal/../sysdeps/posix/raise.c:27:6
```
Also reported on 32-bit x86.

I think the cause is the code was casting the result of StringRef.find
into an int64_t. The failure value of find is StringRef::npos, which is
defined as:
static constexpr size_t npos = ~size_t(0);

* size_t(0) is 32 bits of 0s
* the inverse of that is 32 bits of 1s
* Cast to int64_t needs to widen this, and it will preserve the original
value in doing so, which is 0xffffffff.
* The result is 0x00000000ffffffff, which is >= 0, so we keep searching
and try to go off the end of the file.

Or put another way, this equivalent function returns true when compiled
for a 32-bit system:
```
bool fn() {
    size_t foo = ~size_t(0);
    int64_t foo64 = (int64_t)foo;
    return foo64 >= 0;
}
```

Using size_t throughout fixes the problem. Also I don't see a reason it
needs to be a signed number, given that it always searches forward from
the current offset.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants