Bug #5108

ruby 1.8.7 fails to build with glibc 2.14

Added by csabahenk (Csaba Henk) over 6 years ago. Updated over 5 years ago.

Target version:
ruby -v:
ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]


On a glibc-2.14 based GNU/Linux system (recent Arch where I've seen;
looking around on the net suggests that Fedora 15 is affected too) you get
the following error in ext/dl when building ruby 1.8.7:

compiling dl
make[1]: Entering directory /home/csaba/aur/ruby-1.8.7-svn/src/ext/dl'
Generating callback.func
Generating cbtable.func
gcc -I. -I../.. -I../../. -I../.././ext/dl -DHAVE_DLFCN_H -DHAVE_DLOPEN -DHAVE_DLCLOSE -DHAVE_DLSYM -DHAVE_DLERROR -I. -fPIC -g -O2 -fno-defer-pop -fno-omit-frame-pointer -c dl.c
In file included from dl.c:104:0:
callback.func:1:1: warning: data definition has no type or storage class [enabled by default]
callback.func:1:7: error: expected identifier or ‘(’ before ‘long’
In file included from dl.c:104:0:
callback.func:78:33: error: expected ‘)’ before ‘(’ token
callback.func:79:3: warning: data definition has no type or storage class [enabled by default]
callback.func:79:24: error: ‘proc’ undeclared here (not in a function)
callback.func:79:39: error: ‘argc’ undeclared here (not in a function)
callback.func:79:45: error: ‘argv’ undeclared here (not in a function)
callback.func:82:1: error: expected identifier or ‘(’ before ‘}’ token
dl.c:106:1: error: expected ‘;’, ‘,’ or ‘)’ before ‘static’
make[1]: *** [dl.o] Error 1
make[1]: Leaving directory
make: *** [all] Error 1

This is caused by the fact that the generated file callback.func is corrupt.
The corruption is triggered by a recent glibc change:;a=commitdiff;h=glibc-2.13-161-gfcabc0f

which was to fix a POSIX compatibility issue:

namely, that upon closing a stream (fclose(3)) the underlying file descriptor should
be moved to the position where I/O was done on the stream last time.

How this affects the build?

Upon generating callback.func, mkmf is required. While mkmf.rb is loaded,
a rogue duplicate of $stdout is created:

When the generating script has finishes its work, ruby prepares to terminate and
does a GC. During GC, the rogue duplicate is closed, which, with the above glibc
semantics implies that the output file is seeked to 0 position. The last writeout
of $stdout's buffered data takes places after the seek, so the tail of the generated
code will be written to the beginning of the file, instead of being appended to.

The attached patch makes sure that no long-lived duplicate of $stdout hangs around.

NOTE: the POSIX requirement to which glibc tries to adhere seems to have some
ambiguity -- it says:

"[...] the next operation on the open file description deals with the byte after the last
one read from or written to the stream being closed."

Now, "the last one" read / written seems to have the implicit assumption that there
was actually something read / written. So it's ambiguous in the case when there was
nothing done with the stream in between opening and closing it. Glibc choose to
position the descriptor in this case too, that's why ruby is affected; on the other
OS of which we know that it adheres to this part of the standard (Solaris, as it's
pointed out in the glibc bug report) ruby is not affected because Solaris libc does
not position a file in the no-I/O-fclose case.

I'll check with Glibc folks what's their opinion about this corner case.

stdout-rouge-fix.patch (719 Bytes) stdout-rouge-fix.patch csabahenk (Csaba Henk), 07/27/2011 10:46 PM


#2 [ruby-core:42195] Updated by kridtek (Andreas Krüger) about 6 years ago

For a workaround, I have added STDOUT.flush at the end of each of the three scripts ruby-1.8.7-p357/ext/dl/mk*rb .

This allowed the compile to proceed.

#3 [ruby-core:47076] Updated by pwnall (Victor Costan) over 5 years ago

Please consider merging this, so 1.8.7 builds on Fedora without patches.

#4 [ruby-core:47077] Updated by naruse (Yui NARUSE) over 5 years ago

  • Status changed from Open to Rejected
  • Priority changed from 5 to Normal

The normal maintenance of Ruby 1.8.7 is finished in June.
So the patch won't be merged.

specify --without-dl and use libffi gem or something.

Also available in: Atom PDF