[Lldb-commits] [lldb] 4b9eed9 - [BSDArchive] NULL check the child object file ptr before accessing its member

Wanyi Ye via lldb-commits lldb-commits at lists.llvm.org
Thu Jul 27 10:22:05 PDT 2023


Author: Wanyi Ye
Date: 2023-07-27T13:21:31-04:00
New Revision: 4b9eed9c64f3a01bc2d8e444a94101b696a3809c

URL: https://github.com/llvm/llvm-project/commit/4b9eed9c64f3a01bc2d8e444a94101b696a3809c
DIFF: https://github.com/llvm/llvm-project/commit/4b9eed9c64f3a01bc2d8e444a94101b696a3809c.diff

LOG: [BSDArchive] NULL check the child object file ptr before accessing its member

Recently we've observed lldb crashes caused by missing object file linked to a thin archive (.a) files. The crash is due to a missing NULL check in the code when looking for child object file referred by the thin archive. Malformed archive file should not crash LLDB. Instead, it should report the error and continue.

New error message will look like the following

```
error: libfoo.a(__objects__/foo/barAppDelegate.mm.o) failed to load objfile for path/to/libfoo.a.
Debugging will be degraded for this module.
```

Test Plan:

llvm-lit test
```
./bin/llvm-lit -sv ../llvm-project/lldb/test/API/functionalities/archives/TestBSDArchives.py
```

Test without code change will error out with LLDB crash
```
--
Command Output (stderr):
--
PASS: LLDB (~/llvm-upstream/Debug/bin/clang-arm64) :: test (TestBSDArchives.BSDArchivesTestCase)
PASS: LLDB (~/llvm-upstream/Debug/bin/clang-arm64) :: test_frame_var_errors_when_archive_missing (TestBSDArchives.BSDArchivesTestCase)
FAIL: LLDB (~/llvm-upstream/Debug/bin/clang-arm64) :: test_frame_var_errors_when_mtime_mistmatch_for_object_in_archive (TestBSDArchives.BSDArchivesTestCase)
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      HandleCommand(command = "b a")
1.      HandleCommand(command = "breakpoint set --name 'a'")
Fatal Python error: Segmentation fault

Current thread 0x00000001f7b99e00 (most recent call first):
  File "~/llvm-upstream/Debug/bin/LLDB.framework/Resources/Python/lldb/__init__.py", line 3270 in HandleCommand
  File "~/llvm-upstream/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 2070 in runCmd
  File "~/llvm-upstream/llvm-project/lldb/packages/Python/lldbsuite/test/lldbtest.py", line 2421 in expect
  File "~/llvm-upstream/llvm-project/lldb/test/API/functionalities/archives/TestBSDArchives.py", line 156 in test_frame_var_errors_when_thin_archive_malformed
...
```

Differential Revision: https://reviews.llvm.org/D156367

Added: 
    

Modified: 
    lldb/source/Core/Module.cpp
    lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
    lldb/test/API/functionalities/archives/Makefile
    lldb/test/API/functionalities/archives/TestBSDArchives.py

Removed: 
    


################################################################################
diff  --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index 672d86496bde6d..4b74929d671467 100644
--- a/lldb/source/Core/Module.cpp
+++ b/lldb/source/Core/Module.cpp
@@ -1285,7 +1285,8 @@ ObjectFile *Module::GetObjectFile() {
           // those values that overwrite unspecified unknown values.
           m_arch.MergeFrom(m_objfile_sp->GetArchitecture());
         } else {
-          ReportError("failed to load objfile for {0}",
+          ReportError("failed to load objfile for {0}\nDebugging will be "
+                      "degraded for this module.",
                       GetFileSpec().GetPath().c_str());
         }
       }

