[llvm] 5cd3db3 - [llvm][ELF]Add Shdr check for getBuildID (#126537)

via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 3 02:02:40 PDT 2025


Author: Ruoyu Qiu
Date: 2025-10-03T10:02:36+01:00
New Revision: 5cd3db3bed62c07790c17bf1947e98bc903472a9

URL: https://github.com/llvm/llvm-project/commit/5cd3db3bed62c07790c17bf1947e98bc903472a9
DIFF: https://github.com/llvm/llvm-project/commit/5cd3db3bed62c07790c17bf1947e98bc903472a9.diff

LOG: [llvm][ELF]Add Shdr check for getBuildID (#126537)

Add Section Header check for getBuildID, fix crash with invalid Program
Header.

Fixes: #126418

---------

Signed-off-by: Ruoyu Qiu <cabbaken at outlook.com>
Signed-off-by: Ruoyu Qiu <qiuruoyu at xiaomi.com>
Co-authored-by: Ruoyu Qiu <qiuruoyu at xiaomi.com>
Co-authored-by: James Henderson <James.Henderson at sony.com>

Added: 
    llvm/unittests/Object/BuildIDTest.cpp

Modified: 
    llvm/lib/Object/BuildID.cpp
    llvm/test/DebugInfo/symbolize-build-id.test
    llvm/unittests/Object/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Object/BuildID.cpp b/llvm/lib/Object/BuildID.cpp
index 89d6bc3ab550d..d1ee597a11327 100644
--- a/llvm/lib/Object/BuildID.cpp
+++ b/llvm/lib/Object/BuildID.cpp
@@ -24,6 +24,24 @@ using namespace llvm::object;
 namespace {
 
 template <typename ELFT> BuildIDRef getBuildID(const ELFFile<ELFT> &Obj) {
+  auto findBuildID = [&Obj](const auto &ShdrOrPhdr,
+                            uint64_t Alignment) -> std::optional<BuildIDRef> {
+    Error Err = Error::success();
+    for (auto N : Obj.notes(ShdrOrPhdr, Err))
+      if (N.getType() == ELF::NT_GNU_BUILD_ID &&
+          N.getName() == ELF::ELF_NOTE_GNU)
+        return N.getDesc(Alignment);
+    consumeError(std::move(Err));
+    return std::nullopt;
+  };
+
+  auto Sections = cantFail(Obj.sections());
+  for (const auto &S : Sections) {
+    if (S.sh_type != ELF::SHT_NOTE)
+      continue;
+    if (std::optional<BuildIDRef> ShdrRes = findBuildID(S, S.sh_addralign))
+      return ShdrRes.value();
+  }
   auto PhdrsOrErr = Obj.program_headers();
   if (!PhdrsOrErr) {
     consumeError(PhdrsOrErr.takeError());
@@ -32,12 +50,8 @@ template <typename ELFT> BuildIDRef getBuildID(const ELFFile<ELFT> &Obj) {
   for (const auto &P : *PhdrsOrErr) {
     if (P.p_type != ELF::PT_NOTE)
       continue;
-    Error Err = Error::success();
-    for (auto N : Obj.notes(P, Err))
-      if (N.getType() == ELF::NT_GNU_BUILD_ID &&
-          N.getName() == ELF::ELF_NOTE_GNU)
-        return N.getDesc(P.p_align);
-    consumeError(std::move(Err));
+    if (std::optional<BuildIDRef> PhdrRes = findBuildID(P, P.p_align))
+      return PhdrRes.value();
   }
   return {};
 }

diff  --git a/llvm/test/DebugInfo/symbolize-build-id.test b/llvm/test/DebugInfo/symbolize-build-id.test
index d63f43ff859e6..2620718293320 100644
--- a/llvm/test/DebugInfo/symbolize-build-id.test
+++ b/llvm/test/DebugInfo/symbolize-build-id.test
@@ -21,6 +21,7 @@ Sections:
     Type:    SHT_NOTE
     Flags:   [ SHF_ALLOC ]
     Content: 040000000800000003000000474e5500abb50d82b6bdc861
+    AddressAlign: 4
 ProgramHeaders:
   - Type:     PT_NOTE
     Flags:    [ PF_R ]

diff  --git a/llvm/unittests/Object/BuildIDTest.cpp b/llvm/unittests/Object/BuildIDTest.cpp
new file mode 100644
index 0000000000000..04ca6364fbc4d
--- /dev/null
+++ b/llvm/unittests/Object/BuildIDTest.cpp
@@ -0,0 +1,120 @@
+//===- BuildIDTest.cpp - Tests for getBuildID ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/BuildID.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/ObjectYAML/yaml2obj.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Testing/Support/Error.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+template <class ELFT>
+static Expected<ELFObjectFile<ELFT>> toBinary(SmallVectorImpl<char> &Storage,
+                                              StringRef Yaml) {
+  raw_svector_ostream OS(Storage);
+  yaml::Input YIn(Yaml);
+  if (!yaml::convertYAML(YIn, OS, [](const Twine &Msg) {}))
+    return createStringError(std::errc::invalid_argument,
+                             "unable to convert YAML");
+  return ELFObjectFile<ELFT>::create(MemoryBufferRef(OS.str(), "dummyELF"));
+}
+
+static StringRef getInvalidNoteELF(bool WithShdr) {
+  static std::string WithSection(R"(
+--- !ELF
+FileHeader:
+  Class:          ELFCLASS64
+  Data:           ELFDATA2LSB
+  Type:           ET_EXEC
+  Machine:        EM_X86_64
+ProgramHeaders:
+  - Type:         PT_NOTE
+    FileSize:     0x1a
+    FirstSec:     .note.gnu.build-id
+    LastSec:      .note.gnu.build-id
+Sections:
+  - Name:         .note.gnu.build-id
+    Type:         SHT_NOTE
+    AddressAlign: 0x04
+    Notes:
+      - Name:     "GNU"
+        Desc:     "abb50d82b6bdc861"
+        Type:     3
+)");
+  static std::string WithoutSection(WithSection + R"(
+  - Type:         SectionHeaderTable
+    NoHeaders:    true
+)");
+  if (WithShdr)
+    return WithSection;
+  return WithoutSection;
+}
+
+// The BuildID can be looked up from a section header, if there is no program
+// header.
+TEST(BuildIDTest, InvalidPhdrFileSizeWithShdrs) {
+  SmallString<0> Storage;
+  Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
+      toBinary<ELF64LE>(Storage, getInvalidNoteELF(true));
+  ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
+  BuildIDRef BuildID = getBuildID(&ElfOrErr.get());
+  EXPECT_EQ(
+      StringRef(reinterpret_cast<const char *>(BuildID.data()), BuildID.size()),
+      "\xAB\xB5\x0D\x82\xB6\xBD\xC8\x61");
+}
+
+// The code handles a malformed program header that points at data outside the
+// file.
+TEST(BuildIDTest, InvalidPhdrFileSizeNoShdrs) {
+  SmallString<0> Storage;
+  Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
+      toBinary<ELF64LE>(Storage, getInvalidNoteELF(false));
+  ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
+  BuildIDRef BuildID = getBuildID(&ElfOrErr.get());
+  EXPECT_EQ(
+      StringRef(reinterpret_cast<const char *>(BuildID.data()), BuildID.size()),
+      "");
+}
+
+// The code handles a malformed section header that points at data outside the
+// file.
+TEST(BuildIDTest, InvalidSectionHeader) {
+  SmallString<0> Storage;
+  Expected<ELFObjectFile<ELF64LE>> ElfOrErr = toBinary<ELF64LE>(Storage, R"(
+--- !ELF
+FileHeader:
+  Class:          ELFCLASS64
+  Data:           ELFDATA2LSB
+  Type:           ET_EXEC
+  Machine:        EM_X86_64
+ProgramHeaders:
+  - Type:         PT_NOTE
+    FirstSec:     .note.gnu.build-id
+    LastSec:      .note.gnu.build-id
+Sections:
+  - Name:         .note.gnu.build-id
+    Type:         SHT_NOTE
+    AddressAlign: 0x04
+    ShOffset:     0x1a1
+    Notes:
+      - Name:     "GNU"
+        Desc:     "abb50d82b6bdc861"
+        Type:     3
+)");
+  ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
+  BuildIDRef BuildID = getBuildID(&ElfOrErr.get());
+  EXPECT_EQ(
+      StringRef(reinterpret_cast<const char *>(BuildID.data()), BuildID.size()),
+      "\xAB\xB5\x0D\x82\xB6\xBD\xC8\x61");
+}

diff  --git a/llvm/unittests/Object/CMakeLists.txt b/llvm/unittests/Object/CMakeLists.txt
index 1343352d1dc69..cd70a7b18b5f4 100644
--- a/llvm/unittests/Object/CMakeLists.txt
+++ b/llvm/unittests/Object/CMakeLists.txt
@@ -7,6 +7,7 @@ set(LLVM_LINK_COMPONENTS
 
 add_llvm_unittest(ObjectTests
   ArchiveTest.cpp
+  BuildIDTest.cpp
   COFFObjectFileTest.cpp
   DXContainerTest.cpp
   ELFObjectFileTest.cpp


        


More information about the llvm-commits mailing list