| #include <utest/utest.h> |
| #include <errno.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <math.h> |
| #include <limits.h> |
| #include <signal.h> |
| #include <pthread.h> |
| #include <setjmp.h> |
| |
| TEST_SUITE("EFENCE"); |
| |
| /* <--- Begin definition of test cases ---> */ |
| |
| /* The guts of this test came from electric fence's tstheap: |
| * |
| * Electric Fence - Red-Zone memory allocator. |
| * Bruce Perens, 1988, 1993 |
| * |
| * For email below, drop spaces and <spam-buster> tag. |
| * MODIFIED: March 20, 2014 (jric<spam-buster> @ <spam-buster> chegg DOT com) |
| */ |
| |
| #define POOL_SIZE 1024 |
| #define LARGEST_BUFFER 30000 |
| #define TEST_DURATION 1000 |
| |
| static void *pool[POOL_SIZE]; |
| |
| bool test_alloc_and_free(void) |
| { |
| void **element; |
| size_t size; |
| |
| for (int count = 0; count < TEST_DURATION; count++) { |
| element = &pool[(int)(drand48() * POOL_SIZE)]; |
| size = (size_t)(drand48() * (LARGEST_BUFFER + 1)); |
| if (*element) { |
| free(*element); |
| *element = 0; |
| } else if (size > 0) { |
| *element = malloc(size); |
| *(uint8_t*)(*element) = 0xab; |
| *(uint8_t*)(*element + size - 1) = 0xcd; |
| } |
| } |
| /* Surviving without page faulting is success. */ |
| return TRUE; |
| } |
| |
| /* The pointer Needs to be volatile, so that blob = malloc() gets assigned |
| * before the fault. */ |
| static char *volatile blob; |
| static jmp_buf save; |
| static void *fault_addr; |
| |
| static void segv_action(int signr, siginfo_t *si, void *arg) |
| { |
| fault_addr = si->si_addr; |
| longjmp(save, 1); |
| } |
| |
| static struct sigaction sigact = {.sa_sigaction = segv_action, 0}; |
| |
| bool test_catching_fault(void) |
| { |
| pthread_yield();/* link in pth for intra-thread signals (SIGSEGV) */ |
| sigaction(SIGSEGV, &sigact, 0); |
| blob = malloc(PGSIZE); |
| if (!setjmp(save)) { |
| /* First time through, we'll try to pagefault. */ |
| blob[PGSIZE + 1] = 0; |
| UT_ASSERT_FMT("Tried to fault, but didn't!", FALSE); |
| } |
| /* Second time, we'll return via setjmp */ |
| UT_ASSERT_FMT("Fault addr was %p, should be %p", |
| fault_addr == blob + PGSIZE + 1, fault_addr, |
| blob + PGSIZE + 1); |
| return TRUE; |
| } |
| |
| /* <--- End definition of test cases ---> */ |
| |
| struct utest utests[] = { |
| UTEST_REG(alloc_and_free), |
| UTEST_REG(catching_fault), |
| }; |
| int num_utests = sizeof(utests) / sizeof(struct utest); |
| |
| int main(int argc, char *argv[]) |
| { |
| char **whitelist = &argv[1]; |
| int whitelist_len = argc - 1; |
| |
| RUN_TEST_SUITE(utests, num_utests, whitelist, whitelist_len); |
| } |