A segmentation fault occurs inside getwc() if this function is called on a file pointer obtained from a preloaded fopen() which merely returns the (FILE*) pointer returned by the glibc fopen(). System: Linux kernel 2.6.11.4, gcc 3.3.4 To replicate: 1) compile the following code snippet /* Compiled with gcc -Wall -W -D_REENTRANT libtest.c -nostartfiles -shared -fPIC -Wl,-soname,libtest.so -o libtest.so -ldl * */ #define _GNU_SOURCE #include <stdio.h> #include <dlfcn.h> FILE *fopen(const char *path, const char *mode) { FILE * (*real_fopen) (const char*,const char*); real_fopen = dlsym(RTLD_NEXT, "fopen"); if (!real_fopen) { printf("dlsym() failed\n."); return NULL; } printf("invoking real fopen\n"); return (*real_fopen)(path,mode); } 2) compile the following test program /* Compiled with gcc -o test test.c */ #include <stdio.h> #include <wchar.h> int main (void) { FILE *fp = fopen("abcd", "r"); if (!fp) { printf("inside test program: fp == NULL, quitting.\n"); return 0; } wint_t w = getwc(fp); return 0; } 3) run LD_PRELOAD=./libtest.so ./test This generates a segmentation fault inside getwc().
If you look carefully, you'll see that on several arches, including i?86-linux, there are several fopen functions: readelf -Ws /lib/libc.so.6 | grep \ fopen@ 1210: 0046678b 140 FUNC GLOBAL DEFAULT 11 fopen@GLIBC_2.0 1882: 003bd512 50 FUNC GLOBAL DEFAULT 11 fopen@@GLIBC_2.1 6849: 0046678b 140 FUNC GLOBAL DEFAULT 11 fopen@GLIBC_2.0 7521: 003bd512 50 FUNC GLOBAL DEFAULT 11 fopen@@GLIBC_2.1 When you use dlsym and not dlvsym, you bind to the oldest one, backwards compatible fopen which doesn't support wide char stdio.
Subject: Re: seg fault inside getwc() when using LD_PRELOADed code Thank you for your email. Is there a way to automatically bind to the most recent version available on the system? (Or is there a function which will provide me with the name of the most recent version found given a symbol name?) Manuel On 23 Sep 2005 22:23:24 -0000, jakub at redhat dot com <sourceware-bugzilla@sourceware.org> wrote: > > ------- Additional Comments From jakub at redhat dot com 2005-09-23 22:23 ------- > If you look carefully, you'll see that on several arches, including i?86-linux, > there are several fopen functions: > readelf -Ws /lib/libc.so.6 | grep \ fopen@ > 1210: 0046678b 140 FUNC GLOBAL DEFAULT 11 fopen@GLIBC_2.0 > 1882: 003bd512 50 FUNC GLOBAL DEFAULT 11 fopen@@GLIBC_2.1 > 6849: 0046678b 140 FUNC GLOBAL DEFAULT 11 fopen@GLIBC_2.0 > 7521: 003bd512 50 FUNC GLOBAL DEFAULT 11 fopen@@GLIBC_2.1 > When you use dlsym and not dlvsym, you bind to the oldest one, backwards > compatible fopen which doesn't support wide char stdio. > > -- > What |Removed |Added > ---------------------------------------------------------------------------- > Status|NEW |RESOLVED > Resolution| |INVALID > > > http://sourceware.org/bugzilla/show_bug.cgi?id=1377 > > ------- You are receiving this mail because: ------- > You reported the bug, or are watching the reporter. > You are on the CC list for the bug, or are watching someone who is. >
I'm seeing a crash in getwc on an older installation of glibc (glibc 2.3.4). The FILE * in this case did not come from fopen, but rather from popen. No tricks with shared libraries are being played. $ cat popen_getwc.c #include <unistd.h> #include <stdio.h> #include <wchar.h> int main(void) { FILE *command = popen("ls", "r"); wint_t ch = getwc(command); pclose(command); return ch; } $ gcc -Wall popen_getwc.c -o popen_getwc $ ./popen_getwc Segmentation fault $ gcc --version gcc (GCC) 3.4.3 20050227 (Red Hat 3.4.3-22.1) Copyright (C) 2004 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ /lib/libc.so.6 GNU C Library stable release version 2.3.4, by Roland McGrath et al. Copyright (C) 2005 Free Software Foundation, Inc. [ ... etc ... ] The crash is unaffected by whether or not we call setlocale to have LC_CTYPE set up for multi-byte encodings or not. I'm sticking the comment here because it affects an glibc version from around the time when this original bug was reported, and they seem related. I couldn't find anything else in the bug database about a crash in getwc. It's understandable that using dlsym to get to the wrong version of fopen is like sticking a fork in the toaster, hence ``RESOLVED INVALID''. But is it also ``INVALID'' to be doing getwc on a popen'ed stream? I'm going to try the workaround of implementing popen from scratch, so that the stream is then just created with fdopen. The fdopen function is not affected by this problem; I can drop in fdopen/fclose in the place of popen/pclose in the above testcase and it does not crash: #include <unistd.h> #include <stdio.h> #include <wchar.h> int main(void) { FILE *command = fdopen(0, "r"); wint_t ch = getwc(command); /* <- no problem */ pclose(command); return ch; }
(In reply to comment #3) > I'm going to try the workaround of implementing popen from scratch, so that > the stream is then just created with fdopen. There is a much simpler workaround which may work well for some applications, like mine, which have already wrapped streams in an object that can be extended with extra context info. The recipe is: Create the FILE * command stream with popen. Then pull out the file descriptor with fileno, duplicate it with dup, and use fdopen to create a new FILE * descriptor on the duplicate. Then use the new FILE * in place of the old for I/O operations. Keep the original handle in order to call pclose, to collect the process exit status.
Your bugreport seems valid, however please don't hijack old bugs for this, it seems to have nothing to do with the original bugreport, open a new bug instead.
(In reply to comment #5) > Your bugreport seems valid, however please don't hijack old bugs for this, it > seems to have nothing to do with the original bugreport, open a new bug instead. No can do. I got run over by a bus this morning. But, oops, someone flipped the bug status without creating a new record. So it fell through the cracks.
well, thanks for not making life of your overloaded glibc developers easier; bug 10958