Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose the address of MJIT Pointers #7446

Merged
merged 1 commit into from Mar 5, 2023

Conversation

tenderlove
Copy link
Member

@tenderlove tenderlove commented Mar 4, 2023

This way we can manually dereference pointers with Fiddle.

Background: I'm trying to access the local table array on instruction sequence bodies. I guess we can't unwrap them because it's a ID * and the length of the array is unknown? I'm not sure that's just my guess. Anyway, this adds a reader to Pointer so we can manually de-reference the list.

Here's sample code to show how I'm using it (btw, hacks comes from here):

require "hacks" # to get RTypedData layout
require "fiddle"

module Fiddle
  def self.read_ptr ptr, offset
    Fiddle::Pointer.new(ptr)[offset, Fiddle::SIZEOF_VOIDP].unpack1("l!")
  end

  class CArray # :nodoc:
    def self.unpack ptr, len, type
      size = Fiddle::PackInfo::SIZE_MAP[type]
      bytesize = size * len
      ptr[0, bytesize].unpack("#{Fiddle::PackInfo::PACK_MAP[type]}#{len}")
    end
  end
end

C = RubyVM::MJIT.const_get(:C)

# Convert a Method object in to an rb_iseq_t from MJIT
def method_to_iseq_t method
  rb_iseq = RubyVM::InstructionSequence.of(method)
  addr = Fiddle.dlwrap(rb_iseq)
  offset = Hacks::STRUCTS["RTypedData"]["data"][0]
  addr = Fiddle.read_ptr addr, offset

  C.rb_iseq_t.new addr
end

class Foo
  def foo a, b
    a + b
  end
end

rb_iseq = method_to_iseq_t(Foo.instance_method(:foo))

# Accessing the local table doesn't work
begin
  rb_iseq.body.local_table
rescue NoMethodError
end

# I want the address of the pointer so I can dereference it myself
addr = Fiddle.read_ptr rb_iseq.body[:local_table].addr, 0

# Unpack the local table array
list = Fiddle::CArray.unpack(Fiddle::Pointer.new(addr),
                             rb_iseq.body.local_table_size,
                             Fiddle::TYPE_UINTPTR_T)

p list.map { Hacks.rb_id2sym _1 } # => [:a, :b]

I need the addr method so the above code can work. Thanks!

@tenderlove tenderlove requested a review from k0kubun March 4, 2023 21:59
@@ -219,7 +219,7 @@ def self.[]=(addr, value)
end

class Pointer
attr_reader :type
attr_reader :type, :addr
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about calling it to_i? I feel it'd be less likely to conflict with existing names used in C, and that's why I already use the name for the same functionality in class Immediate (which is a pointer of an immediate and thus has @addr).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also kind of useful that nil.to_i becomes 0.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes, I totally agree. It makes sense. I've updated the patch to use to_i.

This way we can manually dereference pointers with Fiddle
Copy link
Member

@k0kubun k0kubun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@k0kubun k0kubun merged commit fc5482d into ruby:master Mar 5, 2023
@tenderlove tenderlove deleted the expose-pointer-addr branch March 6, 2023 02:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
2 participants