class HeapInfo::Chunk

The object of a heap chunk

Attributes

base[R]

@return [Integer] Base address of this chunk

data[R]

@return [String] chunk data

prev_size[R]

@return [Integer] previous chunk size

size_t[R]

@return [Integer] 4 or 8 according to 32bit or 64bit, respectively.

Public Class Methods

new(size_t, base, dumper, head: false) click to toggle source

Instantiate a {HeapInfo::Chunk} object

@param [Integer] size_t 4 or 8 @param [Integer] base Start address of this chunk @param [Proc] dumper For dump more information of this chunk @param [Boolean] head

For specific if is fake chunk in +arena+.
If +head+ is +true+, will not load +size+ and +prev_size+ (since it's meaningless)

@example

HeapInfo::Chunk.new 8, 0x602000, ->(addr, len) { [0,0x21, 0xda4a].pack('Q*')[addr-0x602000, len] }
# create a chunk with chunk size 0x21
# File lib/heapinfo/chunk.rb, line 26
def initialize(size_t, base, dumper, head: false)
  raise ArgumentError, 'size_t can be either 4 or 8' unless [4, 8].include?(size_t)
  self.class.__send__(:define_method, :dump) { |*args| dumper.call(*args) }
  @size_t = size_t
  @base = base
  sz = dump(@base, size_t * 2)
  if head # no need to read size if is bin
    @data = dump(@base + size_t * 2, size_t * 4)
    return
  end
  @prev_size = Helper.unpack(size_t, sz[0, size_t])
  @size = Helper.unpack(size_t, sz[size_t..-1])
  r_size = [size - size_t * 2, size_t * 4].min # don't read too much data
  r_size = [r_size, 0].max # prevent negative size
  @data = dump(@base + size_t * 2, r_size)
end

Public Instance Methods

bintype() click to toggle source

Bin type of this chunk @return [Symbol] Bin type is simply determined according to #size @example

[c.size, c.size_t]
#=> [80, 8]
c.bintype
#=> :fast

@example

[c.size, c.size_t]
#=> [80, 4]
c.bintype
#=> :small

@example

c.size
#=> 135168
c.bintype
#=> :mmap
# File lib/heapinfo/chunk.rb, line 113
def bintype
  sz = size
  return :unknown if sz < @size_t * 4
  return :fast if sz <= @size_t * 16
  return :small if sz <= @size_t * 0x7e
  return :large if sz <= @size_t * 0x3ffe # is this correct?
  :mmap
end
flags() click to toggle source

The chunk flags record in low three bits of size @return [Array<Symbol>] flags of chunk @example

c = [0, 0x25].pack("Q*").to_chunk
c.flags
# [:non_main_arena, :prev_inuse]
# File lib/heapinfo/chunk.rb, line 60
def flags
  mask = @size - size
  flag = []
  flag << :non_main_arena unless (mask & 4).zero?
  flag << :mmapped unless (mask & 2).zero?
  flag << :prev_inuse unless (mask & 1).zero?
  flag
end
mmapped?() click to toggle source

Ask if chunk is mmapped.

@return [Boolean] +true|false+ if chunk is mmapped

# File lib/heapinfo/chunk.rb, line 79
def mmapped?
  flags.include? :mmapped
end
non_main_arena?() click to toggle source

Ask if chunk not belongs to main arena.

@return [Boolean] +true|false+ if chunk not belongs to main arena

# File lib/heapinfo/chunk.rb, line 72
def non_main_arena?
  flags.include? :non_main_arena
end
prev_inuse?() click to toggle source

Ask if chunk has set the prev-inuse bit.

@return [Boolean] +true|false+ if the prev_inuse bit has been set

# File lib/heapinfo/chunk.rb, line 86
def prev_inuse?
  flags.include? :prev_inuse
end
size() click to toggle source

Size of chunk @return [Integer] The chunk size without flag masks

# File lib/heapinfo/chunk.rb, line 92
def size
  @size & -8
end
to_s() click to toggle source

Hook #to_s for pretty printing @return [String]

# File lib/heapinfo/chunk.rb, line 45
def to_s
  ret = Helper.color(format("#<%s:%#x>\n", self.class.to_s, @base), sev: :klass)
  ret += "flags = [#{flags.map { |f| Helper.color(":#{f}", sev: :sym) }.join(',')}]\n"
  ret += "size = #{Helper.color(format('%#x', size))} (#{bintype})\n"
  ret += "prev_size = #{Helper.color(format('%#x', @prev_size))}\n" unless flags.include? :prev_inuse
  ret += "data = #{Helper.color(@data.inspect)}#{'...' if @data.length < size - size_t * 2}\n"
  ret
end