diff  --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
index 957ecc223405aa..51b2535421a6a9 100644
--- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
+++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
@@ -540,7 +540,8 @@ ObjectFileSP ObjectContainerBSDArchive::GetObjectFile(const FileSpec *file) {
           std::shared_ptr<DataBuffer> child_data_sp =
               FileSystem::Instance().CreateDataBuffer(child, file_size,
                                                       file_offset);
-          if (child_data_sp->GetByteSize() != object->file_size)
+          if (!child_data_sp ||
+              child_data_sp->GetByteSize() != object->file_size)
             return ObjectFileSP();
           lldb::offset_t data_offset = 0;
           return ObjectFile::FindPlugin(

diff  --git a/lldb/test/API/functionalities/archives/Makefile b/lldb/test/API/functionalities/archives/Makefile
index 43bf6b22f4788a..22cec82538bf42 100644
--- a/lldb/test/API/functionalities/archives/Makefile
+++ b/lldb/test/API/functionalities/archives/Makefile
@@ -2,7 +2,7 @@ C_SOURCES := main.c a.c b.c c.c
 EXE :=  # Define a.out explicitly
 MAKE_DSYM := NO
 
-all: a.out libbar.a
+all: a.out libbar.a libfoo-thin.a
 
 a.out: main.o libfoo.a
 	$(LD) $(LDFLAGS) $^ -o $@
@@ -16,4 +16,9 @@ libbar.a: c.o
 	$(eval LLVM_ARFLAGS := -rcsDT)
 	$(LLVM_AR) $(LLVM_ARFLAGS) $@ $^
 
+libfoo-thin.a: a.o b.o
+	$(eval LLVM_AR := $(LLVM_TOOLS_DIR)/llvm-ar)
+	$(eval LLVM_ARFLAGS := -rcsDT)
+	$(LLVM_AR) $(LLVM_ARFLAGS) $@ $^
+
 include Makefile.rules

diff  --git a/lldb/test/API/functionalities/archives/TestBSDArchives.py b/lldb/test/API/functionalities/archives/TestBSDArchives.py
index cf558d59440b1f..bee5a37c728a29 100644
--- a/lldb/test/API/functionalities/archives/TestBSDArchives.py
+++ b/lldb/test/API/functionalities/archives/TestBSDArchives.py
@@ -129,6 +129,58 @@ def test_frame_var_errors_when_archive_missing(self):
         ]
         self.check_frame_variable_errors(thread, error_strings)
 
+    @skipIfRemote
+    @skipUnlessDarwin
+    def test_frame_var_errors_when_thin_archive_malformed(self):
+        """
+        Create thin archive libfoo.a and make it malformed to make sure
+        we don't crash and report an appropriate error when resolving
+        breakpoint using debug map.
+        """
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        libfoo_path = self.getBuildArtifact("libfoo.a")
+        libthin_path = self.getBuildArtifact("libfoo-thin.a")
+        objfile_a = self.getBuildArtifact("a.o")
+        # Replace the libfoo.a file with a thin archive containing the same
+        # debug information (a.o, b.o). Then remove a.o from the file system
+        # so we force an error when we set a breakpoint on a() function.
+        # Since the a.o is missing, the debug info won't be loaded and we
+        # should see an error when trying to break into a().
+        os.remove(libfoo_path)
+        shutil.copyfile(libthin_path, libfoo_path)
+        os.remove(objfile_a)
+
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+        # We won't be able to see source file
+        self.expect(
+            "b a",
+            substrs=["Breakpoint 1: where = a.out`a, address ="],
+        )
+        # Break at a() should fail
+        (target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint(
+            self, "a", bkpt_module=exe
+        )
+        error_strings = [
+            '"a.o" object from the "',
+            "libfoo.a\" archive: either the .o file doesn't exist in the archive or the modification time (0x",
+            ") of the .o file doesn't match",
+        ]
+        self.check_frame_variable_errors(thread, error_strings)
+
+        # Break at b() should succeed
+        (target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint(
+            self, "b", bkpt_module=exe
+        )
+        self.expect(
+            "thread list",
+            STOPPED_DUE_TO_BREAKPOINT,
+            substrs=["stopped", "stop reason = breakpoint"],
+        )
+        self.expect(
+            "frame variable", VARIABLES_DISPLAYED_CORRECTLY, substrs=["(int) arg = 2"]
+        )
+
     @skipIfRemote
     @skipUnlessDarwin
     def test_frame_var_errors_when_mtime_mistmatch_for_object_in_archive(self):


        


More information about the lldb-commits mailing list