Note: This bug is displayed in read-only format because the product is no longer active in Red Hat Bugzilla.

Bug 101837

Summary: lstat relocation error when called from shared library
Product: [Retired] Red Hat Linux Reporter: Jeff Woods <jcwoods>
Component: glibcAssignee: Jakub Jelinek <jakub>
Status: CLOSED NOTABUG QA Contact: Brian Brock <bbrock>
Severity: medium Docs Contact:
Priority: medium    
Version: 8.0CC: fweimer
Target Milestone: ---   
Target Release: ---   
Hardware: i686   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2003-08-07 14:06:58 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Jeff Woods 2003-08-07 13:59:18 UTC
From Bugzilla Helper:
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624

Description of problem:
When lstat is called from a routine in a shared library, the following error is
generated when a binary linked against the shared library is executed:

<binary>: relocation error: <shared library>: undefined symbol: lstat

This also holds true for lstat64, fstat, and fstat64.

This appears to be a problem with the glibc headers, because in sys/stat.h,
lstat is #defined to translate to __lxstat.  lstat is not a symbol in libc,
where __lxstat is.  For some reason, the define is not being applied properly
and lstat remains unresolved.

As a work-around, the #define from sys/stat.h can be removed and inserted at the
top of the shared library source file which calls lstat, and everything works
correctly (see below).

Version-Release number of selected component (if applicable):
glibc-2.3.2-4.80.6

How reproducible:
Always

Steps to Reproduce:
Can be reproduced by building the following source code:

==== main.c ====

#include <stdio.h>

int size(char *);

int main(int argc, char **argv)
{
    int s;

    s = size(argv[1]);
    fprintf(stdout, "Size of %s is %d\n", argv[1], s);

    return 0;
}

==== size.c ====

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int size(char *file)
{
    struct stat sbuf;

    if (lstat(file, &sbuf) < 0)
    {
        perror("lstat");
        return 0;
    }

    fprintf(stdout, "File size: %d\n",sbuf.st_size);
    return sbuf.st_size;
}

Then:

% gcc -c -o size.o size.c
% ld -G -o libsize.so size.o
% gcc -L. -lsize -o main main.c
% export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
% ./main main.c

Actual Results:  Received the relocation error:

./main: relocation error: ./libsize.so: undefined symbol: lstat


Expected Results:  The binary should have executed without the relocation error.

Additional info:

There is a work-around for this, though it is somewhat awkward.  Modifying the
size.c file to include the #define from sys/stat.h corrects the problem:

==== size.c ====
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

static __inline__ int lstat (__const char *__path,
                                     struct stat *__statbuf) __THROW
{
      return __lxstat (_STAT_VER, __path, __statbuf);
}

int size(char *file)
{
    struct stat sbuf;

    if (lstat(file, &sbuf) < 0)
    {
        perror("lstat");
        return 0;
    }

    fprintf(stdout, "File size: %d\n",sbuf.st_size);
    return sbuf.st_size;
}

Rebuild using the steps above, and everything works correctly.

Comment 1 Jakub Jelinek 2003-08-07 14:06:58 UTC
The problem is in how you are building the shared library.
Never ever use ld directly unless you know what you are doing.
Use gcc -shared -o libsize.so size.o
to link it instead. lstat etc. are not #define's, they are extern inline
functions, but without optimizations (ie. how you are compiling it) they are
not inlined. gcc driver during linking ensures the library is linked against
all necessary libraries (like -lc, which actually expands to libc.so.6 dependency
and libc_nonshared.a).