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


Reply via email to