#include #include #include static int alloc_count, when_to_fail, err_count; static bool stealing; static void *failing_alloc(size_t len) { if (alloc_count++ == when_to_fail) return NULL; /* once we've failed once, it shouldn't ask again (steal can though). */ assert(stealing || alloc_count <= when_to_fail); return malloc(len); } static void *failing_realloc(void *p, size_t len) { if (alloc_count++ == when_to_fail) return NULL; return realloc(p, len); } static void nofail_on_error(const char *msg) { diag("ERROR: %s", msg); err_count++; } static void destroy_p(void *p) { } int main(void) { char *p, *c1, *c2; bool success; plan_tests(25); tal_set_backend(failing_alloc, failing_realloc, NULL, nofail_on_error); /* Fail at each possible point in an allocation. */ when_to_fail = err_count = 0; do { alloc_count = 0; p = tal(NULL, char); when_to_fail++; } while (!p); ok1(alloc_count >= 1); ok1(when_to_fail > 1); ok1(err_count == when_to_fail - 1); /* Do it again. */ when_to_fail = err_count = 0; do { alloc_count = 0; c1 = tal(p, char); when_to_fail++; } while (!c1); ok1(alloc_count >= 1); ok1(when_to_fail > 1); ok1(err_count == when_to_fail - 1); /* Now during resize. */ c2 = c1; when_to_fail = err_count = 0; for (;;) { alloc_count = 0; if (tal_resize(&c1, 100)) break; /* Failing alloc will not change pointer. */ ok1(c1 == c2); when_to_fail++; }; ok1(alloc_count == 1); ok1(when_to_fail == 1); ok1(err_count == 1); /* Make sure it's really resized. */ memset(c1, 1, 100); /* Now for second child. */ when_to_fail = err_count = 0; do { alloc_count = 0; c2 = tal(p, char); when_to_fail++; } while (!c2); ok1(alloc_count >= 1); ok1(when_to_fail > 1); /* Note: adding a child will fall through if group alloc fails. */ ok1 (err_count == when_to_fail - 1 || err_count == when_to_fail); /* Now while adding a destructor. */ when_to_fail = err_count = 0; do { alloc_count = 0; success = tal_add_destructor(p, destroy_p); when_to_fail++; } while (!success); ok1(alloc_count >= 1); ok1(when_to_fail > 1); ok1(err_count == when_to_fail - 1); /* Now while adding a name. */ when_to_fail = err_count = 0; do { const char name[] = "some name"; alloc_count = 0; success = tal_set_name(p, name); when_to_fail++; } while (!success); ok1(alloc_count >= 1); ok1(when_to_fail > 1); ok1(err_count == when_to_fail - 1); /* Now while stealing. */ stealing = true; when_to_fail = err_count = 0; do { alloc_count = 0; success = tal_steal(c2, c1) != NULL; when_to_fail++; } while (!success); ok1(alloc_count >= 1); ok1(when_to_fail > 1); ok1(err_count == when_to_fail - 1); /* Now stealing with more children (more coverage). */ when_to_fail = 1000; (void)tal(p, char); c1 = tal(p, char); c2 = tal(p, char); (void)tal(p, char); /* Now steal again. */ when_to_fail = err_count = 0; do { alloc_count = 0; success = tal_steal(c2, c1) != NULL; when_to_fail++; } while (!success); ok1(alloc_count >= 1); ok1(when_to_fail > 1); ok1(err_count == when_to_fail - 1); tal_free(p); tal_cleanup(); return exit_status(); }