Bug 274211 - lang/tcc: Crashes with SIGSEGV on 14.x / 15.0-CURRENT when compiling hello world
Summary: lang/tcc: Crashes with SIGSEGV on 14.x / 15.0-CURRENT when compiling hello world
Status: Open
Alias: None
Product: Ports & Packages
Classification: Unclassified
Component: Individual Port(s) (show other bugs)
Version: Latest
Hardware: amd64 Any
: --- Affects Only Me
Assignee: freebsd-ports-bugs (Nobody)
URL:
Keywords: crash, needs-qa
Depends on:
Blocks:
 
Reported: 2023-10-02 11:14 UTC by Mina Galić
Modified: 2023-10-05 06:51 UTC (History)
1 user (show)

See Also:


Attachments
valgrind --leak-check=full --show-leak-kinds=all -s tcc (49.17 KB, text/plain)
2023-10-03 20:00 UTC, Mina Galić
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Mina Galić freebsd_triage 2023-10-02 11:14:43 UTC
given the following hello.c:

```
#include <stdio.h>

int main (int argc, const char **argv) {
        printf("Hello, World!\n");
        return 0;
}
```

when invoking tcc to compile a binary (tcc -o hello hello.c)

we get a SIGSEGV in tcc_load_object_file. Here's the full lldb output, with tcc compiled with `-O0 -g`:

```
meena@defbix /u/p/l/t/w/tinycc-release_0_9_26 ❯❯❯ lldb ./tcc -- /home/meena/src/hello.c -o hello
(lldb) target create "./tcc"
Current executable set to '/usr/ports/lang/tcc/work/tinycc-release_0_9_26/tcc' (x86_64).
(lldb) settings set -- target.run-args  "/home/meena/src/hello.c" "-o" "hello"
(lldb) run
Process 20766 launched: '/usr/ports/lang/tcc/work/tinycc-release_0_9_26/tcc' (x86_64)
Process 20766 stopped
* thread #1, name = 'tcc', stop reason = signal SIGSEGV: invalid address (fault address: 0x1c)
    frame #0: 0x000000000022aa26 tcc`tcc_load_object_file(s1=0x00002e6d3ec09000, fd=3, file_offset=0) at tccelf.c:2533:51
   2530         if (sh->sh_link > 0)
   2531             s->link = sm_table[sh->sh_link].s;
   2532         if (sh->sh_type == SHT_RELX) {
-> 2533             s->sh_info = sm_table[sh->sh_info].s->sh_num;
   2534             /* update backward link */
   2535             s1->sections[s->sh_info]->reloc = s;
   2536         }
(lldb) bt all
* thread #1, name = 'tcc', stop reason = signal SIGSEGV: invalid address (fault address: 0x1c)
  * frame #0: 0x000000000022aa26 tcc`tcc_load_object_file(s1=0x00002e6d3ec09000, fd=3, file_offset=0) at tccelf.c:2533:51
    frame #1: 0x00000000002112fe tcc`tcc_add_file_internal(s1=0x00002e6d3ec09000, filename="/usr/lib/crt1.o", flags=0) at libtcc.c:1181:19
    frame #2: 0x0000000000211538 tcc`tcc_add_library_internal(s=0x00002e6d3ec09000, fmt="%s/%s", filename="crt1.o", flags=0, paths=0x00002e6d3ec08010, nb_paths=1) at libtcc.c:1254:13
    frame #3: 0x00000000002115bf tcc`tcc_add_crt(s=0x00002e6d3ec09000, filename="crt1.o") at libtcc.c:1270:15
    frame #4: 0x0000000000211864 tcc`tcc_set_output_type(s=0x00002e6d3ec09000, output_type=1) at libtcc.c:1360:13
    frame #5: 0x000000000020e6a3 tcc`main(argc=4, argv=0x0000000820c88778) at tcc.c:302:5
    frame #6: 0x0000000822e9dbea libc.so.7`__libc_start1(argc=4, argv=0x0000000820c88778, env=0x0000000820c887a0, cleanup=<unavailable>, mainX=(tcc`main at tcc.c:245)) at libc_start1.c:157:7
    frame #7: 0x000000000020e3c0 tcc`_start at crt1_s.S:83
(lldb) 

