memory stack allocation library
In C, it's often hard to track memory allocations and avoid memory leaks. To simplify this task, it may be useful to allocate memory via special object and, when appropriate, free all allocations by one call.
struct memstack
- an example of such special object, available via memstack/memstack.h
- memstack_init
- memstack_destroy
- memstack_push
- memstack_pop
- memstack_repush_last
- memstack_cleanup
- memstack_get_bottom
- memstack_reset
- memstack_get_last_mem
void memstack_init(struct memstack *st);
Parameters:
st
- memstack structure to initialize
Example:
struct memstack st;
memstack_init(&st);
It's also possible to initialize memstack statically:
struct memstack st = MEMSTACK_STATIC_INITIALIZER;
void memstack_destroy(struct memstack *st);
Parameters:
st
- memstack structure to destroy
All memory allocated by memstack is deallocated
memstack_memory_t *memstack_push(struct memstack *st, size_t size);
Parameters:
st
- memstack structuresize
- number of bytes to allocate, must be non-zero
Returns: pointer to abstract structure memstack_memory_t
or NULL
if allocation failed
Returned pointer will be suitably aligned for any structure, so may be casted to any poiner type
Note: memstack_push()
may not call system malloc()
if there is enough free space in last allocated internal memstack memory block
Example:
extern struct memstack *st;
struct my_struct *m = (struct my_struct*)memstack_push(st, sizeof(*m));
if (!m)
fail;
void memstack_pop(struct memstack *st, memstack_memory_t *mem);
Parameters:
st
- memstack structuremem
- pointer to abstract structurememstack_memory_t
- the same pointer that was returned by one of previousmemstack_push()
calls
It is possible to pop multiple sequential allocations by one call - just pop the first allocation of the sequence
Note: memstack_pop()
may not call system free()
for the last popped internal memstack memory block
Example:
extern struct memstack *st;
extern struct my_struct *m;
memstack_pop(st, (memstack_memory_t*)m);
memstack_memory_t *memstack_repush_last(struct memstack *st, memstack_memory_t *mem, size_t new_size);
Parameters:
st
- memstack structuremem
- pointer to abstract structurememstack_memory_t
that was returned by lastmemstack_push()
call orNULL
new_size
- new allocation size, in bytes, must be non-zero
If mem
is NULL
, then acts like memstack_push()
Returns: pointer to abstract structure memstack_memory_t
or NULL
if failed to expand existing allocation or create new allocation
Returned pointer will be suitably aligned for any structure, so may be casted to any poiner type
Example:
extern struct memstack *st;
extern void *m;
m = memstack_repush_last(st, (memstack_memory_t*)m, 100);
if (!m)
fail;
void memstack_cleanup(struct memstack *st);
Parameters:
st
- memstack structure
Note: memstack remembers maximum total size of allocations and will try to allocate one big memory block on first memstack_push()
call
memstack_bottom_t *memstack_get_bottom(struct memstack *st);
Parameters:
st
- memstack structure
Returns: pointer to abstract structure memstack_bottom_t
for passing it to memstack_reset()
Returned pointer must not be checked, it may have any value, even NULL
This function is used to remember memstack state before doing next allocations and then to reset memstack to saved state after these allocations
Note: saved state is associated with last memstack allocation that may be made before memstack_get_bottom()
call and is invalidated by memstack_pop()/memstack_repush_last()
called for that allocation
void memstack_reset(struct memstack *st, memstack_bottom_t *pos);
Parameters:
st
- memstack structurepos
- memstack state previously obtained viamemstack_get_bottom()
orNULL
All memory allocated in memstack after pos
was taken is popped
If pos
is NULL
, then acts like memstack_cleanup()
Example:
extern struct memstack *st;
memstack_bottom_t *pos = memstack_get_bottom(st);
memstack_memory_t *m1 = memstack_push(st, 100);
memstack_memory_t *m2 = memstack_push(st, 200);
...
memstack_reset(st, pos);
memstack_memory_t *memstack_get_last_mem(struct memstack *st, size_t size);
Parameters:
st
- memstack structuresize
- last allocation size, in bytes, must be non-zero
Returns: pointer to abstract structure memstack_memory_t
that was returned by last memstack_push()/memstack_repush_last()
call
Note: size
must be exactly the same one that was passed to last memstack_push()/memstack_repush_last()
call
Example:
extern struct memstack *st;
memstack_memory_t *m1 = memstack_push(st, 100);
...
memstack_memory_t *m2 = memstack_get_last_mem(st, 100);
assert(m1 == m2);
void memstack_check(struct memstack *st);
Parameters:
st
- memstack structure
Note: red zone size - build-time configurable via DMEMSTACK_TEST_BYTES_COUNT
macro
void memstack_print(struct memstack *st);
Parameters:
st
- memstack structure
Note: allocations are written to stderr
void memstack_enable_log(struct memstack *st, int enable);
Parameters:
st
- memstack structureenable
- non-zero to enable logging,0
- to disable
Note: allocations are written to stdout
-
Get clean-build build system:
-
For windows, get Gnu Make executable:
-
Build library
3.1 On Linux (example):
$ make MTOP=/home/user/clean-build OS=LINUX CPU=x86_64
3.2 On Windows (example):
C:\tools\gnumake-4.2.1.exe MTOP=C:\tools\clean-build OS=WINXX CPU=x86_64 WINVARIANT=WIN7 VS="C:\Program Files (x86)\Microsoft Visual Studio 14.0" WDK="C:\Program Files (x86)\Windows Kits\10" WDK_TARGET="10.0.14393.0"
Tips:
- specify
NO_STATIC=1
to not build static library archive - specify
NO_SHARED=1
to not build shared library (dll) - specify
TARGET=DEBUG
to build debugging versions of libraries - to view other possible values of
OS
,CPU
orTARGET
variables, define them as?
- specify
V=1
for verbose build, to print executed commands
If make target is not specified, default target
all
(compile the library) will be builtBy default, all variants of libraries are built:
- for static library -
MEMSTACK_LIB_VARIANTS="R P D S"
- for dynamic library -
MEMSTACK_DLL_VARIANTS="R S"
Notes:
- if some variant is unsupported under target platform, variant is filtered-out from list of variants
- if variants list is empty, default variant
R
is built
Variants of static library for LINUX:
R
- default, position-dependent code for linking executablesP
- position-independent code for linking executables (-fpie
compiler option)D
- position-independent code for linking shared objects (-fpic
compiler option)
Variants of static library for WINDOWS:
R
- default, dynamically linked multi-threaded C runtime library (/MD
compiler option)S
- statically linked multi-threaded C runtime library (/MT
compiler option)
Variants of dynamic library for LINUX:
R
- default, position-independent code (-fpic
compiler option)
Variants of dynamic library for WINDOWS:
R
- default, dynamically linked multi-threaded C runtime library (/MD
compiler option)S
- statically linked multi-threaded C runtime library (/MT
compiler option)
Tip: there are predefined targets:
tests
- to build library and testscheck
- to build library and tests, then run testsclean
- to delete built artifacts, except created directoriesdistclean
- to delete all artifacts, including created directories
- specify
-
Install library and interface headers
Note: make command should be the same as for building, except the target should be
install
oruninstall
4.1 On Linux (example):
possibly as root, do
$ make MTOP=/home/user/clean-build OS=LINUX CPU=x86_64 install
4.2 On Windows (example):
C:\tools\gnumake-4.2.1.exe MTOP=C:\tools\clean-build OS=WINXX CPU=x86_64 WINVARIANT=WIN7 VS="C:\Program Files (x86)\Microsoft Visual Studio 14.0" WDK="C:\Program Files (x86)\Windows Kits\10" WDK_TARGET="10.0.14393.0" PREFIX=C:\dst install
Note: Headers are installed in
$(INCLUDEDIR)
, libraries - in$(LIBDIR)
Tips:
- define variable
PREFIX
to override default install location -/usr/local
(for UNIX) orartifacts
(for WINDOWS) - define variable
INCLUDEDIR
to override default headers install location -$(PREFIX)/include
- define variable
LIBDIR
to override default libraries install location -$(PREFIX)/lib
- define variable
DESTDIR
to add prefix to$(PREFIX)
- to make path to temporary install location - specify
NO_INSTALL_HEADERS=1
to not install development library interface header files - specify
NO_INSTALL_LA=1
to not install development libtool library files (for UNIX) - specify
NO_INSTALL_PC=1
to not install development pkg-config library files (for UNIX) - specify
NO_INSTALL_IMPS=1
to not install development dll import libraries (for WINDOWS) - specify
NO_DEVEL=1
to not install all above development files (headers, .la, .pc, import libraries)
Tip: there is one more predefined target:
uninstall
- to delete installed files. Note: some installed directories may not be deleted.
- define variable