Bug #3987
closedSynchronization pb with external C library
Description
=begin
Summary:
I use an imported function that takes a (FILE *) argument and prints to it. When I pass it an opened FILE from ruby, then try to read this file when the external function returns I most of the time get segfaults. The test case below uses a temp file, but I get the same using STDOUT with a bigger library.
$ cat mylib.c
#include <stdio.h>
int read_and_print(FILE *, unsigned char *) ;
int read_and_print(FILE *outfile, unsigned char *buf)
{
unsigned char len = buf[0] ;
unsigned int i ;
for ( i = 0 ; i < len ; ++i )
{
fprintf(outfile, "[%02x]", buf[i+1]) ;
}
fprintf(outfile, "\n") ;
return len ;
}
$ gcc -Wall -O2 -g -fPIC -Wl,-soname,libmylib.so.1 -shared -o libmylib.so.1 mylib.c
$ cat testmylib.rb
#! /usr/bin/env ruby
encoding: utf-8¶
require 'tempfile'
require 'dl/import'
module MyLib
extend DL::Importer
dlload './libmylib.so.1'
extern 'int read_and_print(FILE *, unsigned char *)'
end
def use_lib(buf)
puts "Now using the external function"
tf = Tempfile.new("testtmp")
MyLib.read_and_print(tf, buf)
tf.close unless tf.closed?
tf.open { |f| puts f.read }
tf.close(true)
puts "Done with external function"
end
puts "Start test"
buf = "".force_encoding("ASCII-8BIT")
buf << 10 << 0 << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9
use_lib(buf)
puts "Test ends here"
$ gdb
GNU gdb (GDB) 7.1-1mdv2010.1 (Mandriva Linux release 2010.1)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i586-mandriva-linux-gnu".
For bug reporting instructions, please see:
http://www.gnu.org/software/gdb/bugs/.
(gdb) file ruby
Reading symbols from /usr/bin/ruby...Reading symbols from /usr/lib/debug/usr/bin/ruby1.9.debug...done.
done.
(gdb) set args testmylib.rb
(gdb) run
Starting program: /usr/bin/ruby testmylib.rb
warning: no loadable sections found in added symbol-file /usr/lib/debug/usr/lib/libruby1.9.so.1.9.1.debug
[Thread debugging using libthread_db enabled]
[New Thread 0xb794fb70 (LWP 13965)]
warning: no loadable sections found in added symbol-file /usr/lib/debug/usr/lib/ruby1.9/1.9/i586-linux/enc/encdb.so.debug
warning: no loadable sections found in added symbol-file /usr/lib/debug/usr/lib/ruby1.9/1.9/i586-linux/enc/trans/transdb.so.debug
warning: no loadable sections found in added symbol-file /usr/lib/debug/usr/lib/ruby1.9/1.9/i586-linux/etc.so.debug
warning: no loadable sections found in added symbol-file /usr/lib/debug/usr/lib/ruby1.9/1.9/i586-linux/dl.so.debug
Start test
Now using the external function
Program received signal SIGSEGV, Segmentation fault.
0xb7c0eadf in vfprintf () from /lib/i686/libc.so.6
(gdb) bt
#0 0xb7c0eadf in vfprintf () from /lib/i686/libc.so.6
#1 0xb7c1903f in fprintf () from /lib/i686/libc.so.6
#2 0xb7fd8475 in read_and_print (outfile=0x7, buf=0x82157c8 "\n")
at mylib.c:11
#3 0xb793f221 in rb_dlcfunc_call (self=136404020, ary=136400680)
at cfunc.c:418
#4 0xb7f14973 in call_cfunc (func=0xb79392b0 <rb_dlcfunc_call>,
recv=, len=1, argc=1, argv=0xb7950070)
at vm_insnhelper.c:320
#5 0xb7f228ea in vm_call_cfunc (th=0x804ba90, cfp=,
num=, blockptr=0x0, flag=0, id=5912, me=0x81adfb0,
recv=136404020) at vm_insnhelper.c:401
#6 vm_call_method (th=0x804ba90, cfp=,
num=, blockptr=0x0, flag=0, id=5912, me=0x81adfb0,
recv=136404020) at vm_insnhelper.c:523
#7 0xb7f1881b in vm_exec_core (th=0x804ba90, initial=)
at insns.def:1006
#8 0xb7f1eb03 in vm_exec (th=0x804ba90) at vm.c:1145
#9 0xb7f25adb in rb_iseq_eval_main (iseqval=134634880) at vm.c:1386
#10 0xb7e2130a in ruby_exec_internal (n=0x8065d80) at eval.c:214
#11 0xb7e21995 in ruby_exec_node (n=0x8065d80) at eval.c:261
#12 0xb7e23325 in ruby_run_node (n=0x8065d80) at eval.c:254
#13 0x080486f8 in main (argc=2, argv=0xbfffee04) at main.c:35
My guess is that the system still tries to write the '\n' but ruby already closed the file.
I ended up digging this way because the output from the external function is not synchronized with the main program:
$ cat testmylib2.rb
#! /usr/bin/env ruby
encoding: utf-8¶
require 'dl/import'
module MyLib
extend DL::Importer
dlload './libmylib.so.1'
extern 'int read_and_print(FILE *, unsigned char *)'
end
def use_lib(buf)
puts "Now using the external function"
MyLib.read_and_print(STDOUT, buf)
puts "Done with external function, returned #{res}"
end
puts "Start test"
buf = "".force_encoding("ASCII-8BIT")
buf << 10 << 0 << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9
use_lib(buf)
puts "Test ends here"
$ ruby testmylib2.rb > testout && cat testout
Start test
Now using the external function
Done with external function, returned 10
Test ends here
[00][01][02][03][04][05][06][07][08][09]
The expected output would of course be:
Start test
Now using the external function
[00][01][02][03][04][05][06][07][08][09]
Done with external function, returned 10
Test ends here
=end
Updated by nobu (Nobuyoshi Nakada) over 14 years ago
- Status changed from Open to Rejected
=begin
Tempfile object just behaves like an IO object, not an IO object itself.
Use to_io method to convert it.
=end