Project

General

Profile

Bug #1856 ยป seg-fault.rb

Source code that re-produces the problem - anthonywright (Anthony Wright), 08/01/2009 10:25 PM

 
# Ruby Treasures 0.4
# Copyright (C) 2002 Paul Brannan <paul@atdesk.com>
#
# You may distribute this software under the same terms as Ruby (see the file
# COPYING that was distributed with this library).
#
require 'fcntl'

module Open3Z
PROCESSES = Hash.new

# Make sure we clean up our child processes, and ONLY our child processes.
orig_sigchld_handler = trap "CLD" do |*args|
begin
PROCESSES.each do |pid, foo|
if Process.waitpid(pid, Process::WNOHANG) == pid then
PROCESSES.delete(pid)
end
end
rescue Errno::ECHILD
end
orig_sigchld_handler.call(*args) if not orig_sigchld_handler.nil?
end

##
# A version of popen3 that yields (or returns) rd, wr, err, pid
#
def popen3_with_pid(*cmd)
rd = IO.pipe() # stdin (child reads from 0, parent writes to 1)
wr = IO.pipe() # stdout (child writes to 1, parent reads from 0)
err = IO.pipe() # stderr (child writes to 1, parent reads from 0)
ps = IO.pipe() # status (child writes to 1, parent reads from 0)

# Set "close on exec". As soon as the pipe is closed, we know that the
# child process has made a successful call to exec (if we ever read data
# from the pipe, though, it is an exception that was Marshaled from the
# child).
ps[1].fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)

pid = fork do
# child
rd[1].close ; STDIN .reopen(rd[0]) ; rd[0].close
wr[0].close ; STDOUT.reopen(wr[1]) ; wr[1].close
err[0].close ; STDERR.reopen(err[1]) ; err[1].close

begin
exec(*cmd)
raise "exec returned!"
rescue Exception
Marshal.dump($!, ps[1])
ps[1].flush
end
ps[1].close unless ps[1].closed?
exit!
end

# parent
rd[0].close
wr[1].close
err[1].close
ps[1].close

exc = nil
begin
exc = Marshal.load(ps[0])
rescue EOFError
# If we get an EOF error, then the exec was successful.
end

# If exc is set, then the exec was NOT successful.
if not exc.nil? then
raise exc
end

pi = [rd[1], wr[0], err[0], pid]
if block_given? then
begin
return yield(*pi)
ensure
[rd[1], wr[0], err[0]].each do |p|
p.close unless p.closed?
end
end
end

return pi
end

##
# The original popen3 that yields (or returns) rd, wr, err
#
def popen3(*cmd, &block)
if block_given? then
popen3_with_pid(*cmd) do |rd, wr, err, pid|
yield rd, wr, err
Process.waitpid(pid)
end
else
rd, wr, err, pid = popen3_with_pid(*cmd)
PROCESSES[pid] = true
if Process.waitpid(pid, Process::WNOHANG) == pid then
PROCESSES.delete(pid)
end
return rd, wr, err
end
end

module_function :popen3_with_pid
module_function :popen3
end


while true
Open3Z.popen3("/bin/ls -l /bin") { |stdin,stdout,stderr|
stdout.readlines.each { |line|
puts line
}
}
end
    (1-1/1)