From ca5f88eb7dc91dc9f0ecf3dcf19f74e74e44b4a0 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Thu, 14 Jan 2021 11:41:52 +0200 Subject: [PATCH] builtin: implement `-d debug_realloc` --- vlib/builtin/builtin.c.v | 91 +++++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 39 deletions(-) diff --git a/vlib/builtin/builtin.c.v b/vlib/builtin/builtin.c.v index 23b0efe06e..262ada3ac9 100644 --- a/vlib/builtin/builtin.c.v +++ b/vlib/builtin/builtin.c.v @@ -77,25 +77,27 @@ pub fn panic(s string) { // eprintln prints a message with a line end, to stderr. Both stderr and stdout are flushed. pub fn eprintln(s string) { - // eprintln is used in panics, so it should not fail at all - if s.str == 0 { - eprintln('eprintln(NIL)') - } C.fflush(C.stdout) C.fflush(C.stderr) - C.write(2, s.str, s.len) - C.write(2, c'\n', 1) + // eprintln is used in panics, so it should not fail at all + if s.str == 0 { + C.write(2, c'eprintln(NIL)\n', 14) + } else { + C.write(2, s.str, s.len) + C.write(2, c'\n', 1) + } C.fflush(C.stderr) } // eprint prints a message to stderr. Both stderr and stdout are flushed. pub fn eprint(s string) { - if s.str == 0 { - eprint('eprint(NIL)') - } C.fflush(C.stdout) C.fflush(C.stderr) - C.write(2, s.str, s.len) + if s.str == 0 { + C.write(2, c'eprint(NIL)\n', 12) + } else { + C.write(2, s.str, s.len) + } C.fflush(C.stderr) } @@ -143,36 +145,32 @@ pub fn println(s string) { [unsafe] pub fn malloc(n int) byteptr { if n <= 0 { - panic('malloc(<=0)') + panic('> V malloc(<=0)') } + $if vplayground ? { + if n > 10000 { + panic('allocating more than 10 KB is not allowed in the playground') + } + } + $if trace_malloc ? { + total_m += n + C.fprintf(C.stderr, c'v_malloc %d total %d\n', n, total_m) + // print_backtrace() + } + mut res := byteptr(0) $if prealloc { - // println('p') - res := g_m2_ptr + res = g_m2_ptr unsafe { g_m2_ptr += n } nr_mallocs++ - return res } $else { - ptr := unsafe {C.malloc(n)} - if ptr == 0 { + res = unsafe { C.malloc(n) } + if res == 0 { panic('malloc($n) failed') } - return ptr } - /* - TODO -#ifdef VPLAY - if n > 10000 { - panic('allocating more than 10 KB is not allowed in the playground') - } -#endif -#ifdef DEBUG_ALLOC - total_m += n - println('\n\n\nmalloc($n) total=$total_m') - print_backtrace() -#endif - */ + return res } /* @@ -180,23 +178,38 @@ pub fn malloc(n int) byteptr { fn malloc_size(b byteptr) int */ // v_realloc resizes the memory block `b` with `n` bytes. -// The `b byteptr` must be a pointer to an existing memory block previously allocated with `malloc`, `v_calloc` or `vcalloc`. +// The `b byteptr` must be a pointer to an existing memory block +// previously allocated with `malloc`, `v_calloc` or `vcalloc`. [unsafe] pub fn v_realloc(b byteptr, n int) byteptr { + mut new_ptr := byteptr(0) $if prealloc { unsafe { - new_ptr := malloc(n) - size := 0 // malloc_size(b) - C.memcpy(new_ptr, b, size) - return new_ptr + new_ptr = malloc(n) + C.memcpy(new_ptr, b, n) } } $else { - ptr := unsafe {C.realloc(b, n)} - if ptr == 0 { - panic('realloc($n) failed') + $if debug_realloc ? { + // NB: this is slower, but helps debugging memory problems. + // The main idea is to always force reallocating: + // 1) allocate a new memory block + // 2) copy the old to the new + // 3) fill the old with 0x57 (`W`) + // 4) free the old block + // => if there is still a pointer to the old block somewhere + // it will point to memory that is now filled with 0x57. + new_ptr = malloc(n) + C.memcpy(new_ptr, b, n) + C.memset(b, 0x57, n) + C.free(b) + } $else { + new_ptr = unsafe { C.realloc(b, n) } + if new_ptr == 0 { + panic('realloc($n) failed') + } } - return ptr } + return new_ptr } // v_calloc dynamically allocates a zeroed `n` bytes block of memory on the heap.