【问题标题】:Why does this C++ member function call fail with a segmentation fault?为什么这个 C++ 成员函数调用会因分段错误而失败?
【发布时间】:2015-01-22 07:29:38
【问题描述】:

我多年来一直关注这个论坛,发现它非常有帮助,到目前为止回答了我所有的问题。但是今天我好像卡住了。

作为 C++ 新手,我尝试编写一些类来帮助我通过代理服务器连接到网站。因此,我调用了一个封装了一些逻辑来处理 HTTP 请求的类的函数。我通过引用将一个结构和另外两个参数传递给该函数。执行失败并出现分段错误(duh)。调试显示当我调用我的函数时发生分段错误。

在我的主函数中,我创建了一个在 httplayer.hpp 中声明的类的实例,并像这样调用它的一个成员:

#include "../include/httplayer.hpp"

int main(int argc,char** argv){
    HttpLayer httplayer;
    proxy_data proxy;
    proxy.username="name";
    proxy.password="pwd";
    proxy.address="some.address";
    proxy.port="8080";

    int n = httplayer.openHttpSocket("google.com",8080,proxy); //Here the catasprohy happens
    //more stuff
    return 0;
}

httplayer.hpp 文件如下所示:

#include <iostream>
#include <cstring>
#include <string>

#include "../include/commlayer.hpp"


struct proxy_data{
        std::string username, password, address, port;
};

class HttpLayer{
    public:
        static const int HTTP_BUF_SIZE = 6555648;

        int closeHttpSocket();
        int requestHttp(std::string, char*);
        int openHttpSocket(std::string, int, struct proxy_data&);

    private:
        bool endsWith(std::string const & value, std::string const & ending);
        CommLayer comm;
};

在对应的httplayer.cpp中我终于有了这个函数:

int HttpLayer::openHttpSocket(std::string address,int port,proxy_data &proxy){  

gdb 显示以下信息:

14 int n = httplayer.openHttpSocket("google.com",8080,proxy);
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
0x0804940b in HttpLayer::openHttpSocket (
    this=<error reading variable: Cannot access memory at address 0xbf37d81c>, 
address=<error reading variable: Cannot access memory at address 0xbf37d818>, port=8080, 
proxy=<error reading variable: Cannot access memory at address 0xbf37d814>)
at src/httplayer.cpp:20
20  int HttpLayer::openHttpSocket(std::string address,int port,proxy_data &proxy){

我的第一个嫌疑人是结构,但到目前为止还没有看到我的错误。我是 C++ 新手,所以我在使用类、函数或头文件的方式上可能会犯一些非常明显的错误,但我似乎无法找到自己。

非常感谢您的帮助,谢谢!

编辑:

当然,只有作为 C++ 菜鸟的我才是正确的,而有经验的社区肯定会误会。 所以我为了证明我的无限智慧所做的就是注释掉除了 printf() 之外的 openHttpSocket 的内容......但突然它起作用了。所以我开始重新部分重新包含代码,直到我偶然发现这一行:

int HttpLayer::openHttpSocket(std::string address,int port,proxy_data &proxy){
    ...
    unsigned char proxyanswer[HTTP_BUF_SIZE];
    ...
}

好吧,所有功劳都归功于@WhozCraig 的水晶球。以及其他所有要求我发布该功能的内容的人。谢谢!

现在另一个初学者的问题:我的堆栈会发生什么?以及如何创建可以在 C++ 的成员函数中使用的某种 char* 缓冲区?或者在 C++ 中是否有一个完全不同的概念可以用来代替那些好的旧 char 数组?

【问题讨论】:

  • 展示openHttpSocket方法的代码
  • 推送 s 而不是 n 并进入函数。或者提供一个显示问题而不是您认为错误的最小示例。
  • Works for me,所以问题出在你没有展示的东西上。请将您的真实代码缩小到MCVE 并发布。基本上,我们可以复制粘贴到 ideone 并自己观察行为。
  • 如果我使用 s 进入 openHttpSocket,我会立即收到相同的分段错误错误消息。因此我认为 openHttpSocket() 的内容与问题无关。为了确保我在第一行中包含了一个在段错误之前没有被击中的 printf。代码仍然相关吗,@Sergey?
  • 我要刷掉水晶球上的灰尘,然后预测您的openHttpSocket 成员中有unsigned char buff[HTTP_BUF_SIZE] 形式的缓冲区(以及boom去你的堆栈)。现在,请显示代码。

标签: c++ linux function struct segmentation-fault


【解决方案1】:

HTTP_BUF_SIZE 是 650 万。这意味着这个函数范围的变量声明:

unsigned char proxyanswer[HTTP_BUF_SIZE];

尝试在堆栈上创建大约 6MB 的缓冲区。这将在大多数默认设置下溢出堆栈。

你不想在堆栈上这么大的对象,你希望他们在堆上。在 C++ 术语中,您不希望这些在函数中具有自动存储持续时间,而是希望它们动态分配。 C++创建动态数组的方法是:

std::vector<unsigned char> proxyanswer(HTTP_BUF_SIZE);

这会动态分配内存(“在堆上”)并且几乎可以用作普通数组(支持[] 下标等)。如果您需要以指针的形式访问实际缓冲区(例如,将其传递给 C API),您可以使用proxyanswer.data()(C++11 及更高版本)或&amp;proxyanswer.front()( C++03 及以下)。

【讨论】:

  • @ChristianPanhuber 值得注意的是:std::vector&lt;&gt; 将像这样以预置大小初始化元素。 IE。它会将unsigned char() 放在每个元素中(因此用零填充它,一次一个)。这可能具有显着的性能阻抗。如果您不关心缓冲区值的初始化(即无论如何您很快就会自己填充它),请考虑使用std::unique_ptr&lt;unsigned char[]&gt; 来管理一个原始的、未初始化的缓冲区。
猜你喜欢
  • 1970-01-01
  • 2016-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-13
  • 2018-08-14
相关资源
最近更新 更多