I have the following assignment for an online class and was wondering if anyone was familiar with paranoid arrays, as it's very difficult to get help for this specific class.
Your paranoid array will expose a very simple interface provided in parray.h. You can assume the parray will not be free’d. The parray new call creates an array of a set-number of entries (count argument) of a fixed size (size argument). Internally, the parray will not arrange the elements consecutively in memory, so the parray entry function returns a pointer to a given entry (specified by argument index). In order to trigger a segfault upon overflow within an element, you should use guard pages. A guard page’s main purpose is to trigger segfaults when it is accessed. Thus, pagetable read, write, and execute permissions on a guard table are disabled, so any access to the page will trigger the fault. When a guard page is placed immediately after a buffer or data structure, any buffer overflow bugs affecting that piece of memory will hit the guard page, triggering an instant segfault
Every entry in your array should be bounded by guard pages on each side. For example, an array with 10 entries should use 11 guard pages: one before the first entry, one after the last entry, and nine in between consecutive entries.
My parray_new and parray_entry call is as follows:
typedef char byte;
parray_t* parray_new(int size, int count)
{
struct parray* p = NULL;
// TODO: Allocate and return parray
// Add guard pages first at this time
int pagesize = getpagesize();
p->size = (size * count) + (pagesize * count) + pagesize;
p->array = malloc(p->size + pagesize - 1);
if(posix_memalign(&p->array, p->size, count))
{
exit(0);
}
return p;
}
void* parray_entry(struct parray* p, int index)
{
//int pagesize = getpagesize();
byte* entry = NULL;
// TODO: compute correct entry
if (mprotect(&p->array, p->size-1, PROT_READ))
{
exit(0);
}
if (mprotect(&p->array, p->size, PROT_WRITE))
{
exit(0);
}
entry = (void*)(p->array + index);
return entry;
}
I also have the following handler:
static void handler(int sig, siginfo_t *si, void* unused)
{
// TODO: Use fprintf or perror to print
// a message indicating a segmentation fault
// happened and provide the memory address
// where the fault happened
fprintf(stderr, "Segmentation Fault\n k = %d, %p\n", sig, si >si_addr);
}
Finally, the main method:
int main(void)
{
struct sigaction sa;
/*
* TODO: Overwrite the signal handler for
* SIGSEGV
*/
memset(&sa, '\0', sizeof(sa));
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
if (sigaction(SIGSEGV, &sa, NULL) == -1)
{
perror("sigaction");
exit(EXIT_FAILURE);
}
}
There's also several tests to run in the main method, but I've left those out because I encounter an error before I even reach them. What happens is, the handler prints forever (Segmentation fault, k = 11, 0x8). I do not know the significance of 11 or 0x8, but it does not stop printing that sequence until I force it.
Any help would be greatly appreciated, and I apologize for the length of this post. Thanks
Edit: from what I can see, the handler continues to print. It's not so much that I'm getting a seg fault (I might be), but whatever I put in the handler it continues to print. Also if I change it to perror it does the same. What can I do to allow the program to continue after the handler?