JRuby FFI bug with getZeroTerminatedByteArray
---------------------------------------------
Key: JRUBY-5067
URL: http://jira.codehaus.org/browse/JRUBY-5067
Project: JRuby
Issue Type: Bug
Affects Versions: JRuby 1.5.2
Environment: JRuby 1.5.2 and 1.6.0 dev, Ubuntu 10, OpenJDK, java
version "1.6.0_18"
Reporter: Daniel Berger
Assignee: Thomas E Enebo
Attachments: hs_err_pid18886.log
See the code below. Calling Net::Proto.getprotoent causes a SIGSEGV. The full
trace is attached separately.
Here's the code:
{noformat}
require 'ffi'
# The Net module serves as a namespace only.
module Net
# The Proto class serves as the base class for the various protocol methods.
class Proto
extend FFI::Library
unless RUBY_PLATFORM == 'java' && JRUBY_VERSION.to_f < 1.5
ffi_lib(FFI::Library::LIBC)
end
# The version of the net-proto library
VERSION = '1.1.0'
private_class_method :new
private
class ProtocolStruct < FFI::Struct
layout(
:p_name, :string,
:p_aliases, :pointer,
:p_proto, :int
)
end
class FFI::Pointer
def read_array_of_string
elements = []
psz = RUBY_PLATFORM == 'java' ? 4 : self.class.size
loc = self
until ((element = loc.read_pointer).null?)
elements << element.read_string
loc += psz
end
elements
end
end
ProtoStruct = Struct.new('ProtoStruct', :name, :aliases, :proto)
attach_function 'setprotoent', [:int], :void
attach_function 'endprotoent', [], :void
attach_function 'getprotobyname_r', [:string, :pointer, :pointer, :long,
:pointer], :int
attach_function 'getprotobynumber_r', [:int, :pointer, :pointer, :long,
:pointer], :int
attach_function 'getprotoent_r', [:pointer, :string, :long, :pointer], :int
public
# If given a protocol string, returns the corresponding number. If
# given a protocol number, returns the corresponding string.
#
# Returns nil if not found in either case.
#
# Examples:
#
# Net::Proto.get_protocol('tcp') # => 6
# Net::Proto.get_protocol(1) # => 'icmp'
#
def self.get_protocol(argument)
if argument.is_a?(String)
getprotobyname(argument)
else
getprotobynumber(argument)
end
end
# Given a protocol string, returns the corresponding number, or nil if
# not found.
#
# Examples:
#
# Net::Proto.getprotobyname('tcp') # => 6
# Net::Proto.getprotobyname('bogus') # => nil
#
def self.getprotobyname(protocol)
raise TypeError unless protocol.is_a?(String)
pptr = FFI::MemoryPointer.new(ProtocolStruct.size)
qptr = FFI::MemoryPointer.new(ProtocolStruct.size)
buf = FFI::MemoryPointer.new(:char, 1024)
begin
setprotoent(0)
int = getprotobyname_r(protocol, pptr, buf, buf.size, qptr)
ensure
endprotoent()
end
int > 0 || qptr.get_pointer(0).null? ? nil :
ProtocolStruct.new(pptr)[:p_proto]
end
# Given a protocol number, returns the corresponding string, or nil if
# not found.
#
# Examples:
#
# Net::Proto.getprotobynumber(6) # => 'tcp'
# Net::Proto.getprotobynumber(999) # => nil
#
def self.getprotobynumber(protocol)
raise TypeError unless protocol.is_a?(Integer)
pptr = FFI::MemoryPointer.new(ProtocolStruct.size)
qptr = FFI::MemoryPointer.new(ProtocolStruct.size)
buf = FFI::MemoryPointer.new(:char, 1024)
begin
setprotoent(0)
int = getprotobynumber_r(protocol, pptr, buf, buf.size, qptr)
ensure
endprotoent()
end
int > 0 || qptr.get_pointer(0).null? ? nil :
ProtocolStruct.new(pptr)[:p_name]
end
# In block form, yields each entry from /etc/protocols as a struct of type
# Proto::ProtoStruct. In non-block form, returns an array of structs.
#
# The fields are 'name' (a string), 'aliases' (an array of strings,
# though often only one element), and 'proto' (a number).
#
# Example:
#
# Net::Proto.getprotoent.each{ |prot|
# p prot.name
# p prot.aliases
# p prot.proto
# }
#
def self.getprotoent
structs = block_given? ? nil : []
pptr = FFI::MemoryPointer.new(ProtocolStruct.size)
qptr = FFI::MemoryPointer.new(ProtocolStruct.size)
buf = 1.chr * 1024
begin
setprotoent(0)
while int = getprotoent_r(pptr, buf, buf.size, qptr)
break if int > 0 || qptr.null?
buf = 1.chr * 1024
ffi_struct = ProtocolStruct.new(pptr)
ruby_struct = ProtoStruct.new(
ffi_struct[:p_name],
ffi_struct[:p_aliases].read_array_of_string,
ffi_struct[:p_proto]
).freeze
if block_given?
yield ruby_struct
else
structs << ruby_struct
end
end
ensure
endprotoent
end
structs
end
end
end
{noformat}
And here's the result of calling Net::Proto.getprotoent:
{noformat}
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00a7c785, pid=19078, tid=3078278000
#
# JRE version: 6.0_18-b18
# Java VM: OpenJDK Client VM (16.0-b13 mixed mode, sharing linux-x86 )
# Derivative: IcedTea6 1.8.1
# Distribution: Ubuntu 10.04 LTS, package 6b18-1.8.1-0ubuntu1
# Problematic frame:
# C [libc.so.6+0x73785]
#
# An error report file with more information is saved as:
# /home/dberger/Repositories/net-proto/lib/linux/net/hs_err_pid19078.log
#
# If you would like to submit a bug report, please include
# instructions how to reproduce the bug and visit:
# https://bugs.launchpad.net/ubuntu/+source/openjdk-6/
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
Aborted
{noformat}
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://jira.codehaus.org/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
---------------------------------------------------------------------
To unsubscribe from this list, please visit:
http://xircles.codehaus.org/manage_email