当前位置: 首页 > news >正文

Webserver解决segmentation fault(core dump)段错问问题

前言

在完成了整个项目后,我用make命令编译了server,当我运行./server文件时,出现了段错误

在大量的代码中找出错因并不是一件容易的事,尤其是对新手程序员来说。而寻找bug的过程就像是侦探调查线索追查凶手一样,我们要通过一点一点的蛛丝马迹来剥离表象,找到真凶。

今天,就由我来扮演一次侦探,调查一番这个段错误到底出自谁手。

段错误:我们面临的是什么敌人

在解决问题之前,让我先来了解一下什么是段错误:

"Segmentation fault (core dumped)" 是一种程序运行时错误,通常表示程序试图访问无效的内存地址。这种错误可能由多种原因引起,包括指针错误、数组越界、使用已释放的内存等。

一般情况下,解决段错误的方法是使用gdb调试段错误生成的core文件。但是许多人会发现系统不会生成core dump文件,这是因为 core dump文件是由linux系统进行生成,而且其往往较大,默认情况下,Linux是不允许生成core dump文件的。

我们可以使用

ulimit -c

命令来查看,如果是 0,说明Linux允许的core文件最大大小为0,即不允许生成core文件

这时,我们要使用

ulimit -c unlimited

来将core文件最大大小改为无限。

我们再编译运行程序就会产生core文件,但是默认的core文件生成目录不在本目录,因此需要把默认core文件生成目录改成运行目录,再然后.....

......

这也太麻烦了,有没有更简单的方法。哎,你别说,还真有,接下来我们不借助core文件来"查案"

GDB调试探方向,段错误真相初现端倪

首先,我们在makefile文件里的编译代码加上-g的可选项,这样生成的server就是一个可以用gdb调试的可执行文件。

随后,我们使用gdb命令进入server可执行文件

gdb server

进入gdb调试器以后,我们使用run运行

gdb给出已下报错:

注意看这里的MYSQL Error: mysql_real_connect,虽然gdb告诉我们是在 iofputs.c 的__GI__IO_fputs函数出现的段错误,但是这是系统调用,无数人用了那么多年,不太可能出现错误,所有应该还是我们自己的代码有问题。那我们该从何找起呢?

哎,我们发现这里有一条日志:

MySQL Error : mysql_real_connect\n

这不是我们写的日志吗,太好了,我们终于发现了错误的蛛丝马迹。

深入代码危险区,巧设监控锁暗敌

经过我们的重重调查,我们终于定位到了错误代码函数所在地,即sql_connection_pool.cpp的init函数

void connection_pool::init(string url, string User, string PassWord, string DBName, int MaxConn, int Port, int close_log) {m_url = url;m_Port = Port;m_User = User;m_PassWord = PassWord;m_DatabaseName = DBName;m_close_log = close_log;for (int i = 0; i < MaxConn; ++i) {MYSQL *con = NULL;con = mysql_init(con);if (con == nullptr) {LOG_ERROR("MySQL Error : mysql_init");exit(1);}/*真正的连接函数*/con = mysql_real_connect(con, url.c_str(), User.c_str(), PassWord.c_str(), DBName.c_str(), Port, NULL, 0);if (con == nullptr) {LOG_ERROR("MySQL Error : mysql_real_connect");exit(1);}connList.push_back(con);m_FreeConn++;}reserve = sem(m_FreeConn);//信号量记录共享资源总量m_MaxConn = m_FreeConn;
}

其中,GDB告诉我们的线索即是这里的”人证“给出的 , 即第22行的

LOG_ERROR("MySQL Error : mysql_real_connect");

让我们看看这个函数里的关键API:mysql_init和mysql_real_connect

mysql_init 是 MySQL C API 中的一个函数,用于初始化和分配一个 MYSQL 结构,这个结构是用于表示 MySQL 连接的句柄。这个函数通常是在开始使用 MySQL C API 之前调用的,以确保连接句柄是有效的。

mysql_real_connect 函数是 MySQL C API 中的一个关键函数,用于建立与 MySQL 服务器的连接

可见,这个函数是通过mysql_init创建句柄,再用该句柄创建mysql连接

咋一看好像这一块的代码都没有问题,那是怎么回事了?

为了深一步调查,我们使用时空回溯大法,我们在这里设下”监控“,重现当时的”犯罪场景“,那么我们该如何设下监控呢?其实很简答,就是我们在c++中常用debug方法,在程序中打印出调试信息,这里我们就在第19行代码

