Bug 29284 - ld silently exits with empty input files with success
Summary: ld silently exits with empty input files with success
Status: ASSIGNED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.38
: P2 normal
Target Milestone: ---
Assignee: Nick Clifton
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-06-24 21:31 UTC by Jan Engelhardt
Modified: 2022-06-28 17:02 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed: 2022-06-27 00:00:00


Attachments
Proposed Patch (435 bytes, patch)
2022-06-27 14:29 UTC, Nick Clifton
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jan Engelhardt 2022-06-24 21:31:52 UTC
Maybe related: bug #10321

Observed:

sh$ >x.o
sh$ ld -r -o new.o x.o; echo $?
0

Expected:

$? == 1


Long rationale:

A parallel-unsafe Makefile could cause a race between two commands that then concurrently write to the same .o file, leaving it truncated or otherwise incomplete.

When that happens, ld is usually quick to point out that there is a problem with the file. Synthetic example trigger:

sh$ echo 'int main(){}' >x.c
sh$ gcc -c x.c
sh$ ls -lgo x.o
-rw-r--r-- 1 1216 Jun 24 23:17 x.o
sh$ truncate -s 1215 x.o
sh$ ld -r -o new.o x.o; echo $?
x.o: file not recognized: file format not recognized
1

However, when that object file happens to be 0 bytes long, ld silently accepts it.

sh$ truncate -s 0 x.o
sh$ ld -r -o new.o x.o; echo $?
0

Because of this, a project may even end up producing a shared library which is incomplete and you would not necessarily know of if the symbols you believed were included (but aren't) are not exercised by any executable.

sh$ gcc -shared -o new.so x.o y.o z.o; ldd -r new.so
        linux-vdso.so.1 (0x00007ffd816d9000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fa7c2400000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fa7c26e8000)

  “ No "undefined symbol", so everything is fine! ... Right? ”


I recognize that libbfd knows many object and archive file types, and that some formats could potentially have legitimate 0-byte archives. Moreover, the ld(1) manpage elaborates that """If the linker cannot recognize the format of an object file, it will assume that it is a linker script.""" and, unfortunately, 0-sized scripts are legitimate scripts in many programming languages, which makes it harder to detect accidentally truncated files  :-/
Comment 1 Nick Clifton 2022-06-27 14:29:34 UTC
Created attachment 14179 [details]
Proposed Patch

Hi Jan,

  You are right in saying that we should not complain about empty input files.
  But I think that it is also reasonable to complain about empty output files.
  So what do you think of this patch ?

  With it applied I get behaviour like this:

    % ld empty.o -r
    ld: a.out: warning - empty output file - was this intended ?
    % echo $?
    1

  I am not sure if we will need an option to disable this warning.  Can you
  think of any situation where empty outputs are intended ?

Cheers
  Nick
Comment 2 Jan Engelhardt 2022-06-27 16:12:56 UTC
>ld: a.out: warning - empty output file - was this intended ?

Is the output really empty - or at least empty in the BFD sense? a.out is 394 bytes in my case.
Comment 3 Nick Clifton 2022-06-28 15:59:14 UTC
(In reply to Jan Engelhardt from comment #2)
Hi Jan,

> Is the output really empty - or at least empty in the BFD sense? a.out is
> 394 bytes in my case.

In a BFD sense yes - the file has nothing of interest in it.  In a file 
system sense no - there are bytes there as you have discovered.  The linker 
does in fact create an ELF format file, albeit one that is basically useless.

But anyway I have asked around a bit and it seems that there are cases 
where "empty" output files (in the BFD sense) are in fact expected/needed.
So the patch is a non-starter.

Instead I could create a patch to add a new linker command line option which
would warn about zero-length scripts (in the filesystem sense).  I think that
it would have to be disabled by default though, given the point you raised in
the description.  But that would not really be of much help to you since you 
would have to modify your build machinery to include it, and if you are doing
that then you could just add a test of the output file to see if it matches
your expectations.

I am not sure what else to suggest, sorry.

Cheers
  Nick
Comment 4 Jan Engelhardt 2022-06-28 17:02:09 UTC
Come to think of it, instead of truncation, compiler and linkers could:

 * unlink (optional, but worthwhile, since it retains the
   disk space usage pattern as truncation)
 * create temp file in target directory (O_TMPFILE where available,
   otherwise plain)
 * rename

That way, any intermediate state would not be exposed. Files of size 0 would then be legitimate 0-sized files only.