看着貌似吓人的底层问题,其实错在原本的自身

本文讲述了作者在Linux环境下遇到C程序因新代码引入崩溃的问题,通过逐步分析发现是由于非法栈内存覆盖引发的。作者详细描述了问题定位、编译器优化影响、以及最终利用Valgrind工具验证的过程。

过程   

近期遇到一个问题,一个在Linux下运行的C语言程序,突然因为某段代码合入后,就导致程序稳定崩溃!

程序崩溃的位置只是具有一个大方向,崩溃堆栈位置不定,而且是某些不应该出现的运行堆栈逻辑,以及曾出现过非法指令的信号异常core文件。

通过逐步试验,发现:

1、撤销掉新增的代码合入,就不会出现问题;还据此发布了版本

2、如果使用O0编译程序,就不会出现崩溃问题;但使用O3优化编译就出现崩溃。怀疑是因为某些编译器代码优化导致的问题,这个就深层次了:(  看着听吓人的!

3、旁路掉某一个模块的代码,也不会出现问题

当时,是一头雾水,搞不清楚明确的方向!

幸运的时,将研究的重点放在旁路的模块中,通过对代码不断二分旁路,找到问题的根源在于,某段代码对于栈内存的非法覆盖。

示例代码

// 出错代码示意

typedef struct {
    int msgType;
    unsigned int msgLen;
    // C语言结构体的惯用法,指向头部区域后面第一个字节
    unsigned char abData[0];
} T_SomeAck; 




void f(T_SomeAck* ptAck)
{
  ...

  memcpy(ptAck->abData, srcData, someSize);

  ...
}



int main(int argc, char **argv)
 {
    // 栈上没有分配那么大的内存;
    // 解决办法: 
    // 1、结构体定义足够内存 
    // 2、符合C语言结构体此类惯用法,从大的缓冲区中转型;用具体结构体定义,区分头部和尾部

    T_SomeAck  tAck;
    
    ...

    f(&tAck);

    ....

    return 0;
  
 }



结论

回想整个问题解决过程,才逐渐明白过来,就一个非法指令的信号异常处理现象,以及其它莫名奇妙、不该运行的崩溃堆栈,就可以怀疑到是因为内存被非法覆盖后引起的崩溃问题。

因为非法覆盖的是函数返回地址等关键信息,最终导致的崩溃!


附录

照例说,valgrind可以发现栈内存越界的问题,后面再试试故障场景是否可以使用工具发现

# valgrind 可以检查出此处的内存异常

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

static int foo(void)
  {
      int a = 1;
      char b[32];

      printf("before memset\n");
      memset(b, 0, 64); /* stomps the stack */
      printf("after memset\n");

      return 0;
  }


 int main(int argc, char **argv)
 {
     int x;

     printf("before foo()\n");
     x = foo();
     printf("after foo()\n");
     return 0;
 }

### 误原因分析 当使用 `openpyxl` 的 `load_workbook` 函数加载 Excel 文件时,如果出现误信息 `'There is no item named [Content_Types].xml in the archive'`,这通常表明文件并非有效的 `.xlsx` 格式文件[^1]。以下是一些可能的原因和解决方法: #### 1. 文件格式问题 文件可能是一个旧版的 Excel 文件(如 `.xls`),而 `openpyxl` 仅支持 `.xlsx` 和 `.xlsm` 文件格式。如果文件是 `.xls` 格式,则需要使用其他库(如 `xlrd` 或 `pandas`)来读取文件内容。 ```python import pandas as pd # 使用 pandas 读取 .xls 文件 data = pd.read_excel('file.xls', engine='xlrd') ``` #### 2. 文件损坏 文件可能在传输或保存过程中损坏,导致其内部结构缺失必要的组件。可以尝试用 Microsoft Excel 或其他电子表格软件打开文件。如果文件无法正常打开或提示损坏,则说明文件存在问题。可以尝试修复文件或重新生成文件[^3]。 #### 3. 文件被误重命名 文件可能被误地重命名为 `.xlsx`,但实际上并不是 Excel 文件。可以通过将 `.xlsx` 文件后缀改为 `.zip` 并解压,手动检查是否存在 `[Content_Types].xml` 文件。如果该文件缺失,则需要重新生成 `.xlsx` 文件[^4]。 #### 4. 文件路径问题 如果文件存储在特定文件夹中,确保文件路径正确且文件未被移动或删除。可以使用绝对路径来避免路径相关的问题。 ```python from openpyxl import load_workbook # 使用绝对路径加载文件 file_path = r'C:\path\to\your\file.xlsx' wb = load_workbook(file_path) ``` #### 5. 库版本问题 确保使用的 `openpyxl` 版本为最新版本。旧版本可能存在一些未修复的 bug,导致加载文件时出现问题。 ```bash pip install --upgrade openpyxl ``` ### 示例代码 以下是一个完整的示例代码,用于加载 `.xlsx` 文件并处理可能的异常: ```python from openpyxl import load_workbook try: # 尝试加载文件 wb = load_workbook(filename='C:\\path\\to\\your\\file.xlsx') except KeyError as e: if "[Content_Types].xml" in str(e): print("文件可能不是有效的 .xlsx 格式,请检查文件完整性和格式。") else: raise e ``` ### 注意事项 如果上述方法均未能解决问题,建议重新生成 `.xlsx` 文件,并确保文件在传输过程中未被修改或损坏[^5]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值