con = mysql_real_connect(con, url.c_str(), User.c_str(), PassWord.c_str(), DBName.c_str(), Port, NULL, 0);

的前后,分别写上

cout<<"before mysql_real_connect"<<endl;
con = mysql_real_connect(con, url.c_str(), User.c_str(), PassWord.c_str(), DBName.c_str(), Port, NULL, 0);
cout<<"after mysql_real_connect"<<endl;

然后我们再编译运行,出现以下结果:

可以看到,程序并非是没进入mysql_real_connect就报错,而是循环了无数遍后才出现的报错;这是怎么回事了,为了清晰地看到循环次数,我们为“监控”加上计数器

cout<<"第"<<i<<"次 before mysql_real_connect"<<endl;
con = mysql_real_connect(con, url.c_str(), User.c_str(), PassWord.c_str(), DBName.c_str(), Port, NULL, 0);
cout<<"第"<<i<<"次 after mysql_real_connect"<<endl;

可以看到,程序循环了151次后就结束了,随后发生了段错误。这是什么原因?让我们接着“调查”。

日夜辗转寻真相,辛勤探寻不负望

经过前面的“调查”,我们得到了线索,再init循环中,当程序循环151次,第152次就发生了段错误。没办法,我们先去调查一下是谁调用了init

我们发现,调用该函数的是WebServer.cpp的void sql_pool()函数,而且该函数给init的循环上限MaxConn设置的是3306

void WebServer::sql_pool() {/*初始化数据库连接池*/m_connPool = connection_pool::Getinstance();m_connPool->init("localhost", m_user, m_passWord, m_databaseName, 3306, m_sql_num, m_close_log);/*初始化数据库读取表*/users->initmysql_result(m_connPool);
}

我们对比一下m_connPool的定义,发现了问题所在

void connection_pool::init(string url, string User, string PassWord, string DBName,  int MaxConn, int Port,int close_log) 

原来是因为Port和MaxConn在定义在前的为端口,定义在后的为循环上限了,导致了端口号被用来当循环的上限;而数据库最大能创建的连接数是152,超出了152自然就触发了段错误;那么,我们将调用init的地方改过来即可。

后记

经过不懈的努力,我终于是解决了这个BUG。但其实在解决bug的过程中我并不像文章中说的那么容易,包括最开始我为了去得到 core文件,找了许多方法,也花了很多时间,但是一直没有什么显著效果。中间我一度沮丧到想哭。最后也是不管三七二十一用GDB运行了一次server文件才找到了一点点蛛丝马迹。而后面在发现循环151次后就会段错误的时候,我也一度找错了方向,找了许多方法,把数据库的连接上限改成3500,系统能容纳的最大文件描述符也被我改成了3500,如下图

但是当我以为解决问题的时候,再运行虽然超过了151,但在1000多的时候还是会段错误,当时我想了好多办法,但一直收效见微。可见在错误的方向上,你越努力,错的就越离谱。最后还是检查源码的时候发现这里的调用把port和Maxconn写错位了,也算是给写这篇文章的大家一个警醒吧。

像这样的BUG我在项目中遇到不止一个,其实项目我在两天前就写完了,这两天一直在debug,几乎可以说是不吃不喝地程度了,连上厕所,睡觉都在想怎么debug。皇天不负有心人,项目我也终于是完成了,后面把剩下的博客写完,我的将近30天Webserver之旅就到此为止了。

相关文章:

Webserver解决segmentation fault(core dump)段错问问题

前言 在完成了整个项目后&#xff0c;我用make命令编译了server&#xff0c;当我运行./server文件时&#xff0c;出现了段错误 在大量的代码中找出错因并不是一件容易的事&#xff0c;尤其是对新手程序员来说。而寻找bug的过程就像是侦探调查线索追查凶手一样&#xff0c;我们…...

存储过程基本了解

文章目录 介绍存储过程示例1. 目的2. 输入参数3. 输出参数4. 执行逻辑5. 返回值6. 示例用法7. 注意事项 存储过程的关键字有哪些简单实操 介绍 存储过程是一组预编译的SQL语句&#xff0c;以及流程控制语句&#xff0c;封装在数据库服务器中并可以被重复调用。它们可以接收参数…...

『大模型笔记』RAG应用的12种调优策略指南

RAG应用的12种调优策略指南 文章目录 一. 概要二. 数据索引2.1. 数据清洗2.2. 分块2.3. 嵌入模型2.4. 元数据(或未向量化的数据)2.5. 多索引2.6. 索引算法三. 推理阶段(检索和生成)3.1. 检索参数3.2. 高级检索策略3.3. 重新排序模型3.5. 大语言模型(LLM)...

