Реализация параноидального массива в C - PullRequest
0 голосов
/ 03 апреля 2019

У меня есть следующее задание для онлайн-класса, и мне было интересно, знаком ли кто-нибудь с параноидальными массивами, так как очень трудно получить помощь для этого конкретного класса.

Ваш массив paranoid предоставит очень простой интерфейс, предоставленный в parray.h. Вы можете Предположим, что parray не будет бесплатным. При вызове parray new создается массив с номером набора записей (аргумент count) фиксированного размера (аргумент size). Внутренне, парри будет не размещать элементы последовательно в памяти, поэтому функция ввода parray возвращает указатель на данную запись (указывается индексом аргумента). Чтобы вызвать segfault при переполнении внутри элемента, вы должны использовать guard страницы. Основная цель защитной страницы - запускать ошибки при обращении к ним. Таким образом, разрешения на чтение, запись и выполнение для таблицы защиты таблиц отключены, поэтому любой доступ к страница вызовет ошибку. Когда защитная страница размещается сразу после буфера или структура данных, любые ошибки переполнения буфера, затрагивающие этот фрагмент памяти, будут поражать страница, активирующая мгновенный сегмент

Каждая запись в вашем массиве должна быть ограничена защитными страницами с каждой стороны. Например, массив с 10 записями должен использовать 11 защитных страниц: одну перед первой записью, одну после последняя запись и девять между последовательными записями.

Мой вызов parray_new и parray_entry выглядит следующим образом:

 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;
 }

У меня также есть следующий обработчик:

 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);
 }

Наконец, основной метод:

 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);
    }   
 }

Есть также несколько тестов для запуска в основном методе, но я их пропустил, потому что я сталкиваюсь с ошибкой еще до того, как достигну их. Что происходит, обработчик печатает вечно (ошибка сегментации, k = 11, 0x8). Я не знаю значения 11 или 0x8, но это не останавливает печать этой последовательности, пока я не заставлю ее.

Любая помощь будет принята с благодарностью, и я прошу прощения за длину этого поста. Спасибо

Редактировать: из того, что я вижу, обработчик продолжает печатать. Это не так сильно, что я получаю ошибку сегмента (я мог бы быть), но все, что я помещаю в обработчик, оно продолжает печатать. Кроме того, если я изменю его на perror, он сделает то же самое. Что я могу сделать, чтобы программа продолжила работу после обработчика?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...