```

n.b.: Given that this bug only occurs on 14.x / 15.0-CURRENT, chances are that it's got something to do with recent libc/csu changes.

also note that setting ARCHLEVEL=scalar doesn't change the behaviour.
Comment 1 Paul Floyd 2023-10-02 12:29:58 UTC
Can you run it under Valgrind?
If that gives nothing, can you build with address sanitizer?
Comment 2 Mina Galić freebsd_triage 2023-10-03 20:00:57 UTC
Created attachment 245415 [details]
valgrind --leak-check=full --show-leak-kinds=all -s tcc

(In reply to Paul Floyd from comment #1)
rebuild and rerun with ASAN:

```
AddressSanitizer:DEADLYSIGNAL
=================================================================
==90002==ERROR: AddressSanitizer: SEGV on unknown address 0x00000000001c (pc 0x00000035ac8f bp 0x7fffffffd710 sp 0x7fffffffcdc0 T0)
==90002==The signal is caused by a READ memory access.
==90002==Hint: address points to the zero page.
    #0 0x35ac8f in tcc_load_object_file /usr/ports/lang/tcc/work/tinycc-release_0_9_26/tccelf.c:2533:51
    #1 0x3052da in tcc_add_file_internal /usr/ports/lang/tcc/work/tinycc-release_0_9_26/libtcc.c:1181:19
    #2 0x3058f6 in tcc_add_library_internal /usr/ports/lang/tcc/work/tinycc-release_0_9_26/libtcc.c:1254:13
    #3 0x305a6b in tcc_add_crt /usr/ports/lang/tcc/work/tinycc-release_0_9_26/libtcc.c:1270:15
    #4 0x3062e0 in tcc_set_output_type /usr/ports/lang/tcc/work/tinycc-release_0_9_26/libtcc.c:1360:13
    #5 0x2fd12a in main /usr/ports/lang/tcc/work/tinycc-release_0_9_26/tcc.c:302:5
    #6 0x8004e4be9 in __libc_start1 /poudriere/jails/current-amd64/usr/src/lib/libc/csu/libc_start1.c:157:7
    #7 0x251d6f in _start /poudriere/jails/current-amd64/usr/src/lib/csu/amd64/crt1_s.S:83
    #8 0x8003a7007  (<unknown module>)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /usr/ports/lang/tcc/work/tinycc-release_0_9_26/tccelf.c:2533:51 in tcc_load_object_file
==90002==ABORTING
```
Comment 3 Paul Floyd 2023-10-04 06:37:19 UTC
I just tried building the code.

So many warnings that it overflowed my terminal history. Most of them seem to be related to some crappy macro that was probably written for 1970s compilers that didn't have "static". No surprise that junk like that crashes.


I fought with BSD make to get tcc to build something debuggable. In the end I just ran

make WITH_DEBUG=1

then cd'd to work/tinycc-release_0_9_26 and ran

gmake clean ; gmake CFLAGS="-g -fno-omit-frame-pointer" LDFLAGS="-g"

Valgrind still didn't want to read the debuginfo, don't know why.

The crash is here

     2532          if (sh->sh_type == SHT_RELX) { 
  >  2533              s->sh_info = sm_table[sh->sh_info].s->sh_num;

because sm_table[sh->sh_info].s is NULL.

It looks like sm_table is big enough - 26 elements allocated on line 2395 and sh->sh_info is 3.

The file that tcc is reading is /usr/lib/crt1.o

readelf -a on that says

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000000000  00000040
       0000000000000034  0000000000000000  AX       0     0     8
  [ 2] .rela.text        RELA             0000000000000000  00000108
       0000000000000030  0000000000000018   I      23     1     8
  [ 3] .eh_frame         X86_64_UNWIND    0000000000000000  00000078
       0000000000000038  0000000000000000   A       0     0     8
  [ 4] .rela.eh_frame    RELA             0000000000000000  00000138
       0000000000000018  0000000000000018   I      23     3     8

(and there are 26 section headers).

Something looks wrong there.


Assuming that sh->sh_info corresponds to the section header number above, but the "if" in the code makes it look like SHT_RELX / RELA when in fact header 3 is
  [ 3] .eh_frame         X86_64_UNWIND

If I compare the readelf -a output on FreeBSD 13.2 it is quite different. For a start there is no .eh_frame at all.

So I reckon that tcc can't cope with the changed ELF contents of the object file. That's likely to be down to the use of LLVM 16 in FreeBSD 14.

That's all for this morning.
Comment 4 Paul Floyd 2023-10-05 06:51:01 UTC
As I see it there are 2 possible fixes.

At the crash

        if (sh->sh_type == SHT_RELX) {
            s->sh_info = sm_table[sh->sh_info].s->sh_num;

sh is referring to section header 4 for which a new section was created.
sh->sh_info refers to section header 3 which got skipped.

So either the above code needs changing to something like

        if (sh->sh_type == SHT_RELX) {
            if (sm_table[sh->sh_info].new_section) {
                s->sh_info = sm_table[sh->sh_info].s->sh_num;

Or section header 3 needs to be handled so that sm_table[3] has been initialized.

Trying the easy one as above, I get lots of errors in /usr/include/sys/_types.h because it seems like tcc does not know the size of any builtin types.

I also tried "hello world" on FreeBSD 13.2 amd64 and it compiled but the exe coredumps between _start() and main().

From what I see in the port git history there was a code fix back in 2015. Otherwise totally dead.

In the github history a lot has changed.

I don't think that it is worth trying to patch the ports version 0_9_26. It would probably be easier to switch to the upstream 9.28