blob: be67d543b33572b8ece82d98f9b594fc28a462ec [file] [log] [blame]
#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;
}