| #include "efence.h" |
| #include <setjmp.h> |
| #include <signal.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| |
| /* |
| * Electric Fence confidence tests. |
| * Make sure all of the various functions of Electric Fence work correctly. |
| */ |
| |
| #ifndef PAGE_PROTECTION_VIOLATED_SIGNAL |
| #define PAGE_PROTECTION_VIOLATED_SIGNAL SIGSEGV |
| #endif |
| |
| struct diagnostic { |
| int (*test)(void); |
| int expectedStatus; |
| const char *explanation; |
| }; |
| |
| extern int EF_PROTECT_BELOW; |
| extern int EF_ALIGNMENT; |
| |
| static sigjmp_buf env; |
| |
| /* |
| * There is still too little standardization of the arguments and return |
| * type of signal handler functions. |
| */ |
| static void segmentationFaultHandler(int signalNumber |
| #if (defined(_AIX)) |
| , |
| ... |
| #endif |
| ) |
| { |
| signal(PAGE_PROTECTION_VIOLATED_SIGNAL, SIG_DFL); |
| siglongjmp(env, 1); |
| } |
| |
| static int gotSegmentationFault(int (*test)(void)) |
| { |
| if (sigsetjmp(env, 1) == 0) { |
| int status; |
| |
| signal(PAGE_PROTECTION_VIOLATED_SIGNAL, |
| segmentationFaultHandler); status = (*test)(); |
| signal(PAGE_PROTECTION_VIOLATED_SIGNAL, SIG_DFL); |
| return status; |
| } else |
| return 1; |
| } |
| |
| static char *allocation; |
| /* c is global so that assignments to it won't be optimized out. */ |
| char c; |
| |
| static int testSizes(void) |
| { |
| /* |
| * If ef_number can't hold all of the bits of a void *, have the user |
| * add -DUSE_ LONG_LONG to the compiler flags so that ef_number will be |
| * declared as "unsigned long long" instead of "unsigned long". |
| */ |
| return (sizeof(ef_number) < sizeof(void *)); |
| } |
| |
| static int allocateMemory(void) |
| { |
| allocation = (char *)malloc(1); |
| |
| if (allocation != 0) |
| return 0; |
| else |
| return 1; |
| } |
| |
| static int freeMemory(void) |
| { |
| free(allocation); |
| return 0; |
| } |
| |
| static int protectBelow(void) |
| { |
| EF_PROTECT_BELOW = 1; |
| return 0; |
| } |
| |
| static int read0(void) |
| { |
| c = *allocation; |
| |
| return 0; |
| } |
| |
| static int write0(void) |
| { |
| *allocation = 1; |
| |
| return 0; |
| } |
| |
| static int read1(void) |
| { |
| c = allocation[1]; |
| |
| return 0; |
| } |
| |
| static int readMinus1(void) |
| { |
| c = allocation[-1]; |
| return 0; |
| } |
| |
| static struct diagnostic diagnostics[] = { |
| {testSizes, 0, |
| "Please add -DLONG_LONG to the compiler flags and recompile."}, |
| {allocateMemory, 0, |
| "Allocation 1: This test allocates a single byte of memory."}, |
| {read0, 0, "Read valid memory 1: This test reads the allocated memory."}, |
| {write0, 0, "Write valid memory 1: This test writes the allocated memory."}, |
| {read1, 1, "Read overrun: This test reads beyond the end of the buffer."}, |
| {freeMemory, 0, "Free memory: This test frees the allocated memory."}, |
| {protectBelow, 0, |
| "Protect below: This sets Electric Fence to protect\n" |
| "the lower boundary of a malloc buffer, rather than the\n" |
| "upper boundary."}, |
| {allocateMemory, 0, |
| "Allocation 2: This allocates memory with the lower boundary" |
| " protected."}, |
| {read0, 0, "Read valid memory 2: This test reads the allocated memory."}, |
| {write0, 0, "Write valid memory 2: This test writes the allocated memory."}, |
| {readMinus1, 1, |
| "Read underrun: This test reads before the beginning of the" |
| " buffer."}, |
| {0, 0, 0}}; |
| |
| static const char failedTest[] = "Electric Fence confidence test failed.\n"; |
| |
| static const char newline = '\n'; |
| |
| int main(int argc, char **argv) |
| { |
| static const struct diagnostic *diag = diagnostics; |
| |
| EF_PROTECT_BELOW = 0; |
| EF_ALIGNMENT = 0; |
| |
| while (diag->explanation != 0) { |
| int status = gotSegmentationFault(diag->test); |
| |
| if (status != diag->expectedStatus) { |
| /* |
| * Don't use stdio to print here, because stdio |
| * uses malloc() and we've just proven that malloc() |
| * is broken. Also, use _exit() instead of exit(), |
| * because _exit() doesn't flush stdio. |
| */ |
| write(2, failedTest, sizeof(failedTest) - 1); |
| write(2, diag->explanation, strlen(diag->explanation)); |
| write(2, &newline, 1); |
| _exit(-1); |
| } |
| diag++; |
| } |
| return 0; |
| } |