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之旅就到此为止了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/264290.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HUAWEI Programming Contest 2024(AtCoder Beginner Contest 342)

D - Square Pair 题目大意 给一长为的数组&#xff0c;问有多少对&#xff0c;两者相乘为非负整数完全平方数 解题思路 一个数除以其能整除的最大的完全平方数&#xff0c;看前面有多少个与其余数相同的数&#xff0c;两者乘积满足条件&#xff08;已经是完全平方数的部分无…

暂时的停更

最近因学业紧张&#xff0c;暂时停更&#xff0c;但还是会上线 我的专栏&#xff1a;C教程 感谢大家的支持

ChatGPT调教指南 | 咒语指南 | Prompts提示词教程(二)

在我们开始探索人工智能的世界时,了解如何与之有效沉浸交流是至关重要的。想象一下,你手中有一把钥匙,可以解锁与OpenAI的GPT模型沟通的无限可能。这把钥匙就是——正确的提示词(prompts)。无论你是AI领域的新手,还是希望优化与大型语言模型交流的老手,掌握如何精确使用…

SpringBoot3整合Swagger3,访问出现404错误问题(未解决)

秉承着能用就用新的的理念&#xff0c;在JDK、SpringBoot、SpringCloud版本的兼容性下&#xff0c;选择了Java17、SpringBoot3.0.2整合Swagger3。 代码编译一切正常&#xff0c;Swagger的Bean也能加载&#xff0c;到了最后访问前端页面swagger-ui的时候出现404。 根据网上资料…

【Git】Git命令的学习与总结

本文实践于 Learn Git Branching 这个有趣的 Git 学习网站。在该网站&#xff0c;可以使用 show command 命令展示所有可用命令。你也可以直接访问网站的sandbox&#xff0c;自由发挥。 一、本地篇 基础篇 git commit git commit将暂存区&#xff08;staging area&#xff…

【Flink精讲】Flink任务调度机制

Graph 的概念 Flink 中的执行图可以分成四层&#xff1a; StreamGraph -> JobGraph -> ExecutionGraph -> 物理执 行图。 StreamGraph&#xff1a;是根据用户通过 Stream API 编写的代码生成的最初的图。用来表示程序的拓扑结构。JobGraph&#xff1a; StreamGraph …

国家电网相关信息收集

国家电网有限公司招聘平台--首页 (sgcc.com.cn) 这是官方唯一招聘网站平台 国家电网最新组织机构&#xff08;总部、分部、27家省公司、40家直属单位&#xff09; - 知乎 (zhihu.com) 总部招聘&#xff1a; 我的评价&#xff1a;总部在北京&#xff0c;而且只招几个&#xff…

HTTP/HTTPS协议

什么是HTTP协议 HTTP被称为超文本传输协议(里面不仅仅可以是字符串,还可以是图片,特殊字符等),这是一种应用非常广泛的应用层协议. HTTP协议诞生于1991年,现在是最主流使用的一种应用层协议.它从诞生到现在为止迭代了多个版本. 但目前最主流使用的还是HTTP1.1和HTTP2.0. HTTP协…

产品渲染3D效果图一张多少钱,哪个平台更有性价比?

产品渲染3D效果图的价格受到多方面因素的影响&#xff0c;包括但不限于产品类型、渲染难度以及输出尺寸等。如果效果图需要后期处理&#xff0c;还有可能增加其他费用。接下来&#xff0c;我们来了解一下产品渲染效果图的费用情况。 1.产品渲染3D效果图一张多少钱&#xff1f; …

Fiddler工具 — 19.Fiddler抓包HTTPS请求(二)

5、查看证书是否安装成功 方式一&#xff1a; 点击Tools菜单 —> Options... —> HTTPS —> Actions 选择第三项&#xff1a;Open Windows Certificate Manager打开Windows证书管理器。 打开Windows证书管理器&#xff0c;选择操作—>查看证书&#xff0c;在搜索…

MySQL——基础内容

