Commit 2e34efaa by Edward Thomson

buf::oom tests: use custom allocator for oom failures

Create a custom allocator for the `buf::oom` tests that will fail with
out-of-memory errors in predictable ways.  We were previously trying to
guess the way that various allocators on various platforms would fail
in a way such that `malloc`/`realloc` would return `NULL` (instead of
aborting the application, or appearing suspicious to various
instrumentation or static code analysis tools like valgrind.)

Introduce a fake `malloc` and `realloc` that will return `NULL` on
allocations requesting more than 100 bytes.  Otherwise, we proxy to the
default allocator.  (It's important to use the _default_ allocator, not
just call `malloc`, since the default allocator on Windows CI builds may
be the debugging C runtime allocators which would not be compatible with
a standard `malloc`.)
parent 305e801a
#include "clar_libgit2.h" #include "clar_libgit2.h"
#include "buffer.h" #include "buffer.h"
/* /* Override default allocators with ones that will fail predictably. */
* We want to use some ridiculous size that `malloc` will fail with
* but that does not otherwise interfere with testing. On Linux, choose static git_allocator std_alloc;
* a number that is large enough to fail immediately but small enough static git_allocator oom_alloc;
* that valgrind doesn't believe it to erroneously be a negative number.
* On macOS, choose a number that is large enough to fail immediately static void *oom_malloc(size_t n, const char *file, int line)
* without having libc print warnings to stderr. {
*/ /* Reject any allocation of more than 100 bytes */
#if defined(GIT_ARCH_64) && defined(__linux__) return (n > 100) ? NULL : std_alloc.gmalloc(n, file, line);
# define TOOBIG 0x0fffffffffffffff }
#elif defined(GIT_ARCH_64)
# define TOOBIG 0xffffffffffffff00 static void *oom_realloc(void *p, size_t n, const char *file, int line)
#endif {
/* Reject any allocation of more than 100 bytes */
/** return (n > 100) ? NULL : std_alloc.grealloc(p, n, file, line);
* If we make a ridiculously large request the first time we }
* actually allocate some space in the git_buf, the realloc()
* will fail. And because the git_buf_grow() wrapper always void test_buf_oom__initialize(void)
* sets mark_oom, the code in git_buf_try_grow() will free {
* the internal buffer and set it to git_buf__oom. git_stdalloc_init_allocator(&std_alloc);
* git_stdalloc_init_allocator(&oom_alloc);
* We initialized the internal buffer to (the static variable)
* git_buf__initbuf. The purpose of this test is to make sure oom_alloc.gmalloc = oom_malloc;
* that we don't try to free the static buffer. oom_alloc.grealloc = oom_realloc;
*
* Skip this test entirely on 32-bit platforms; a buffer large enough cl_git_pass(git_libgit2_opts(GIT_OPT_SET_ALLOCATOR, &oom_alloc));
* to guarantee malloc failures is so large that valgrind considers }
* it likely to be an error.
*/ void test_buf_oom__cleanup(void)
{
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_ALLOCATOR, NULL));
}
void test_buf_oom__grow(void) void test_buf_oom__grow(void)
{ {
#ifdef GIT_ARCH_64
git_buf buf = GIT_BUF_INIT; git_buf buf = GIT_BUF_INIT;
git_buf_clear(&buf); cl_git_pass(git_buf_grow(&buf, 42));
cl_assert(!git_buf_oom(&buf));
cl_assert(git_buf_grow(&buf, TOOBIG) == -1); cl_assert(git_buf_grow(&buf, 101) == -1);
cl_assert(git_buf_oom(&buf)); cl_assert(git_buf_oom(&buf));
git_buf_dispose(&buf); git_buf_dispose(&buf);
#else
cl_skip();
#endif
} }
void test_buf_oom__grow_by(void) void test_buf_oom__grow_by(void)
{ {
git_buf buf = GIT_BUF_INIT; git_buf buf = GIT_BUF_INIT;
buf.size = SIZE_MAX-10; cl_git_pass(git_buf_grow_by(&buf, 42));
cl_assert(!git_buf_oom(&buf));
cl_assert(git_buf_grow_by(&buf, 50) == -1); cl_assert(git_buf_grow_by(&buf, 101) == -1);
cl_assert(git_buf_oom(&buf)); cl_assert(git_buf_oom(&buf));
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment