Skip to content

[object] Fix reproducer crash when input file has no contents#1166

Open
deepakshirkem wants to merge 1 commit into
qualcomm:mainfrom
deepakshirkem:fix/sysroot-script-crash-818
Open

[object] Fix reproducer crash when input file has no contents#1166
deepakshirkem wants to merge 1 commit into
qualcomm:mainfrom
deepakshirkem:fix/sysroot-script-crash-818

Conversation

@deepakshirkem
Copy link
Copy Markdown
Contributor

Problem

ELD crashes with a segfault when a reproduce tarball contains a linker script that references a file not found in the sysroot.

Testing

Added test SysrootScriptCrash that verifies ELD errors out gracefully instead of segfaulting when a linker script references an unreadable file.

Screenshot

Screenshot from 2026-05-12 18-52-19

Fixes #818

cc @quic-seaswara , @parth-07 , @quic-areg

return true;
if (!Input->getSize())
if (!Input->getSize()) {
ThisConfig.raise(Diag::input_file_has_zero_size) << Input->decoratedPath();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are we emitting this diagnostic for non-existing file? If so, that is incorrect. Also with this modification, the link will fail for existing but 0-sized files. Is this an intended behavior change?

Copy link
Copy Markdown
Contributor Author

@deepakshirkem deepakshirkem May 12, 2026

Choose a reason for hiding this comment

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

Hi @parth-07, I think you are right in both cases. I will update the checks.

# Verify that ELD does not crash when a linker script references a
# file that cannot be read (e.g. not found in sysroot).
# ELD should error out gracefully instead of segfaulting.
# Fix for issue #818.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

github specific references can probably be left out.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hi @quic-areg, Thank You ::)). Will remove it.

@deepakshirkem deepakshirkem force-pushed the fix/sysroot-script-crash-818 branch 2 times, most recently from ea77759 to 02f9cdf Compare May 12, 2026 16:02
@deepakshirkem
Copy link
Copy Markdown
Contributor Author

Hi @parth-07, I have updated the fix. Here is the verified behavior
Screenshot from 2026-05-12 21-30-50

Hi @quic-areg , Updated the test. Please go one more time.

Comment thread lib/Object/ObjectLinker.cpp Outdated
@deepakshirkem deepakshirkem force-pushed the fix/sysroot-script-crash-818 branch from 02f9cdf to b8fb315 Compare May 13, 2026 09:59
@deepakshirkem
Copy link
Copy Markdown
Contributor Author

Hi @Parth / @quic-areg / @quic-seaswara , Updated the suggested test. Please review when get a chance and also the run pipeline.

RUN: %clang %clangopts -o %t1.o %p/Inputs/1.c -c
RUN: touch %t1.empty.o
RUN: llvm-ar rcs %t1.a %t1.o %t1.empty.o
RUN: llvm-ar rcsT %t1.thin.a %t1.o %t1.empty.o
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Use the lit variables, do we know if this will work on windows ?

RUN: %clang %clangopts -o %t1.o %p/Inputs/main.c -c
RUN: %not %link %linkopts %t1.o -T %p/Inputs/script.t 2>&1 | %filecheck %s
#END_TEST
CHECK: cannot read file
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

which file ?

Comment thread lib/Object/ObjectLinker.cpp Outdated
@deepakshirkem deepakshirkem force-pushed the fix/sysroot-script-crash-818 branch from b8fb315 to fdfcc03 Compare May 13, 2026 19:03
@deepakshirkem
Copy link
Copy Markdown
Contributor Author

Hi @quic-seaswara, addressed your comments.

@deepakshirkem deepakshirkem force-pushed the fix/sysroot-script-crash-818 branch from fdfcc03 to 62a09af Compare May 13, 2026 20:10
@deepakshirkem
Copy link
Copy Markdown
Contributor Author

Hi @quic-seaswara, Can you re-run the pipeline one more time.

@deepakshirkem deepakshirkem force-pushed the fix/sysroot-script-crash-818 branch from 62a09af to 937fa19 Compare May 13, 2026 21:29
@deepakshirkem
Copy link
Copy Markdown
Contributor Author

Hi @quic-seaswara, I am not sure why the CI failed for that test case, as it is passing locally for me. I think it might be because my branch was out of date. I have now rebased it with the latest top/main branch. Could you please run the CI one more time? Sorry

Comment thread lib/Object/ObjectLinker.cpp Outdated
// 2. File does not exist (MemArea = null):
// fatal_cannot_read_input already raised. Return false to
// prevent crash in downstream processing.
if (Input->getMemArea())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should not reach readAndProcessInput for an invalid Input *. We resolve the input path and create the MemoryArea for the input in Input::resolvePath(). This function should report the error and return false if the file does not exist.

Copy link
Copy Markdown
Contributor Author

@deepakshirkem deepakshirkem May 16, 2026

Choose a reason for hiding this comment

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

You were right. I found that the root cause is not in resolvePath(), but in resolvePathMappingFile(). The issue is that createMemoryArea() returns nullptr for the missing file, but setMemArea(nullptr) is still called and the function returns true, incorrectly signaling success to the caller. Added GDB logs to the comment as proof.

