Почему printf прерывает обработчики сигналов в macOS, а не в ubuntu? - PullRequest
0 голосов
/ 22 сентября 2018

Я выполнял простую демонстрацию обработчиков сигналов в качестве упражнения, когда заметил какое-то странное поведение.Следующий код работает без изменений на Ubuntu 14.04 LTS, но не на macOS Sierra 10.12.6.То есть на macOS программа навсегда зависает без вывода.Однако он работает на обеих платформах с printf, закомментированным в обработчиках сигналов, или с дополнительным printf, добавленным в основную функцию в любом месте перед вызовом posix_memalign.Я не понимаю это поведение, что происходит?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <signal.h>


//Has to be global for signal handler
char* mem_spot = NULL;
const char* copy_from = "hello";
const int mem_req = 5;

//signal handler prototype
void handle_seg(int fault);

int
main(int argc, char const *argv[])
{
    //On macOS this must be placed uncommented somewhere before
    //posix_memalign or the signal handler printing removed:

    //printf("Strange fixing code!");

    //setup signal handlers
    signal(SIGSEGV,handle_seg);
    signal(SIGBUS,handle_seg);
    //get memory aligned to the page and protect it
    posix_memalign((void**) &mem_spot, getpagesize(), mem_req);
    mprotect(mem_spot,mem_req,PROT_READ);
    //Copying into the memory slot (it's protected so should break!)
    strcpy(mem_spot,copy_from);
    //Output my results
    printf("Write of string '%s' to memory giving '%s' complete!\n",copy_from, mem_spot);
    return 0;
}

void handle_seg(int fault)
{
    if (fault == SIGSEGV){
        printf(" (Handled a segmentation fault!) ");
        mprotect(mem_spot,mem_req,PROT_READ | PROT_WRITE);
    }
    else if (fault == SIGBUS){
        printf(" (Handled a bus fault!) ");
        mprotect(mem_spot,mem_req,PROT_READ | PROT_WRITE);
    }
}

1 Ответ

0 голосов
/ 22 сентября 2018

Итак, чтобы дать реальный ответ: Ваша программа вызывает неопределенное поведение несколькими способами, что означает, что она может делать все что угодно.Распечатка чего-либо, зависание или сбой - все равно действительные результаты его запуска.

Ваша первая проблема: вызов неисинхронно-безопасной функции сигнала из обработчика сигнала.Существует ограниченное количество функций, которые можно безопасно вызывать из обработчиков.Вы можете увидеть список здесь или в linux с man signal-safety.

Ваша вторая проблема: возврат из обработчика сигнала, вызванного SIGSEGV, который не был вызванфункция типа kill(), которая явно поднимает данный сигнал.Чтобы процитировать приведенную выше документацию:

Поведение процесса не определено после нормального возврата из функции перехвата сигнала для сигнала SIGBUS, SIGFPE, SIGILL или SIGSEGV, который не был сгенерирован kill(), sigqueue () или Повышение ().

Подводя итог: То, что вы делаете, по своей сути нарушено, а не то, что можно предсказать или обосновать или понять.Не делай этого.

...