目录 第01章_数据库概述 关系型数据库(RDBMS)——表、关系模型 非关系型数据库(非RDBMS) 表、记录、字段 表的关联关系 一对一关联 一对多关系 多对多 自我引用 第02章_MySQL环境搭建 登录命令 常用命令 show databases; create database use 数据库名 show tables 第03章…

大概了解一下G1收集器

在上一篇文章中&#xff08;链接&#xff1a;大概了解一下CMS收集器&#xff09;我们提到&#xff0c;CMS是一种主要针对旧生代对象进行回收的收集器。与CMS不同&#xff0c;G1号称“全功能的垃圾收集器”&#xff0c;对初生代内存和旧生代内存均进行管理。鉴于此&#xff0c;这…

【Java程序设计】【C00291】基于Springboot的网上图书商城(有论文)

基于Springboot的网上图书商城&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的网上图书商城 本系统分为系统功能模块、管理员功能模块以及卖家功能模块。 系统功能模块&#xff1a;在系统首页可以查看首页、图书…

c++:vector的相关oj题(136. 只出现一次的数字、118. 杨辉三角、26. 删除有序数组中的重复项、JZ39 数组中出现次数超过一半的数字)

文章目录 1. 136. 只出现一次的数字题目详情代码(直接来异或&#xff09;思路 2. 118. 杨辉三角题目详情代码1思路代码2思路2 3. 26. 删除有序数组中的重复项题目详情代码思路 4. JZ39 数组中出现次数超过一半的数字题目详情代码1&#xff08;暴力&#xff09;思路1代码2&#…

Unity发布webgl获取浏览器的URL

Unity发布webgl获取浏览器的URL Unity发布webgl之后获取浏览器的url 在unity中创建文件夹Plugins&#xff0c;然后添加添加文件UnityGetBrowserURL.jslib var GetUrlFunc {//获取地址栏的URLStringReturnValueFunction: function () {var returnStr window.top.location.hre…

【Java程序员面试专栏 数据结构】三 高频面试算法题:栈和队列

一轮的算法训练完成后,对相关的题目有了一个初步理解了,接下来进行专题训练,以下这些题目就是汇总的高频题目,因为栈和队列这两哥们结构特性比较向对应,所以放到一篇Blog中集中练习 题目题干直接给出对应博客链接,这里只给出简单思路、代码实现、复杂度分析 题目关键字…

Less预处理器教程

学习源码可以看我的个人前端学习笔记 (github.com):qdxzw/frontlearningNotes 觉得有帮助的同学&#xff0c;可以点心心支持一下哈 一、Less介绍 less官方文档 lesscss.org/ less中文文档 less.bootcss.com/ less是一种css预处理器&#xff0c;它扩展了css语言&#xff0c…

OpenCV开发笔记(七十五):相机标定矫正中使用remap重映射进行畸变矫正

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://blog.csdn.net/qq21497936/article/details/136293833 各位读者&#xff0c;知识无穷而人力有穷&#xff0c;要么改需求&#xff0c;要么找专业人士&#xff0c;要么自己研究 红胖子(红模仿…

Day15-集合-迭代器-课后练习-参考答案

文章目录 Day15_课后练习泛型练习题第1题第2题第3题第4题第5题 集合练习题第1题第2题 Day15_课后练习 泛型练习题 第1题 案例&#xff1a;有如下四个学生的成绩&#xff1a; &#xff08;1&#xff09;用Comparable接口对下列四位同学的成绩做降序排序&#xff0c;如果成绩一…

SQL Server 开发环境配置教程(SSMS+SQL Prompt)

背景 记录一下 SQL Server 常用开发软件 体验了各种数据库IDE(DBeaver、Navicat、DataGrip)之后综合下来还是感觉 SSMSSQL Prompt 对于 SQL Server 最好用&#xff0c;所以在此记录一下配置过程 数据库可视化管理工具SSMS 官方下载地址&#xff1a; https://learn.microsoft…