使用 -O3 使用 g++ 编译时C++程序中的分段错误

Segmentation fault in a C++ program when compiling with g++ using -O3

本文关键字:使用 分段 错误 程序 C++ -O3 g++ 编译      更新时间:2023-10-16

当我使用 g++(版本 4.9.1(编译以下代码时,它适用于非优化或使用 -O2 进行优化。但是,当使用 -O3 编译时,程序在第 30 行崩溃并打印"分段错误(核心转储("。

我试图保持尽可能简单。我还注意到,删除(看似(不重要的部分,例如成员变量单词,似乎可以解决问题。我在这里做错了什么?

#include <iostream>
#include <stdlib.h>
using namespace std;
char *curMemPos2=NULL;  //The first free pos in allocated memory
class Dictionary{
    public:
        int numWords;
        int* words;
        double* wordFrequency;
        Dictionary(int nw){
            numWords = nw;
            wordFrequency = NULL;
            wordFrequency = (double*)curMemPos2;
            curMemPos2 += (sizeof(double)*numWords);
            words = NULL;
            words = (int*)curMemPos2;
            curMemPos2 += (sizeof(int)*numWords);
            if (wordFrequency == NULL || words == NULL) {
                cout << "could not allocate memory" << endl;
                exit(0);
            }
        }
        void addwords(){
            for (int i = 0; i < numWords; i++){
                wordFrequency[i] = i * 0.2;
            }
        }
};
int main(){ 
    curMemPos2 = (char*) malloc(1024 * 1024);
    if (curMemPos2 == NULL) {
        cout << "could not allocate initial memory" << endl;
        exit(0);
    }
    for (int i = 5; i < 10; i++){
        cout << "--------------------------" << endl;
        cout << "initializing dict with " << i << " words" << endl;
        Dictionary d = Dictionary(i);
        cout << "adding words" << endl;
        d.addwords();
    }
}

您似乎正在尝试在此处执行基于内存池的分配器,这通常不是一个坏主意。(不过,该实现可能需要大量改进。

您遇到的问题是对齐。 int 可能是 4 字节对齐的。 double 可能是 8 字节对齐的。

malloc返回的地址始终适合具有基本对齐要求的任何类型的对象 - 因此对于intdouble,它始终对齐良好。当您尝试分配奇数个 int s 时,会出现此问题。假设 malloc 返回地址0x3000并且您分配了 5 个int,然后 curMemPos2 的地址变为 0x3014 ,然后您尝试分配 5 个double s - 但0x3014不是double的有效地址,因为它不是 8 字节对齐的。

事实上,它不适用于优化,而它没有工作,这表明您的代码中存在一些未定义的行为,在某些情况下(不幸(有效。

您在这里有几个候选人:

  • 如果两个不同类型的指针(例如 int *wordsdouble *wordfrequency ( 将指向相同的内存位置,将不遵守严格的混叠。 严格别名是关于编译器对指针所做的假设,以便进一步优化代码。
  • 有时添加到全局curMemPos2指针sizeof(int)有时添加到sizeof(double) 。 即使您的初始指针可能符合所有类型的对齐方式,如果优化器尝试使用具有对齐要求的特殊 CPU 操作,则您的cumMemPos2也可能在某个时刻不符合double导致邪恶的对齐要求。
  • 您的自制分配方案不控制上限:您将永远递增curMemPos2并且您的指针有一天可能会指向未分配的内存(此处不会将它们设置为 NULL(。但是,好的,此项目符号不是问题的原因,因为您只分配了几个条目。

建议:

由于每个Dictionary构造都使用自我管理的内存池中的数字字int数字double,因此我建议使用受保护的结构:

class Dictionary{
    protected: 
        struct mbloc {     // with a struct, the compiler takes care of alignment requ.
            double frequency; 
            int words; 
            };            
    public:
         ...   // allocate mbloc *entries instead of *int and *doubles; 
}; 

使用这种方法,您可以考虑使用 new 来分配一个干净的 mbloc 数组,甚至可能是一个vector<mbloc>