leedcode刷题--day7(字符串)

23 文章讲解 力扣地址 C class Solution { public:void reverseString(vector<char>& s) {int left 0;int right s.size() - 1; // right 应该初始化为 s.size() - 1while (left < right) {swap(s[left], s[right]); // 直接交换 s[left] 和 s[right] 的值lef…...

【蓝桥杯省赛真题31】python连续正整数之和 中小学青少年组蓝桥杯比赛python编程省赛真题解析

目录 python连续正整数之和 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python连续正整数之和 第十二届蓝桥杯青少年组python比赛省赛真题 …...

【116个】网络安全测试相关面试真题

1、Burpsuite常用的功能是什么&#xff1f; 2、reverse_tcp和bind_tcp的区别&#xff1f; 3、拿到一个待检测的站或给你一个网站&#xff0c;你觉得应该先做什么&#xff1f; 4、你在渗透测试过程中是如何敏感信息收集的&#xff1f; 5、你平时去哪些网站进行学习、挖漏洞提…...

微服务day02-Ribbon负载均衡与Nacos安装与入门

一.Ribbon负载均衡 在上一节中&#xff0c;我们通过在RestTemplte实例中加上了注解 LoadBalanced,表示将来由RestTemplate发起的请求会被Ribbon拦截和处理&#xff0c;实现了访问服务时的负载均衡&#xff0c;那么他是如何实现的呢&#xff1f; 1.1 Ribbon负载均衡的原理 Rib…...

深度学习-神经网络原理

文章目录 神经网络原理1.单层神经网络1.1 回归单层神经网络&#xff1a;线性回归1.2 二分类单层神经网络&#xff1a;sigmoid与阶跃函数 1.3 多分类单层神经网络&#xff1a;softmax回归 神经网络原理 人工神经网络&#xff08;Artificial Neural Network&#xff0c;ANN&…...

Chat GPT:智能对话的下一步

Chat GPT&#xff1a;智能对话的下一步 介绍 Chat GPT&#xff08;Generative Pre-trained Transformer&#xff09;是一种基于Transformer架构的强大对话模型&#xff0c;可以产生自然流畅的回答&#xff0c;并实现人机对话的感觉。本文将探讨Chat GPT在智能对话领域的影响和…...

[数据集][目标检测]鸡蛋破蛋数据集VOC+YOLO格式792张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;792 标注数量(xml文件个数)&#xff1a;792 标注数量(txt文件个数)&#xff1a;792 标注类别…...

RabbitMQ实战学习

RabbitMQ实战学习 文章目录 RabbitMQ实战学习RabbitMQ常用资料1、安装教程2、使用安装包3、常用命令4、验证访问5、代码示例 一、RabbitMQ基本概念1.1. MQ概述1.2 MQ 的优势和劣势1.3 MQ 的优势1. 应用解耦2. 异步提速3. 削峰填谷 1.4 MQ 的劣势1.5 RabbitMQ 基础架构1.6 JMS 二…...

插混、油混、增程式、轻混、强混,啥区别

这里写自定义目录标题 随着我国新能源汽车的大力推进&#xff0c;电车可以说是世界未来的主流&#xff0c;只不过现在是处在一个过渡时代 这是个好时代&#xff0c;因为我们见证并体验着历史过渡的细节 这是个不好的时代&#xff0c;因为我们可能只是未来新新人类的试验品 帮他…...

React 模态框的设计(八)优化补充

在之前的弹窗的设计中&#xff0c;有两处地方现在做一点小小的优化&#xff0c;就是把_Draggable.jsx中的 onPointerEnter 事件 用 useLayoutEffect来规换&#xff0c;效果更佳&#xff0c;同样的&#xff0c;在_ModelContainer.jsx中也是一样。如下所示&#xff1a; _Draggabl…...

知识积累(三):深度学习相关概念(查看检索时看到)

文章目录 1. 知识蒸馏2. 可微搜索索引&#xff08;DSI&#xff09;参考资料 在找论文时&#xff0c;发现的相关概念。 1. 知识蒸馏 知识蒸馏&#xff08;knowledge distillation&#xff09;是模型压缩的一种常用的方法&#xff0c;不同于模型压缩中的剪枝和量化&#xff0c;知…...

计算机专业必看的几部电影

目录 ​编辑 1. 《第九区》&#xff08;District 9&#xff0c;2009&#xff09; 2. 《谍影重重》&#xff08;The Bourne Identity&#xff0c;2002&#xff09; 3. 《源代码》&#xff08;Source Code&#xff0c;2011&#xff09; 4. 《她》&#xff08;Her&#xff0c;…...

工业人工智能需要注意的10件事

我们无法逃避人工智能这个风口&#xff0c;宣传人工智能软件的广告铺天盖地&#xff0c;似乎每个供应商都在推出最新的工具包&#xff0c;每天都有关于 ChatGPT、Bard 等新用例的文章。似乎全世界都在说&#xff1a;你现在需要人工智能&#xff01; 人工智能确实正在成为自动化…...

软考-系统集成项目管理中级-信息系统建设与设计

本章重点考点 1.信息系统的生命周期 信息系统建设的内容主要包括设备采购、系统集成、软件开发和运维服务等。信息系统的生命周期可以分为四个阶段:立项、开发、运维和消亡。 2.信息系统开发方法 信息系统常用的开发方法有结构化方法、原型法、面向对象方法等 1)结构化方法 …...

C++从零开始的打怪升级之路(day39)

这是关于一个普通双非本科大一学生的C的学习记录贴 在此前&#xff0c;我学了一点点C语言还有简单的数据结构&#xff0c;如果有小伙伴想和我一起学习的&#xff0c;可以私信我交流分享学习资料 那么开启正题 今天分享的是关于模板的知识点 1.非类型模板参数 模板参数分为…...

Java面试题之并发

并发 1.并发编程的优缺点?2.并发编程三要素?3.什么叫指令重排?4.如何避免指令重排?5.并发?并行?串行?6.线程和进程的概念和区别?7.什么是上下文切换?8.守护线程和用户线程的定义?9.什么是线程死锁?10.形成死锁的四个条件?11.怎么避免死锁?12.创建线程的四种方式?…...

Python GUI自动化定位代码参考

一、pyautogui原始逻辑 import pyautogui # 获取指定图片在屏幕上的位置 image_path path/to/image.png target_position pyautogui.locateCenterOnScreen(image_path) if target_position is not None: # 获取偏移量 offset_x 10 offset_y 10 # 计算实际点…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

基于Java+MySQL实现(GUI)客户管理系统

客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息&#xff0c;对客户进行统一管理&#xff0c;可以把所有客户信息录入系统&#xff0c;进行维护和统计功能。可通过文件的方式保存相关录入数据&#xff0c;对…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

rm视觉学习1-自瞄部分

首先先感谢中南大学的开源&#xff0c;提供了很全面的思路&#xff0c;减少了很多基础性的开发研究 我看的阅读的是中南大学FYT战队开源视觉代码 链接&#xff1a;https://github.com/CSU-FYT-Vision/FYT2024_vision.git 1.框架&#xff1a; 代码框架结构&#xff1a;readme有…...

Qt/C++学习系列之列表使用记录

Qt/C学习系列之列表使用记录 前言列表的初始化界面初始化设置名称获取简单设置 单元格存储总结 前言 列表的使用主要基于QTableWidget控件&#xff0c;同步使用QTableWidgetItem进行单元格的设置&#xff0c;最后可以使用QAxObject进行单元格的数据读出将数据进行存储。接下来…...

【Axure高保真原型】图片列表添加和删除图片

今天和大家分享图片列表添加和删除图片的原型模板&#xff0c;效果包括&#xff1a; 点击图片列表的加号可以显示图片选择器&#xff0c;选择里面的图片&#xff1b; 选择图片后点击添加按钮&#xff0c;可以将该图片添加到图片列表&#xff1b; 鼠标移入图片列表的图片&…...

OCC笔记:TDF_Label中有多个相同类型属性

注&#xff1a;OCCT版本&#xff1a;7.9.1 TDF_Label中有多个相同类型的属性的方案 OCAF imposes the restriction that only one attribute type may be allocated to one label. It is necessary to take into account the design of the application data tree. For exampl…...

链结构与工作量证明7️⃣:用 Go 实现比特币的核心机制

链结构与工作量证明:用 Go 实现比特币的核心机制 如果你用 Go 写过区块、算过哈希,也大致理解了非对称加密、数据序列化这些“硬核知识”,那么恭喜你,现在我们终于可以把这些拼成一条完整的“区块链”。 不过别急,这一节我们重点搞懂两件事: 区块之间是怎么连接成“链”…...