Project

General

Profile

Feature #22463 » patch_memchr.rb

watson1978 (Shizuo Fujita), 10/22/2026 04:24 AM

 
# Redirect memchr imported by the Ruby DLL to another implementation.
require 'fiddle'

module PatchMemchr
PAGE_READWRITE = 0x04

module_function

def read(addr, len) = Fiddle::Pointer.new(addr)[0, len]

def apply(new_addr, dll_name = 'x64-ucrt-ruby400.dll')
k32 = Fiddle.dlopen('kernel32.dll')
get_module = Fiddle::Function.new(k32['GetModuleHandleA'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOIDP)
protect = Fiddle::Function.new(k32['VirtualProtect'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_SIZE_T, Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
base = get_module.call(dll_name).to_i
raise "#{dll_name} not loaded" if base.zero?
nt = base + read(base + 0x3C, 4).unpack1('l<')
opt = nt + 24
raise 'not PE32+' unless read(opt, 2).unpack1('S<') == 0x20b
import_rva = read(opt + 112 + 8, 4).unpack1('L<')
desc = base + import_rva
patched = []
loop do
oft, _ts, _fc, name_rva, ft = read(desc, 20).unpack('L<5')
break if oft.zero? && name_rva.zero? && ft.zero?
i = 0
loop do
thunk = read(base + oft + i * 8, 8).unpack1('Q<')
break if thunk.zero?
if (thunk >> 63).zero? && Fiddle::Pointer.new(base + thunk + 2).to_s == 'memchr'
slot = base + ft + i * 8
old = Fiddle::Pointer.malloc(4, Fiddle::RUBY_FREE)
# VirtualProtect returns 0 on failure, and 0 is truthy in Ruby.
raise 'VirtualProtect failed' if protect.call(slot, 8, PAGE_READWRITE, old).zero?
Fiddle::Pointer.new(slot)[0, 8] = [new_addr].pack('Q<')
raise 'VirtualProtect failed to restore' if protect.call(slot, 8, old[0, 4].unpack1('L<'), old).zero?
raise 'import slot was not updated' unless read(slot, 8).unpack1('Q<') == new_addr
patched << Fiddle::Pointer.new(base + name_rva).to_s
end
i += 1
end
desc += 20
end
patched
end
end

variant = ENV['MEMCHR'] || 'ucrt'
unless variant == 'ucrt'
addr = case variant
when 'swar' then Fiddle.dlopen(File.join(__dir__, 'fastmemchr.dll'))['swar_memchr']
when 'sse2' then Fiddle.dlopen(File.join(__dir__, 'fastmemchr.dll'))['sse2_memchr']
else raise "unknown MEMCHR=#{variant}"
end
dlls = PatchMemchr.apply(addr)
raise 'memchr import was not found, nothing was patched' if dlls.empty?
warn "memchr -> #{variant} (patched import from #{dlls.join(', ')})"
end
s = ("a" * 1023 + "\n").b * 1000
raise 'index broken' unless s.index("\n") == 1023 && s.index("\n", 1024) == 2047 && s.each_line.count == 1000
(3-3/5)