尝试创建100MB的缓冲区时出现分段错误

Segmentation fault when trying to create a buffer of 100MB

本文关键字:分段 错误 缓冲区 创建 100MB      更新时间:2023-10-16

我正试图将一个大型二进制文件写入C++程序的缓冲区。GDB总是在尝试创建与读取的文件大小相同的缓冲区后得到一个segfault。它要么在fclose(pf)、reback或f(open)上失败,这让我在尝试创建缓冲区时相信有什么问题。我的代码段如下。

static int fileTransfer(struct mg_connection *conn, char * filename){
    FILE *fp = fopen(filename, "r"); 
    fseek(fp, 0, SEEK_END);
    int size = ftell(fp);
    char buf[size];
    fclose(fp); 
    // This is an attempt to stop a segment fault from rewind. 
    fp = fopen(filename, "r"); 
    conn->connection_param = (void *) fp;
    size_t n = 0;
    if(fp != NULL)
    {
        n = fread(buf, 1, sizeof(buf), fp);
        mg_send_data(conn, buf, n);
        if(n < sizeof(buf) || conn->wsbits != 0)
        {
            fclose(fp);
            conn->connection_param = NULL;
        }
    }
return 1;
}

我曾尝试在这段代码中放入print语句,但它们不会打印到控制台,因为它们在单独的线程中运行。有人能给我一些关于为什么会发生这种segfault的见解,或者关于如何提高代码效率的建议吗。

我应该注意,这段代码可以在1和10MB的文件上正常工作,但不能在更大的文件上工作。

永远不要这样做:

int size = ftell(fp);
char buf[size];

您是在STACK上创建大小,而不是在堆上。。。。堆栈上的100MB将不起作用。

而且。。。size必须是一个常量,而不是来自ftell()的数字。我甚至不知道它是如何编译的。。。

您必须使用malloc()new运算符来分配内存。

static int fileTransfer(struct mg_connection *conn, char * filename){
    FILE *fp = fopen(filename, "r"); 
    fseek(fp, 0, SEEK_END);
    int size = ftell(fp);
    char * buf = new char[size];  // fix also here!
    fclose(fp); 
    // This is an attempt to stop a segment fault from rewind. 
    fp = fopen(filename, "r"); 
    conn->connection_param = (void *) fp;
    size_t n = 0;
    if(fp != NULL)
    {
        n = fread(buf, 1, size, fp); // fix also here!
        mg_send_data(conn, buf, n);
        if(n < size || conn->wsbits != 0)
        {
            fclose(fp);
            conn->connection_param = NULL;
        }
    }
    delete [] buf; // and you have to deallocate your buffer
    return 1;
}

您正在创建一个具有自动存储持续时间的缓冲区,这意味着它将通过g++放在堆栈上。我所知道的任何操作系统的默认堆栈大小都低于100MB,这意味着它将在支持它们的系统上导致segfault。

尝试用动态存储持续时间分配缓冲区,这将把它放在堆上。

发生的事情实际上是这个网站的名字!基本上,发生的事情是你的程序被创建了——它为堆栈分配了一定数量的内存。

创建char buf[size]时,使用的是称为可变长度数组(VLA)的C99功能。这将在堆栈上为buf分配空间。但是,buf对于堆栈来说太大,所以您的程序会失败。

为了解决此问题,您应该先使用char * buf;,然后执行buf = malloc(size)。这将把buf放在堆上,堆比堆栈大。它还允许您通过检查malloc()是否返回NULL来检查您是否没有足够的内存。不过,在退出之前,您需要确保free(buf)

附带说明一下,您可以使用ulimit -s命令检查堆栈上有多少空间。

这似乎需要在堆栈上分配很多。如果你把它堆起来呢?

char *buf = new char[size];

使用std::vector。这样就不会有堆栈空间的问题,也不会有编写非标准C++代码的其他问题:

#include <vector>
//...
static int fileTransfer(struct mg_connection *conn, char * filename)
{
    FILE *fp = fopen(filename, "r"); 
    fseek(fp, 0, SEEK_END);
    int size = ftell(fp);
    std::vector<char> buf(size);
    fclose(fp); 
    fp = fopen(filename, "r"); 
    conn->connection_param = (void *) fp;
    size_t n = 0;
    if(fp != NULL)
    {
        n = fread(&buf[0], 1, buf.size(), fp);
        mg_send_data(conn, &buf[0], n);
        if(n < buf.size() || conn->wsbits != 0)
        {
            fclose(fp);
            conn->connection_param = NULL;
        }
    }
    return 1;
}