tinycc-devel
[Top][All Lists]
Advanced

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

Re: [Tinycc-devel] realpath(x, NULL) doesn't work with tcc(1)


From: Michael Matz
Subject: Re: [Tinycc-devel] realpath(x, NULL) doesn't work with tcc(1)
Date: Mon, 6 Jun 2016 04:08:16 +0200 (CEST)
User-agent: Alpine 2.20 (LSU 67 2015-01-07)

Hi,

On Thu, 2 Jun 2016, Steffen Nurpmeso wrote:

Well, have i yet asked this?  I think no...
It's like that for a long time, ever since i use tcc(1) (autumn
last year):

 address@hidden tmp]$ cat t.c
 #include <stdlib.h>
 int main(void){
    char *x = realpath(".", NULL);

    return (x != NULL) ? 0 : 1;
 }
 address@hidden tmp]$ for i in clang gcc tcc; do \
   $i -o zt t.c && ./zt; echo $i: $?;\
 done
 clang: 0
 gcc: 0
 tcc: 1

tcc(1) only gets realpath(3) with buffer argument right, i wonder
what that can be?

Wow. You've run into the result of an unimplemented feature of tcc, which I never thought would matter in practice ;-) I'll explain, bear with me: in POSIX 2001 the result of using NULL as 'resolved_path' argument to realpath(3) was left implementation defined. This was an unworkable interface (you basically had no way of finding out if the returned buffer has overflown), so in POSIX 2008 this was specified universally as meaning to malloc the returned buffer. Now, glibc at the time (versions < 2.3) was using that old standards freedom to define this as unsupported. You will see in your program that errno is set to EINVAL after realpath returns NULL with a NULL second argument.

Later glibc introduced the newer and more sensible behaviour with accepting NULL as second argument. But glibc also has a strict no change in interfaces policy, and this was a visible change, so symbol versioning had to be used to provide the old behaviour for old applications (those linked with glibc < 2.3) and new behaviour for new ones. So, since then glibc exports two variants of realpath: address@hidden and realpath@@GLIBC_2.3. Normally when linking executables against a libc providing these two symbols the link editor, when it supports symbol versions, will choose the newest one, record that fact into the executable, and when running the dynamic linker will search for address@hidden and use it.

"when it supports symbol versions" is of course the crucial part: tcc as ELF linker doesn't. So it leaves in an unversioned reference to 'realpath' in the executable and so the dynamic linker is free to choose any. Now the usual ld.so uses a (normally) sensible heuristic for choosing which one when there are several: for references from dlsym it uses the newest available one, for references from applications that have no symbol version information whatsoever it uses the oldest symbol version, on the grounds that apps without any symversion info must have been created before the ELF implementation provided them, i.e. they must be very very old applications.

This reasoning breaks down with an incomplete link editor like tcc. It creates new applications that are regarded as very old by ld.so. So, what you see is ld.so resolving to the old implementation of realpath, instead of the current one.

Short of implementing proper ELF symbol versioning in tcc there's only an ugly work-around: you could use a different link editor. Perhaps there's somewhen a rainy weekend when the former can be done.


Ciao,
Michael.



reply via email to

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