pub fn malloclike_block(
addr: *const (),
size: usize,
redzone: usize,
is_zeroed: bool,
)
client_requests_defs
only.Expand description
Several Valgrind tools (Memcheck, Massif, Helgrind, DRD) rely on knowing when heap blocks are allocated in order to give accurate results.
Ignored if addr == 0.
The following description is taken almost untouched from the docs in the valgrind.h
header
file.
This happens automatically for the standard allocator functions such as malloc()
, calloc()
,
realloc()
, memalign()
, new
, new[]
, free()
, delete
, delete[]
, etc.
But if your program uses a custom allocator, this doesn’t automatically happen, and Valgrind
will not do as well. For example, if you allocate superblocks with mmap()
and then allocates
chunks of the superblocks, all Valgrind’s observations will be at the mmap()
level, and it
won’t know that the chunks should be considered separate entities. In Memcheck’s case, that
means you probably won’t get heap block overrun detection (because there won’t be redzones
marked as unaddressable) and you definitely won’t get any leak detection.
The following client requests allow a custom allocator to be annotated so that it can be handled accurately by Valgrind.
malloclike_block
marks a region of memory as having been allocated by a malloc()-like
function. For Memcheck (an illustrative case), this does two things:
- It records that the block has been allocated. This means any addresses within the block mentioned in error messages will be identified as belonging to the block. It also means that if the block isn’t freed it will be detected by the leak checker.
- It marks the block as being addressable and undefined (if
is_zeroed
is not set), or addressable and defined (ifis_zeroed
is set). This controls how accesses to the block by the program are handled.
addr
is the start of the usable block (ie. after any redzone), size
is its size. redzone
is the redzone size if the allocator can apply redzones – these are blocks of padding at the
start and end of each block. Adding redzones is recommended as it makes it much more likely
Valgrind will spot block overruns. is_zeroed
indicates if the memory is zeroed (or filled
with another predictable value), as is the case for calloc()
.
malloclike_block
should be put immediately after the point where a heap block – that will
be used by the client program – is allocated. It’s best to put it at the outermost level of the
allocator if possible; for example, if you have a function my_alloc()
which calls
internal_alloc()
, and the client request is put inside internal_alloc()
, stack traces
relating to the heap block will contain entries for both my_alloc()
and internal_alloc()
,
which is probably not what you want.
For Memcheck users: if you use malloclike_block
to carve out custom blocks from within a
heap block, B, that has been allocated with malloc/calloc/new/etc, then block B will be
ignored during leak-checking – the custom blocks will take precedence.
In many cases, these three client requests (malloclike_block
, resizeinplace_block
,
freelike_block
) will not be enough to get your allocator working well with Memcheck. More
specifically, if your allocator writes to freed blocks in any way then a
super::memcheck::make_mem_undefined
call will be necessary to mark the memory as addressable
just before the zeroing occurs, otherwise you’ll get a lot of invalid write errors. For
example, you’ll need to do this if your allocator recycles freed blocks, but it zeroes them
before handing them back out (via malloclike_block
). Alternatively, if your allocator reuses
freed blocks for allocator-internal data structures, super::memcheck::make_mem_undefined
calls will also be necessary.
Really, what’s happening is a blurring of the lines between the client program and the
allocator… after freelike_block
is called, the memory should be considered unaddressable
to the client program, but the allocator knows more than the rest of the client program and so
may be able to safely access it. Extra client requests are necessary for Valgrind to understand
the distinction between the allocator and the rest of the program.
See also Memory Pools: describing and working with custom allocators and Memcheck: Client requests