Really appreciate your review and pointing me in the right direction. Please take a look when you get a chance, and let me know if you have any additional test cases in mind.

@deepakshirkem deepakshirkem force-pushed the fix/sysroot-script-crash-818 branch from 937fa19 to c49fa11 Compare May 16, 2026 16:09
@deepakshirkem
Copy link
Copy Markdown
Contributor Author

Hi @quic-areg / @quic-seaswara / @parth-07 , Here is the GDB log confirming the root cause. Observation Input->getMemArea() = 0x0 — null MemArea enters readAndProcessInput() Execution continues past the size check with no early return Crash occurs inside ScriptLexer when it dereferences the null MemoryArea

Breakpoint 1 (ObjectLinker::readAndProcessInput) pending.
Starting program: /home/deepak/Desktop/Deepak/eld/obj/bin/ld.eld --sysroot=A -T LinkerScript/script.t.11452439568106356749 Object/main.o.8683850154013456601 --mapping-file=mapping.ini

[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, eld::ObjectLinker::readAndProcessInput (this=0x555555809c60, Input=0x55555582a330, IsPostLto=false) at /home/deepak/Desktop/Deepak/eld/lib/Object/ObjectLinker.cpp:3619
3619	  if (Input->isInternal())
Continuing.

Breakpoint 1, eld::ObjectLinker::readAndProcessInput (this=0x555555809c60, Input=0x55555582a410, IsPostLto=false) at /home/deepak/Desktop/Deepak/eld/lib/Object/ObjectLinker.cpp:3619
3619	  if (Input->isInternal())
$1 = (eld::MemoryArea *) 0x0
$2 = 0
3621	  if (!Input->getSize())
3622	    ThisConfig.raise(Diag::input_file_has_zero_size) << Input->decoratedPath();
3623	  LayoutInfo *layoutInfo = ThisModule->getLayoutInfo();
3624	  std::string Path = Input->getResolvedPath().native();
3626	  InputFile *CurInput = Input->getInputFile();
3627	  if (!CurInput) {
3628	    InputFile *I = InputFile::create(Input, ThisConfig.getDiagEngine());
3629	    if (!I) {
3635	    CurInput = I;
3636	    Input->setInputFile(I);
3638	  if (CurInput->shouldSkipFile()) {
3644	  if (Input->getAttribute().isPatchBase() &&
3652	  if (CurInput->isBinaryFile()) {
3867	  else if (CurInput->getKind() == InputFile::GNULinkerScriptKind) {
3868	    eld::RegisterTimer T("Read Linker Script", "Read all Input files",
3869	                         ThisConfig.options().printTimingStats());
3868	    eld::RegisterTimer T("Read Linker Script", "Read all Input files",
3870	    if (layoutInfo)
3872	    addInputFileToTar(CurInput, eld::MappingFile::LinkerScript);
3873	    CurInput->setToSkip();
3874	    if (!readLinkerScript(CurInput)) {

Program received signal SIGSEGV, Segmentation fault.
0x00007fffedde2f45 in std::__uniq_ptr_impl<llvm::MemoryBuffer, std::default_delete<llvm::MemoryBuffer> >::_M_ptr (this=0x0) at /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/unique_ptr.h:199
199	      pointer    _M_ptr() const noexcept { return std::get<0>(_M_t); }
SignalHandler (Sig=0, Info=0x7fffffffa5d8, Context=0x7fffedde2f45 <std::__uniq_ptr_impl<llvm::MemoryBuffer, std::default_delete<llvm::MemoryBuffer> >::_M_ptr() const+21>) at /home/deepak/Desktop/Deepak/llvm-project/llvm/lib/Support/Unix/Signals.inc:399
399	static void SignalHandler(int Sig, siginfo_t *Info, void *Context) {
404	  sys::unregisterHandlers();
#0  SignalHandler (Sig=11, Info=0x5555557e8bb0, Context=0x5555557e8a80) at /home/deepak/Desktop/Deepak/llvm-project/llvm/lib/Support/Unix/Signals.inc:404
#1  <signal handler called>
#2  0x00007fffedde2f45 in std::__uniq_ptr_impl<llvm::MemoryBuffer, std::default_delete<llvm::MemoryBuffer> >::_M_ptr (this=0x0) at /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/unique_ptr.h:199
#3  0x00007fffedde2f25 in std::unique_ptr<llvm::MemoryBuffer, std::default_delete<llvm::MemoryBuffer> >::get (this=0x0) at /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/unique_ptr.h:470
#4  0x00007fffef7706ed in std::unique_ptr<llvm::MemoryBuffer, std::default_delete<llvm::MemoryBuffer> >::operator* (this=0x0) at /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/unique_ptr.h:453
#5  0x00007ffff0b5dd0d in eld::MemoryArea::getMemoryBufferRef (this=0x0) at /home/deepak/Desktop/Deepak/eld/include/eld/Support/MemoryArea.h:63
#6  0x00007ffff0b5d770 in eld::Input::getMemoryBufferRef (this=0x55555582a410) at /home/deepak/Desktop/Deepak/eld/include/eld/Input/Input.h:115
#7  0x00007ffff0d2c4f8 in eld::v2::ScriptLexer::ScriptLexer (this=0x7fffffffa7a8, Config=..., ScriptFile=...) at /home/deepak/Desktop/Deepak/eld/lib/ScriptParser/ScriptLexer.cpp:82
#8  0x00007ffff0d09439 in eld::v2::ScriptParser::ScriptParser (this=0x7fffffffa7a8, Config=..., File=...) at /home/deepak/Desktop/Deepak/eld/lib/ScriptParser/ScriptParser.cpp:53
#9  0x00007ffff0c186ab in eld::ScriptReader::readLinkerScriptUsingNewParser (this=0x555555813d00, PConfig=..., PScriptFile=...) at /home/deepak/Desktop/Deepak/eld/lib/Script/ScriptReader.cpp:47
#10 0x00007ffff0c18675 in eld::ScriptReader::readScript (this=0x555555813d00, PConfig=..., PScriptFile=...) at /home/deepak/Desktop/Deepak/eld/lib/Script/ScriptReader.cpp:42
#11 0x00007ffff0af45d4 in eld::ObjectLinker::readLinkerScript (this=0x555555809c60, Input=0x555555835080) at /home/deepak/Desktop/Deepak/eld/lib/Object/ObjectLinker.cpp:228
#12 0x00007ffff0af66d2 in eld::ObjectLinker::readAndProcessInput (this=0x555555809c60, Input=0x55555582a410, IsPostLto=false) at /home/deepak/Desktop/Deepak/eld/lib/Object/ObjectLinker.cpp:3874
#13 0x00007ffff0b5c69c in eld::GroupReader::readGroup (this=0x555555811ce0, CurNode=0x55555582b3d0, PBuilder=..., PConfig=..., IsPostLtoPhase=false) at /home/deepak/Desktop/Deepak/eld/lib/Object/GroupReader.cpp:55
#14 0x00007ffff0af488f in eld::ObjectLinker::readInputs (this=0x555555809c60, InputVector=std::vector of length 3, capacity 4 = {...})

The fix is in Input::resolvePathMappingFile() adding a null check after createMemoryArea() to return false early instead of propagating a null MemArea downstream. Please let me know if you have any additional test cases in mind! Thank You ::((

@deepakshirkem deepakshirkem force-pushed the fix/sysroot-script-crash-818 branch from c49fa11 to 549f429 Compare May 17, 2026 05:45
@deepakshirkem
Copy link
Copy Markdown
Contributor Author

Hi @quic-seaswara / @quic-areg / @parth-07 , Does this need changes or can it be merged?

Copy link
Copy Markdown
Contributor

@Steven6798 Steven6798 left a comment

Choose a reason for hiding this comment

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

Looks good to me

Copy link
Copy Markdown
Contributor

@parth-07 parth-07 left a comment

Choose a reason for hiding this comment

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

Please change the commit message and PR description to: Fix reproducer crash when input file has no contents.

@deepakshirkem deepakshirkem changed the title [object] Fix crash when input file has no contents [object] Fix reproducer crash when input file has no contents May 27, 2026
@deepakshirkem
Copy link
Copy Markdown
Contributor Author

Please change the commit message and PR description to: Fix reproducer crash when input file has no contents.

Done.

@deepakshirkem deepakshirkem requested a review from parth-07 May 27, 2026 17:04
@parth-07
Copy link
Copy Markdown
Contributor

@deepakshirkem I do not see any update to the commit title.

@deepakshirkem deepakshirkem force-pushed the fix/sysroot-script-crash-818 branch from 549f429 to 0caae32 Compare May 27, 2026 17:14
@deepakshirkem
Copy link
Copy Markdown
Contributor Author

@deepakshirkem I do not see any update to the commit title.

Done! Changes have been pushed. Thank You ::((

@@ -0,0 +1,11 @@
#---SysrootScriptCrash.test----------- Executable -----------------#
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@deepakshirkem This test passes even without the changes of this patch, right? Why did we add this test with this patch?

Copy link
Copy Markdown
Contributor Author

@deepakshirkem deepakshirkem May 28, 2026

Choose a reason for hiding this comment

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

Hi @parth-07, Updated.

ELD crashes with a segfault when a reproduce tarball contains a linker
script that references a file not found in the sysroot. The crash occurs
because Input::resolvePathMappingFile() calls createMemoryArea() which
returns nullptr when the file does not exist, but then calls
setMemArea(nullptr) and returns true — incorrectly signaling success.
This allows a null MemArea input to reach readAndProcessInput(), which
eventually dereferences the null pointer inside ScriptLexer.

Fixes qualcomm#818.

Signed-off-by: deepakshirkem <deepakshirke509@gmail.com>
@deepakshirkem deepakshirkem force-pushed the fix/sysroot-script-crash-818 branch from 0caae32 to a912861 Compare May 28, 2026 13:23
@deepakshirkem deepakshirkem requested a review from parth-07 May 28, 2026 13:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reproducer crashes when the link contains a script that is found in the sysroot

5 participants