项目作者: ralight

项目描述 :
Malloc failure testing
高级语言: C
项目地址: git://github.com/ralight/mallocfail.git
创建时间: 2018-06-08T21:19:56Z
项目社区:https://github.com/ralight/mallocfail

开源协议:MIT License

下载


Malloc Fail

This is a shared library that aims to help you test memory allocation failures
in a fairly deterministic manner. It was inspired by a stackoverflow answer:

https://stackoverflow.com/questions/1711170/unit-testing-for-failed-malloc

  1. I saw a cool solution to this problem which was presented to me by S.
  2. Paavolainen. The idea is to override the standard malloc(), which you can do
  3. just in the linker, by a custom allocator which
  4. 1. reads the current execution stack of the thread calling malloc()
  5. 2. checks if the stack exists in a database that is stored on hard disk
  6. 1. if the stack does not exist, adds the stack to the database and returns NULL
  7. 2. if the stack did exist already, allocates memory normally and returns
  8. Then you just run your unit test many times---this system automatically
  9. enumerates through different control paths to malloc() failure and is much more
  10. efficient and reliable than e.g. random testing.

mallocfail.so implements this behaviour for you. It overrides malloc,
calloc, and realloc with custom versions. Each time a custom allocator
runs, the function uses libbacktrace to generate a text representation of the
current call stack, and then generates a sha256 hash of that text. It then
checks to see if the new hash has already been seen. If it has never been seen
before, then the memory allocation fails and the hash is stored in memory and
written to disk. If the hash (i.e. the particular call stack) has been seen
before, then the normal libc version of the allocator is called as normal. Each
time the program starts, the hashes that have already been seen are loaded in
from disk.

The magic of the mallocfail library is that it does not require your program to
be modified, as long as debug symbols are available (i.e. no stripped
executables). You simply use the LD_PRELOAD linker environment variable to
tell the linker to use the malloc etc. implementations in mallocfail instead of
the libc versions.

Simple Usage

The easiest way to use mallocfail is with the provded mallocfail wrapper
script:

  1. mallocfail <your executable>

If you want more control, then to use mallocfail with your executable you need
to set the LD_PRELOAD environment variable.

  1. LD_PRELOAD=/usr/local/lib/mallocfail.so <your executable>

Note that the location of mallocfail.so may be different on your system,
substitute the path in that you have instead. If you have compiled yourself and
are still in the mallocfail directory, then use

  1. LD_PRELOAD=./mallocfail.so <your executable>

It is not recommended to set LD_PRELOAD by using export before running your
executable, because any subsequent command will be affected.

  1. export LD_PRELOAD=/usr/local/lib/mallocfail.so
  2. my_executable_test
  3. ssh myhost # this will certainly fail

Keep running your program until no more entries are being added to the hashes
file. It may take a lot of testing to achieve this.

You may find that your program crashes, or produces unexpected behaviour at
some point. If you want to repeat your test, remove the last line or last few
lines from the hashes file and repeat your program. It may be helpful to set
the MALLOCFAIL_DEBUG environment variable to give you more information on
what is happening.

  1. LD_PRELOAD=/usr/local/lib/mallocfail.so MALLOCFAIL_DEBUG=1 <your executable>

Using the debug option in this manner rather than setting it outright means you
are not bombarded with information on failures that are handled correctly. See
the Environment Variables section below for more information on
MALLOCFAIL_DEBUG.

Usage in GDB

Start gdb as normal:

  1. gdb <your executable>

or

  1. gdb --args <your executable> <your executable arguments>

Then configure LD_PRELOAD in the gdb command window:

  1. set environment LD_PRELOAD /usr/local/lib/mallocfail.so

Then run your program

  1. run

You can then run multiple times to test all outcomes, debug any crashes and so
on.

Environment Variables

You can control the behaviour of mallocfail with some environment variables.

MALLOCFAIL_FILE determines the file that hashes will be written to. Defaults
to mallocfail_hashes if not set.

MALLOCFAIL_DEBUG - set to 1 to enable debugging information. This has the
effect of printing to stdout the stack traces of any allocations that are
forced to fail. Enabling this option means the stack trace is generated twice
per failed memory allocation, which may have a small effect on performance -
worth noting if this is critical to you.

MALLOCFAIL_FAIL_COUNT - set to an integer > 0 to limit the number of failures
that can occur in a run. Setting to 1 will ensure that only a single failure
will happen per run.

Performance Impact

Allocated memory overhead associated with mallocfail is approximately a
constant 2kB on the stack plus 128 bytes on the heap per stored call stack on a
64-bit machine.

Limitations

The current implementation will probably fail badly on threaded programs.

Dependencies

Troy D. Hanson’s uthash (included in repository)
https://troydhanson.github.io/uthash/

Andrey Jivsov sha3 implementation (included in repository)
https://github.com/brainhub/SHA3IUF

Ian Taylor’s libbacktrace
https://github.com/ianlancetaylor/libbacktrace