Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Last active March 24, 2018 18:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save JoshCheek/e1d504794240b359ab58539ad2148b82 to your computer and use it in GitHub Desktop.
Save JoshCheek/e1d504794240b359ab58539ad2148b82 to your computer and use it in GitHub Desktop.
Example of the kinds of issues you can hit when you directly mess with memory
require 'fiddle'
public def class=(new_class)
obj_ptr = Fiddle::Pointer.new 2*self.object_id
klass_ptr = Fiddle::Pointer.new 2*new_class.object_id
obj_ptr[8, 8] = klass_ptr.ref[0, 8]
end
class A
attr_accessor :a, :b, :c
end
class B
attr_accessor :a, :b, :c
end
# The optimization is to store them inside the object instead of allocating the ivar hash
# which ivar corresponds to which location is based on the order they are set in.
# Since we set B's ivars in a different order, their values get swapped.
a = A.new
a.a = 'a'
a.b = 'b'
a.c = 'c'
b = B.new
b.c = 'c'
b.a = 'a'
b.b = 'b'
a # => #<A:0x00007fc62797e2b8 @a="a", @b="b", @c="c">
a.class = B
a # => #<B:0x00007fc62797e2b8 @c="a", @a="b", @b="c">
require 'fiddle'
public def class=(new_class)
obj_ptr = Fiddle::Pointer.new 2*self.object_id
klass_ptr = Fiddle::Pointer.new 2*new_class.object_id
obj_ptr[8, 8] = klass_ptr.ref[0, 8]
end
class A
attr_accessor :a, :b, :c, :d
end
# Instance vars get lost when there are 3 or fewer, due to an optimization
a = A.new
a.a = a.b = a.c = :whatever
a # => #<A:0x00007fd3d68d6880 @c=:whatever, @b=:whatever, @a=:whatever>
a.class = Object
a # => #<Object:0x00007fd3d68d6880>
# Add a fourth ivar and Ruby stores them in the hash table of instance variables
a = A.new
a.a = a.b = a.c = a.d = :whatever
a # => #<A:0x00007fd3d68d62b8 @c=:whatever, @b=:whatever, @a=:whatever, @d=:whatever>
a.class = Object
a # => #<Object:0x00007fd3d68d62b8 @c=:whatever, @b=:whatever, @a=:whatever, @d=:whatever>
require 'fiddle'
public def class=(new_class)
obj_ptr = Fiddle::Pointer.new 2*self.object_id
klass_ptr = Fiddle::Pointer.new 2*new_class.object_id
obj_ptr[8, 8] = klass_ptr.ref[0, 8]
end
# here, we set the class to a non-class value. When we call a method on it, it
# tries to treat "false" as if it was a class, but it isn't. This causes invalid
# memory access, which causes a segmentation fault
o = Object.new
o.class = false
o.inspect
# !> program.rb:13: [BUG] Segmentation fault at 0x0000000000000018
# !> ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin17]
# !>
# !> -- Crash Report log information --------------------------------------------
# !> See Crash Report log file under the one of following:
# !> * ~/Library/Logs/DiagnosticReports
# !> * /Library/Logs/DiagnosticReports
# !> for more details.
# !> Don't forget to include the above Crash Report log file in bug reports.
# !>
# !> -- Control frame information -----------------------------------------------
# !> c:0002 p:0046 s:0008 E:000f28 EVAL program.rb:13 [FINISH]
# !> c:0001 p:0000 s:0003 E:000470 (none) [FINISH]
# !>
# !> -- Ruby level backtrace information ----------------------------------------
# !> program.rb:13:in `<main>'
# !>
# !> -- Machine register context ------------------------------------------------
# !> rax: 0x0000000000000000 rbx: 0x0000000000000000 rcx: 0x00000000000002a1
# !> rdx: 0x00007ffeef173bc0 rdi: 0x0000000000000000 rsi: 0x0000000000000000
# !> rbp: 0x00007ffeef173bb0 rsp: 0x00007ffeef173b70 r8: 0x00007fa4140f4600
# !> r9: 0x000000010112b0a0 r10: 0x00007fa4150571f0 r11: 0x00000000000000c0
# !> r12: 0x0000000000000000 r13: 0x0000000000000aa1 r14: 0x0000000000000aa1
# !> r15: 0x0000000000000aa1 rip: 0x0000000100c5d335 rfl: 0x0000000000010202
# !>
# !> -- C level backtrace information -------------------------------------------
# !> 0 ruby 0x0000000100c77db7 rb_vm_bugreport + 135
# !> 1 ruby 0x0000000100afced8 rb_bug_context + 472
# !> 2 ruby 0x0000000100bec3e1 sigsegv + 81
# !> 3 libsystem_platform.dylib 0x00007fff73f70f5a _sigtramp + 26
# !> 4 ruby 0x0000000100c5d335 method_entry_get + 261
# !> 5 ruby 0x0000000100c5d3cb rb_callable_method_entry + 27
# !> 6 ruby 0x0000000100c549bb vm_exec_core + 12123
# !> 7 ruby 0x0000000100c65b6e vm_exec + 142
# !> 8 ruby 0x0000000100b069b1 ruby_exec_internal + 177
# !> 9 ruby 0x0000000100b068a8 ruby_run_node + 56
# !> 10 ruby 0x0000000100a8c0ff main + 79
# !>
# !> -- Other runtime information -----------------------------------------------
# !>
# !> * Loaded script: program.rb
# !>
# !> * Loaded features:
# !>
# !> 0 enumerator.so
# !> 1 thread.rb
# !> 2 rational.so
# !> 3 complex.so
# !> 4 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/x86_64-darwin17/enc/encdb.bundle
# !> 5 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/x86_64-darwin17/enc/trans/transdb.bundle
# !> 6 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/x86_64-darwin17/rbconfig.rb
# !> 7 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/compatibility.rb
# !> 8 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/defaults.rb
# !> 9 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/deprecate.rb
# !> 10 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/errors.rb
# !> 11 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/version.rb
# !> 12 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/requirement.rb
# !> 13 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/platform.rb
# !> 14 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/basic_specification.rb
# !> 15 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/stub_specification.rb
# !> 16 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/util/list.rb
# !> 17 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/x86_64-darwin17/stringio.bundle
# !> 18 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/specification.rb
# !> 19 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/exceptions.rb
# !> 20 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/dependency.rb
# !> 21 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/core_ext/kernel_gem.rb
# !> 22 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/monitor.rb
# !> 23 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb
# !> 24 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems.rb
# !> 25 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/rubygems/path_support.rb
# !> 26 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/version.rb
# !> 27 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/core_ext/name_error.rb
# !> 28 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/levenshtein.rb
# !> 29 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/jaro_winkler.rb
# !> 30 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/spell_checker.rb
# !> 31 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/delegate.rb
# !> 32 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/spell_checkers/name_error_checkers/class_name_checker.rb
# !> 33 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb
# !> 34 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/spell_checkers/name_error_checkers.rb
# !> 35 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/spell_checkers/method_name_checker.rb
# !> 36 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/spell_checkers/key_error_checker.rb
# !> 37 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/spell_checkers/null_checker.rb
# !> 38 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/formatters/plain_formatter.rb
# !> 39 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean.rb
# !> 40 /Users/xjxc322/.gem/ruby/2.5.0/gems/seeing_is_believing-3.4.0/lib/seeing_is_believing/safe.rb
# !> 41 /Users/xjxc322/.gem/ruby/2.5.0/gems/seeing_is_believing-3.4.0/lib/seeing_is_believing/version.rb
# !> 42 /Users/xjxc322/.gem/ruby/2.5.0/gems/seeing_is_believing-3.4.0/lib/seeing_is_believing/hash_struct.rb
# !> 43 /Users/xjxc322/.gem/ruby/2.5.0/gems/seeing_is_believing-3.4.0/lib/seeing_is_believing/event_stream/events.rb
# !> 44 /Users/xjxc322/.gem/ruby/2.5.0/gems/seeing_is_believing-3.4.0/lib/seeing_is_believing/event_stream/producer.rb
# !> 45 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/x86_64-darwin17/socket.bundle
# !> 46 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/x86_64-darwin17/io/wait.bundle
# !> 47 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/socket.rb
# !> 48 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/timeout.rb
# !> 49 /Users/xjxc322/.gem/ruby/2.5.0/gems/seeing_is_believing-3.4.0/lib/seeing_is_believing/the_matrix.rb
# !> 50 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/prettyprint.rb
# !> 51 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/pp.rb
# !> 52 /Users/xjxc322/.gem/ruby/2.5.0/gems/seeing_is_believing-3.4.0/lib/seeing_is_believing/customize_pp.rb
# !> 53 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/x86_64-darwin17/fiddle.bundle
# !> 54 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/fiddle/function.rb
# !> 55 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/fiddle/closure.rb
# !> 56 /Users/xjxc322/.rubies/ruby-2.5.0/lib/ruby/2.5.0/fiddle.rb
# !>
# !> [NOTE]
# !> You may have encountered a bug in the Ruby interpreter or extension libraries.
# !> Bug reports are welcome.
# !> For details: http://www.ruby-lang.org/bugreport.html
# !>
# !> [IMPORTANT]
# !> Don't forget to include the Crash Report log file under
# !> DiagnosticReports directory in bug reports.
# !>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment