你的哪些騷操作會導致Segmentation Fault😂

你的哪些騷操作會導致Segmentation Fault前言如果你是一個寫過一些C程序的同學,那么很大可能你會遇到魔幻的segmentation fault,可能一時間抓耳撓腮,本篇文章主要介紹一些常見的導致segmentation fault的代碼問題,希望能夠幫助大家快速定位問題!
出現Segmentation Fault的常見操作寫只讀數據#include <stdio.h>char* str= "hello world";int main() {printf("%s\n", str);*str = '1';return 0;}在上面的程序當中 , str是一個全局變量,一個指向只讀數據hello world的指針,因為指向的數據存放在只讀數據區,如下圖所示(rodata區域):

你的哪些騷操作會導致Segmentation Fault&#128514;

文章插圖
數組下標越界#include <stdio.h>int main() {int arr[10];arr[1 << 20] = 100; // 會導致 segmentation faultprintf("arr[n] = %d\n", arr[1 << 20]); // 會導致 segmentation faultreturn 0;}棧溢出 stakc_overflow我們可以使用ulimit -a命令查看,系統的一些參數設置 , 比如說棧的最大大?。?
?code git:(main) ? ulimit -a-t: cpu time (seconds)unlimited-f: file size (blocks)unlimited-d: data seg size (kbytes)unlimited-s: stack size (kbytes)8192-c: core file size (blocks)0-m: resident set size (kbytes)unlimited-u: processes2061578-n: file descriptors1048576-l: locked-in-memory size (kbytes)65536-v: address space (kbytes)unlimited-x: file locksunlimited-i: pending signals2061578-q: bytes in POSIX msg queues819200-e: max nice0-r: max rt priority0-N 15:unlimited上面的參數你可以通過重新編譯linux進行更改 。在上面的參數當中我們的棧能夠申請的最大空間等于8192kb = 8M , 我們現在寫一個程序來測試一下:
#include <stdio.h>void stakc_overflow(int times) {printf("times = %d\n", times);char data[1 << 20]; // 每次申請 1 Mega 數據stakc_overflow(++times);}int main() {stakc_overflow(1);return 0;}上面的程序輸出結果如下所示:
【你的哪些騷操作會導致Segmentation Fault😂】
你的哪些騷操作會導致Segmentation Fault&#128514;

文章插圖
當我們低8次調用stakc_overflow函數的時候 , 程序崩潰了,因為這個時候我們再申請數組的時候,就一定會超過8M,因為在前面的 7 次調用當中已經申請的 7M 的空間,除此之外還有其他的數據需要使用一定的??臻g , 因此會有棧溢出,然后報 segmentation failt 錯誤 。
解引用空指針或者野指針#include <stdio.h>int main() {int* p;printf("%d\n", *p);return 0;}當我們去解引用一個空指針或者一個野指針的時候就匯報segmentation fault,其實本質上還是解引用訪問的頁面沒有分配或者沒有權限訪問,比如下面代碼我們可以解引用一個已經被釋放的空間 。
#include <stdio.h>#include <stdint.h>uint64_t find_rbp() {// 這個函數主要是得到寄存器 rbp 的值uint64_t rbp;asm("movq %%rbp, %0;":"=m"(rbp)::);return rbp;}int main() {uint64_t rbp =find_rbp();printf("rbp = %lx\n", rbp);// long* p = 0x7ffd4ea724a0;printf("%ld\n", *(long*)rbp);return 0;}上面的代碼當中我們調用函數 find_rbp,得到這個函數對應的寄存器 rbp 的值 , 當這個函數調用返回的時候,這個函數的棧幀會被摧毀 , 也就是說 rbp 指向的位置程序已經沒有使用了,但是上面的程序不會產生 segmentation fault ,其中最主要的原因就是解引用的位置的頁面我們已經分配了,而且我們有讀權限 , 而且我們也有寫權限,我們甚至可以給 rbp 指向的位置賦值,像下面那樣 , 程序也不會崩潰 。
#include <stdio.h>#include <stdint.h>uint64_t find_rbp() {uint64_t rbp;asm("movq %%rbp, %0;":"=m"(rbp)::);return rbp;}int main() {uint64_t rbp =find_rbp();printf("rbp = %lx\n", rbp);// long* p = 0x7ffd4ea724a0;printf("%ld\n", *(long*)rbp);*(long*)rbp = 100; // 給指向的位置進行復制操作return 0;}解引用已經釋放的內存#include <stdlib.h>int main() {int* ptr = (int*)malloc(sizeof(int));free(ptr);*ptr = 10;return 0;}其實上面的代碼不見得一定會產生 sementation fault 因為我們使用的libc給我們提供的 free 和 malloc 函數 , 當我們使用 free 函數釋放我們的內存的時候,這部分內存不一定就馬上還給操作系統了,因此在地址空間當中這部分內存還是存在的,因此是可以解引用的 。
其他方式我相信你肯定還有很多其他的方式去引起 sementation fault 的,嗯相信你?。。?
造成 sementation failt 的原因主要有以下兩大類:

推薦閱讀