This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Fixing namespace issues for variables
- From: Joseph Myers <joseph at codesourcery dot com>
- To: <libc-alpha at sourceware dot org>
- Date: Fri, 23 Oct 2015 00:12:22 +0000
- Subject: Fixing namespace issues for variables
- Authentication-results: sourceware.org; auth=none
We have some bugs where library functions use a global variable outside
the namespace of some standards containing those functions, interfering
with programs' own use of variables by that name. These are currently
whitelisted in linknamespace.pl. I'll use signgam (bug 15421) as the
example in what follows (ISO C includes lgamma but not signgam), but the
same applies equally to other cases of this issue.
Normally namespace issues could be fixed by making the problem symbol into
a weak alias for an implementation-namespace symbol and using the
implementation-namespace symbol internally. However, this doesn't work
for data symbols.
A non-PIC program using signgam - whether it defined its own copy with
"int signgam;" or referenced libm's copy with "extern int signgam;" or via
the declaration of signgam when <math.h> is included under some conditions
- uses it with non-PIC code sequences appropriate to a copy of the
variable located directly in that program. When the program is linked, it
then defines a dynamic symbol signgam (at the appropriate symbol version
from glibc), and the dynamic linker makes this preempt the signgam symbol
from libm, so that all references to signgam from within libm end up
referring to the copy from the main program (there may also be a copy
relocation to copy the initializer from libm to the copy in the main
program). If any reference from within libm uses a different name, that
reference does not get preempted, meaning that the two symbols that were
aliases when libm was linked are no longer aliases at runtime.
So simply using aliases is not a solution in the case of data symbols.
The solution I propose instead is as follows. math.h would (under
appropriate feature test macros) do:
extern int *__signgam_location (void);
#define signgam (*__signgam_location ())
__signgam_location would be a new dynamic symbol exported from libm. The
existing signgam export from libm would become a compat symbol.
In static libm, and shared libm for new ports, the variable signgam would
simply be renamed to __signgam, and we'd have:
int *
__signgam_location (void)
{
return &__signgam;
}
In shared libm for existing ports, it would instead return &signgam.
This keeps binary compatibility for existing binaries and shared
libraries, which will continue to bind to the signgam compat symbol from
libm. It is compatible with ISO C for newly linked programs, since (a) a
strict ISO C program won't get the #define in <math.h>, (b) a signgam
symbol from a new program won't bind to a compat symbol in libm and (c)
internal references within libm will thus bind to the compat symbol and so
be preempted by old programs but not new ones. And there is no POSIX
requirement to be able to declare variables (as opposed to certain
functions) yourself without including the corresponding header, or to be
able to use them after #undef, so I believe it is also compatible with
POSIX.
Any comments on this approach? Do people consider it, and the new
__signgam_location symbol (and similar symbols in other cases), OK for
fixing this problem? I think it's preferable to adding new versions of
the lgamma functions that don't set signgam and then selecting versions
based on feature test macros (which is also dubious in conformance terms,
since the lgamma functions *are* valid to declare yourself, in both ISO C
and POSIX).
--
Joseph S. Myers
joseph@codesourcery.com