module HeapInfo::Glibc
Define errors.
Implement free-related functions.
To define heap-related functions in glibc.
Define some useful functions here.
Attributes
Public Instance Methods
Implmentation of +void __libc_free(void *mem)+.
Reference: {github.com/david942j/heapinfo/blob/master/examples/libcdb/libc-2.23/malloc.c#L2934 glibc-2.23} and {code.woboq.org/userspace/glibc/malloc/malloc.c.html#__libc_free Online Source} @param [Integer] mem Memory address to be free.
# File lib/heapinfo/glibc/free.rb, line 10 def libc_free(mem) # TODO: free_hook mem = ulong mem return if mem.zero? # free(0) has no effect ptr = mem2chunk(mem) return munmap_chunk(ptr) if chunk_is_mmapped(ptr) av = arena_for_chunk(ptr) int_free(av, ptr) end
# File lib/heapinfo/glibc/error.rb, line 8 def malloc_assert(condition) raise MallocError, yield unless condition end
Private Instance Methods
Not the real implmentation, maybe wrong some day? @return [Boolean]
# File lib/heapinfo/glibc/helper.rb, line 30 def aligned_ok(size) (size & (2 * size_t - 1)).zero? end
@return [HeapInfo::Arena]
# File lib/heapinfo/glibc/helper.rb, line 40 def arena_for_chunk(ptr) # not support arena other than initial main_arena return if dumper.call(ptr, size_t * 2).to_chunk.non_main_arena? main_arena end
@return [Boolean]
# File lib/heapinfo/glibc/helper.rb, line 11 def chunk_is_mmapped(ptr) # TODO: handle memory not accessible dumper.call(ptr, size_t * 2).to_chunk.mmapped? end
@return [Integer]
# File lib/heapinfo/glibc/helper.rb, line 47 def fastbin_index(size) (size >> (size_t == 8 ? 4 : 3)) - 2 end
Implmentation of void _int_free (mstate av, mchunkptr p, [int have_lock])
.
The original method in C is too long, split to multiple methods to match ruby convention. @param [HeapInfo::Arena] av @param [Integer] ptr Use ptr
instead of p
to prevent confusing with ruby native method.
# File lib/heapinfo/glibc/free.rb, line 28 def int_free(av, ptr) chunk = dumper.call(ptr, size_t * 2).to_chunk size = ulong chunk.size invalid_pointer(ptr, size) invalid_size(size) # check_inuse_chunk # off if size <= get_max_fast int_free_fast(av, ptr, size) elsif !chunk_is_mmapped(ptr) # Though this has been checked in #libc_free int_free_small(av, ptr, size) # else # never reached block, redundant code in glibc. # munmap_chunk(ptr) end end
# File lib/heapinfo/glibc/free.rb, line 43 def int_free_fast(av, ptr, size) invalid_next_size(:fast, av, ptr, size) idx = fastbin_index(size) old = av.fastbin[idx].fd malloc_assert(old != ptr) do format("double free or corruption (fasttop)\ntop of fastbin[0x%x]: 0x%x=0x%x", size & -8, ptr, ptr) end true end
# File lib/heapinfo/glibc/free.rb, line 53 def int_free_small(av, ptr, size) # rubocop:disable UnusedMethodArgument # TODO: unfinished true end
# File lib/heapinfo/glibc/free.rb, line 80 def invalid_next_size(type, av, ptr, size) errmsg = "free(): invalid next size (#{type})\n" nxt_chk = dumper.call(ptr + size, size_t * 2).to_chunk(base: ptr + size) malloc_assert(nxt_chk.size > 2 * size_t) do errmsg + format("next chunk(0x%x) has size(#{nxt_chk.size}) <= 2 * #{size_t}", nxt_chk.base) end malloc_assert(nxt_chk.size < av.system_mem) do errmsg + format('next chunk(0x%x) has size(0x%x) >= av.system_mem(0x%x)', nxt_chk.base, nxt_chk.size, av.system_mem) end end
Start of checkers
# File lib/heapinfo/glibc/free.rb, line 65 def invalid_pointer(ptr, size) errmsg = "free(): invalid pointer\n" # unsigned compare malloc_assert(ptr <= ulong(-size)) { errmsg + format('ptr(0x%x) > -size(0x%x)', ptr, ulong(-size)) } malloc_assert((ptr % (size_t * 2)).zero?) { errmsg + format('ptr(0x%x) %% %d != 0', ptr, size_t * 2) } end
# File lib/heapinfo/glibc/free.rb, line 72 def invalid_size(size) errmsg = "free(): invalid size\n" malloc_assert(size >= min_chunk_size) do errmsg + format('size(0x%x) < min_chunk_size(0x%x)', size, min_chunk_size) end malloc_assert(aligned_ok(size)) { errmsg + format('alignment error: size(0x%x) %% 0x%x != 0', size, size_t * 2) } end
# File lib/heapinfo/glibc/helper.rb, line 16 def max_fast size_t * 16 end
# File lib/heapinfo/glibc/helper.rb, line 6 def mem2chunk(mem) ulong(mem - 2 * size_t) end
The minimal chunk size. Not the real implmentation, maybe wrong some day? @return [Integer] The size.
# File lib/heapinfo/glibc/helper.rb, line 24 def min_chunk_size size_t * 4 end
# File lib/heapinfo/glibc/free.rb, line 58 def munmap_chunk(ptr) # rubocop:disable UnusedMethodArgument # TODO: check page alignment and... page exists? true end
@return [Integer]
# File lib/heapinfo/glibc/helper.rb, line 35 def ulong(n) n % 2**(size_t * 8) end