你的哪些骚操作会导致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区域):

数组下标越界

#include <stdio.h>

int main() {

  int arr[10];
arr[1 << 20] = 100; // 会导致 segmentation fault
printf("arr[n] = %d\n", arr[1 << 20]); // 会导致 segmentation fault
return 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: processes 2061578
-n: file descriptors 1048576
-l: locked-in-memory size (kbytes) 65536
-v: address space (kbytes) unlimited
-x: file locks unlimited
-i: pending signals 2061578
-q: bytes in POSIX msg queues 819200
-e: max nice 0
-r: max rt priority 0
-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;
}

上面的程序输出结果如下所示:

当我们低8次调用stakc_overflow函数的时候,程序崩溃了,因为这个时候我们再申请数组的时候,就一定会超过8M,因为在前面的 7 次调用当中已经申请的 7M 的空间,除此之外还有其他的数据需要使用一定的栈空间,因此会有栈溢出,然后报 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 的原因主要有以下两大类:

  • 读写没有权限的位置:

    • 比如说前面对只读数据区的写操作,或者读写内核数据等等。
  • 使用没有分配的页面:
    • 比如数组越界,就是访问一个没有分配的页面。
    • 解引用空指针或者野指针或者没有初始化的指针,因为空指针或者野指针指向的地址没有分配。
    • 不正确的使用解引用和取地址符号,比如你在使用scanf的时候没有使用取地址符号,也可能造成segmentation fault。
    • 栈溢出,这个是操作系统规定的栈的最大空间。

总结

在本篇文章当中主要给大家介绍了一些常见的造成段错误的原因,下篇我们仔细分析 segmentation fauilt 的本质,以及我们应该如何应对和处理 segmentation fauilt 。希望大家有所收获~~~

以上就是本篇文章的所有内容了,我是LeHung,我们下期再见!!!更多精彩内容合集可访问项目:https://github.com/Chang-LeHung/CSCore

关注公众号:一无是处的研究僧,了解更多计算机(Java、Python、计算机系统基础、算法与数据结构)知识。

你的哪些骚操作会导致Segmentation Fault😂的更多相关文章

  1. linux segmentation fault记录

    文章将记录linux学习使用中出现的各种segmentation fault,持续更新,希望对看到人有所帮助 1. linux pcap segmentation fault -- 2013.11.2 ...

  2. Mac OS 上的一些骚操作

    本帖记录个人在使用 Mac 操作系统上的一些骚操作,不断更新,以飨读者. 快速移动网页到顶部或底部 用双指上下划触摸板吗?NO,我们有更骚的操作: command + ↑ 回到顶部 command + ...

  3. selenium三大切换的骚操作之显性等待

    一.handle窗口切换 当点击某个元素后,会重新生成一个新的页签,但此时我们的操作仍然在原先的窗口当中,如果要在新的窗口继续操作元素,那么就要用到handle窗口切换的方法. 常用方法: windo ...

  4. 关于MySQL的一些骚操作——提升正确性,抠点性能

    概要 回顾以前写的项目,发现在规范的时候,还是可以做点骚操作的. 假使以后还有新的项目用到了MySQL,那么肯定是要实践一番的. 为了准备,创建测试数据表(建表语句中默认使用utf8mb4以及utf8 ...

  5. 聊聊redis实际运用及骚操作

    前言 聊起 redis 咱们大部分后端猿应该都不陌生,或多或少都用过.甚至大部分前端猿都知道. 数据结构: string. hash. list. set (无序集合). setsorted(有序集合 ...

  6. 开源项目在闲鱼、b 站上被倒卖?这是什么骚操作?

    起因 - 又是一封邮件 2020 年 3 月 2 日,收到了一封邮件,对,这次故事的起因又是一封邮件,和上次写个bug被国家信息安全漏洞共享平台抓到了一样. 这是一条评论通知邮件,一开始我以为只是正常 ...

  7. C#中的9个“黑魔法”与“骚操作”

    C#中的9个"黑魔法"与"骚操作" 我们知道C#是非常先进的语言,因为是它很有远见的"语法糖".这些"语法糖"有时过于好 ...

  8. 快来!我从源码中学习到了一招Dubbo的骚操作!

    荒腔走板 大家好,我是 why,欢迎来到我连续周更优质原创文章的第 55 篇. 老规矩,先来一个简短的荒腔走板,给冰冷的技术文注入一丝色彩. 魔幻的 2020 年的上半年过去了,很多人都在朋友圈和上半 ...

  9. newbee-mall开源项目被慕课网拿去做课程,然后我毫不知情,这又是什么骚操作?

    万万没想到,这种事情会发生在我身上. 之前写过<开源囧事>系列而且已经写了四篇,四次开源囧事如下: <开源囧事(一)捅娄子了,写个bug被国家信息安全漏洞共享平台抓到了?> & ...

随机推荐

  1. 故障案例 | 慢SQL引发MySQL高可用切换排查全过程

    作者:梁行 万里数据库DBA,擅长数据库性能问题诊断.事务与锁问题的分析等,负责处理客户MySQL日常运维中的问题,对开源数据库相关技术非常感兴趣. GreatSQL社区原创内容未经授权不得随意使用, ...

  2. 新版 Ubuntu 中 gnome-terminal 可恶的行间距问题逼我退回了 Ubuntu 20.04

    不知道从什么时候起(可能是 Ubuntu 21.04,也可能是 Ubuntu 21.10),Ubuntu 中的 gnome-terminal 的行间距就加大了,看起来极其不爽,特别是和 Powerli ...

  3. SP6779 GSS7 - Can you answer these queries VII(线段树,树链剖分)

    水题,只是坑点多,\(tag\)为\(0\)时可能也要\(pushdown\),所以要\(bool\)标记是否需要.最后树链剖分询问时注意线段有向!!! #include <cstring> ...

  4. 论文解读(GATv2)《How Attentive are Graph Attention Networks?》

    论文信息 论文标题:How Attentive are Graph Attention Networks?论文作者:Shaked Brody, Uri Alon, Eran Yahav论文来源:202 ...

  5. 根节点选择器和 html 选择器

    CSS 中除了用标签选择器选中<html>标签以外还有一个等价的是:root选择器.CSS 变量是有作用域的,全局变量都可以声明在<html>里. <div class= ...

  6. Excel 运算符(三):文本连接符

    文本连接符&用来合并文本串.比如,连接"计算机"和"基础"两个文本串:"计算机基础"&"基础",最终结果 ...

  7. Word 脚注和尾注是什么?怎么设置?

    描述 脚注一般位于页面的底部,作为文档某处内容的注释.尾注一般位于文档的末尾,列出引文的出处等. 设置脚注和尾注 将光标移动到要插入脚注或尾注的地方,然后点击"引用"选项卡. 左边 ...

  8. java.lang.UnsatisfiedLinkError报错

    是因为使用maven时,运行web项目时,在maven的依赖包没有打包到tomcat中(out目录中),所以要手动加上

  9. Linux网桥配置(用于大数据虚拟化)

    理解 VMware里面有三个虚拟机,分别为RHEL8,RHEL7,Windows的虚拟机,只有一个物理网卡连接物理网络,现在三台虚拟机都需要直连到物理网络,此时无法访问物理网络,只能给一个虚拟机访问物 ...

  10. 线程池:ThreadPoolExecutor源码解读

    目录 1 带着问题去阅读 1.1 线程池的线程复用原理 1.2 线程池如何管理线程 1.3 线程池配置的重要参数 1.4 shutdown()和shutdownNow()区别 1.5 线程池中的两个锁 ...