bug-binutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Bug ld/23254] ld.bfd mishandles file pointers while scanning archive wi


From: zenith432 at users dot sourceforge.net
Subject: [Bug ld/23254] ld.bfd mishandles file pointers while scanning archive with LTO members, causing "malformed archive" errors for a well-formed archive
Date: Mon, 04 Jun 2018 15:16:57 +0000

https://sourceware.org/bugzilla/show_bug.cgi?id=23254

--- Comment #3 from zenith432 at users dot sourceforge.net ---
- Your attached patch fixes the problem.

- For the record, I did a workaround with the patch

========
--- orig_plugin.c       2018-01-13 13:31:16.000000000 +0000
+++ plugin.c    2018-06-04 14:41:38.000000000 +0000
@@ -1059,7 +1059,9 @@ plugin_call_claim_file (const struct ld_
          called_plugin = curplug;
          cur_offset = lseek (file->fd, 0, SEEK_CUR);
          rv = (*curplug->claim_file_handler) (file, claimed);
+#if 0
          if (!*claimed)
+#endif
            lseek (file->fd, cur_offset, SEEK_SET);
          called_plugin = NULL;
          if (rv != LDPS_OK)
========

I do not believe this workaround is formally correct - because the plugin is
allowed to continue moving the file pointer via the file descriptor it got.  As
a practical matter, I found by setting debug breakpoints that the current
plugin only moves the file pointer in claim_file_handler, so protecting the
pointer around that call resolved the issue.

- I attached above a standalone example to reproduce the problem, however I can
only get it to happen on macOS.  On Fedora everything runs fine.

gcc is 8.1, binutils built from 2.30 (same happens on git master)

On macOS the output is
/usr/local/bin/gcc -flto -c -o a.o a.c
/usr/local/bin/gcc -flto -c -o b.o b.c
/usr/local/bin/gcc -flto -c -o c.o c.c
/usr/local/bin/gcc-ar cr libarch.a a.o b.o c.o
/usr/local/bin/gcc -nostdlib -flto -o main main.c -L . -larch
./libarch.a: error adding symbols: Malformed archive
collect2: error: ld returned 1 exit status
make: *** [all] Error 1

I had to use -nostdib on macOS because it's a cross compiler and I don't have
the runtime, but it doesn't matter because the "Malformed archive" error is
encountered *before* other errors about unfound entry point or undefined
printf.

The size of stdio FILE buffer is 4096 (it's the same on Fedora)
a.c is cooked up so inside libarch.a the ar_hdr for b.o is split across the
4096 position boundary.
Here is what happens exactly:
- First LD scans and processes a.o inside libarch.a using fseek/fread.  To do
this, stdio reads a 4096 buffer managed through FILE and caches 4096 as the
file pointer.
- Eventually a.o is passed down to claim_file_handler.  The plugin re-processes
a.o using lseek/read, with the file pointer ending up at the end of a.o inside
libarch.a instead of at 4096.
- Then it goes back to process b.o.  At this point stdio FILE has a 4096 byte
buffer and believes the file pointer is at 4096.
- b.o ar_hdr starts a few bytes below 4096, which is in the cached buffer. 
fseek is called to move to b.o header - Since it's in the buffer, fseek does
not lseek, but positions its internal pointer.
- then fread is called to read the ar_hdr for b.o.  The few bytes in the cached
buffer are copied.  Then fread, believing the file pointer to be at 4096, reads
another 4096, but from the wrong location in the file.
- Because the wrong location was read, the ar_hdr for b.o ends up being read
corrupted which is why it breaks with "Malformed archive".

So even if you can't reproduce it, this is what happens and you can follow it
by adding printfs to ld code (or running in debugger).

It doesn't break on Fedora and I'm not sure why.  One possibility is that the
pre-canned binaries are patched somehow.  The other possibility is that Fedora
fseek always calls lseek when moving to b.o ar_hdr which prevents the glitch.

Regards.

-- 
You are receiving this mail because:
You are on the CC list for the bug.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]