Skip to content

mbuilov/memstack

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

memstack

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

Contents

Api overview

  1. memstack_init
  2. memstack_destroy
  3. memstack_push
  4. memstack_pop
  5. memstack_repush_last
  6. memstack_cleanup
  7. memstack_get_bottom
  8. memstack_reset
  9. memstack_get_last_mem

Debug api

  1. memstack_check
  2. memstack_print
  3. memstack_enable_log

Initialize memstack structure

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;

Destroy memstack structure

void memstack_destroy(struct memstack *st);

Parameters:

  • st - memstack structure to destroy

All memory allocated by memstack is deallocated

Get memory from memstack

memstack_memory_t *memstack_push(struct memstack *st, size_t size);

Parameters:

  • st - memstack structure
  • size - 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;

Give memory back to memstack

void memstack_pop(struct memstack *st, memstack_memory_t *mem);

Parameters:

  • st - memstack structure
  • mem - pointer to abstract structure memstack_memory_t - the same pointer that was returned by one of previous memstack_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);

Reallocate last allocation

memstack_memory_t *memstack_repush_last(struct memstack *st, memstack_memory_t *mem, size_t new_size);

Parameters:

  • st - memstack structure
  • mem - pointer to abstract structure memstack_memory_t that was returned by last memstack_push() call or NULL
  • 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;

Pop all memory allocations

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

Get memstack bottom position

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

Reset memstack to saved state

void memstack_reset(struct memstack *st, memstack_bottom_t *pos);

Parameters:

  • st - memstack structure
  • pos - memstack state previously obtained via memstack_get_bottom() or NULL

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);

Get pointer to last pushed memory

memstack_memory_t *memstack_get_last_mem(struct memstack *st, size_t size);

Parameters:

  • st - memstack structure
  • size - 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);

Check red zones of memstack allocations

void memstack_check(struct memstack *st);

Parameters:

  • st - memstack structure

Note: red zone size - build-time configurable via DMEMSTACK_TEST_BYTES_COUNT macro

Print current memstack allocations

void memstack_print(struct memstack *st);

Parameters:

  • st - memstack structure

Note: allocations are written to stderr

Enable logging of memstack allocations

void memstack_enable_log(struct memstack *st, int enable);

Parameters:

  • st - memstack structure
  • enable - non-zero to enable logging, 0 - to disable

Note: allocations are written to stdout


Installing

  1. Get clean-build build system:

    git clone https://github.com/mbuilov/clean-build

  2. For windows, get Gnu Make executable:

    git clone https://github.com/mbuilov/gnumake-windows

  3. 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 or TARGET 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 built

    By 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 executables
    • P - 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 tests
    • check - to build library and tests, then run tests
    • clean - to delete built artifacts, except created directories
    • distclean - to delete all artifacts, including created directories
  4. Install library and interface headers

    Note: make command should be the same as for building, except the target should be install or uninstall

    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) or artifacts (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.