c Sigsegvハンドラー&mprotect
質問
mprotect()を使用してメモリブロックがアクセスを制限するプログラムを構築しています。メモリが要求されると、sigsegvがスローされます。
SigsegVが検出されたら、要求されたメモリ(障害を投げた)と要求されたセグメントのサイズへのポインターに何らかの形でアクセスする必要があります。これは可能ですか?
void fifoSigHandler(){
// Needs to only remove protection from requested block of virtual memory
mprotect(fifoVm,(size_t)fifoVm_size,PROT_WRITE);
printf("Caught Seg Fault");
}
void fifo_init(void* vm, int vm_size, int n_frames, int page_size)
{
fifoVm = vm;
fifoVm_size = vm_size;
fifoFrames = n_frames;
fifoPageSize = page_size;
mprotect(fifoVm,(size_t)fifoVm_size,PROT_NONE);
signal(SIGSEGV, fifoSigHandler);
}
さらに、Mprotect()のレベルを決定する方法はありますか?メモリのブロックが現在割り当てられています(prot_none、prot_readなど)?
解決
使用する必要があります sigaction
と SA_SIGINFO
それ以外の signal
ハンドラーを確立すると、有用な情報でコールバックされます siginfo_t
, 、 含む si_addr
.
si_addr
, 、説明したように sigaction
(2)、アドレスが含まれます。長さに関しては、指示を解析しようとしない限り、あなたは運が悪い。あなたができることは、報告されたページのために行動を起こすことです si_addr
, 、そしてそれだけでは不十分な場合は、すぐに別の信号が得られます。少なくとも、それが私たちがオブジェクトストアで物事をした方法です。
他のヒント
あなたは探している libsigsegv
http://libsigsegv.sourceforge.net/
しかし、その呼び出しに注意してください mprotect
Linuxでのみ信号安全であるため、他のPOSIXシステムはこれをサポートしていない場合があります。
Linuxでは、メモリ保護ビットを取得する唯一の方法は読むことだと思います /proc/$pid/meminfo
サイドノート(Linuxのみ):メモリの消費が心配であり、1つずつ大きなマッピングのページを有効にするつもりなら、マッピングを使用して作成することをお勧めします mmap
と MAP_NORESERVE
その場合、最初の書き込みで物理RAMを割り当てるゼロで充填されたコピーオンワイトページにマッピングが取得されます。 MAP_NORESERVE
カーネルに、最大64TBの仮想アドレススペースを割り当てることができるスワップスペースでメモリをバックバックしないように指示します。唯一の欠点は、記憶がなくなった場合、ひどいことが起こる可能性があることです(oom-killer)。
ステップ1: :init a sigaction
:
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
sigemptyset(&act.sa_mask);
act.sa_sigaction = handler;
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
ステップ2: : これ作って sigaction
取り持つ SIGSEGV
:
sigaction(SIGSEGV, &act, NULL);
(オプション) ステップ3: :他のメモリ信号も処理します。
sigaction(SIGBUS, &act, NULL);
sigaction(SIGTRAP, &act, NULL);
必要に応じてエラー処理を追加します
ステップ4: :ハンドラー関数を定義します:
void handler(int signal, siginfo_t* siginfo, void* uap) {
printf("Attempt to access memory at address %p\n",
siginfo->si_addr);
#ifdef LINUX_64BIT
printf("Instruction pointer: %p\n",
(((ucontext_t*)uap)->uc_mcontext.gregs[16]));
#elif LINUX_32BIT
printf("Instruction pointer: %p\n",
(((ucontext_t*)uap)->uc_mcontext.gregs[14]));
#endif
}
あなたは男のページを参照することができます ucontext_t
と siginfo_t
より興味深いデータのために、ハンドラーは抽出できます。