Class: HeapInfo::Chunk

Inherits:
Object
  • Object
show all
Defined in:
lib/heapinfo/chunk.rb

Overview

The object of a heap chunk

Direct Known Subclasses

Fastbin

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(size_t, base, dumper, head: false) ⇒ Chunk

Instantiate a HeapInfo::Chunk object

Examples:

HeapInfo::Chunk.new 8, 0x602000, ->(addr, len) { [0,0x21, 0xda4a].pack('Q*')[addr-0x602000, len] }
# create a chunk with chunk size 0x21

Parameters:

  • size_t (Integer)

    4 or 8

  • base (Integer)

    Start address of this chunk

  • dumper (Proc)

    For dump more information of this chunk

  • head (Boolean)

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

Raises:

  • (ArgumentError)

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/heapinfo/chunk.rb', line 24

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

Instance Attribute Details

#baseInteger (readonly)

Returns Base address of this chunk

Returns:

  • (Integer)

    Base address of this chunk


11
12
13
# File 'lib/heapinfo/chunk.rb', line 11

def base
  @base
end

#dataString (readonly)

Returns chunk data

Returns:

  • (String)

    chunk data


9
10
11
# File 'lib/heapinfo/chunk.rb', line 9

def data
  @data
end

#prev_sizeInteger (readonly)

Returns previous chunk size

Returns:

  • (Integer)

    previous chunk size


7
8
9
# File 'lib/heapinfo/chunk.rb', line 7

def prev_size
  @prev_size
end

#size_tInteger (readonly)

Returns 4 or 8 according to 32bit or 64bit, respectively.

Returns:

  • (Integer)

    4 or 8 according to 32bit or 64bit, respectively.


5
6
7
# File 'lib/heapinfo/chunk.rb', line 5

def size_t
  @size_t
end

Instance Method Details

#bintypeSymbol

Bin type of this chunk

Examples:

[c.size, c.size_t]
#=> [80, 8]
c.bintype
#=> :fast
[c.size, c.size_t]
#=> [80, 4]
c.bintype
#=> :small
c.size
#=> 135168
c.bintype
#=> :mmap

Returns:

  • (Symbol)

    Bin type is simply determined according to #size


111
112
113
114
115
116
117
118
# File 'lib/heapinfo/chunk.rb', line 111

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

#flagsArray<Symbol>

The chunk flags record in low three bits of size

Examples:

c = [0, 0x25].pack("Q*").to_chunk
c.flags
# [:non_main_arena, :prev_inuse]

Returns:

  • (Array<Symbol>)

    flags of chunk


58
59
60
61
62
63
64
65
# File 'lib/heapinfo/chunk.rb', line 58

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?Boolean

Ask if chunk is mmapped.

Returns:

  • (Boolean)

    true|false if chunk is mmapped


77
78
79
# File 'lib/heapinfo/chunk.rb', line 77

def mmapped?
  flags.include? :mmapped
end

#non_main_arena?Boolean

Ask if chunk not belongs to main arena.

Returns:

  • (Boolean)

    true|false if chunk not belongs to main arena


70
71
72
# File 'lib/heapinfo/chunk.rb', line 70

def non_main_arena?
  flags.include? :non_main_arena
end

#prev_inuse?Boolean

Ask if chunk has set the prev-inuse bit.

Returns:

  • (Boolean)

    true|false if the prev_inuse bit has been set


84
85
86
# File 'lib/heapinfo/chunk.rb', line 84

def prev_inuse?
  flags.include? :prev_inuse
end

#sizeInteger

Size of chunk

Returns:

  • (Integer)

    The chunk size without flag masks


90
91
92
# File 'lib/heapinfo/chunk.rb', line 90

def size
  @size & -8
end

#to_sString

Hook #to_s for pretty printing

Returns:

  • (String)

43
44
45
46
47
48
49
50
# File 'lib/heapinfo/chunk.rb', line 43

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