std :: string copy构造函数seg fault

时间:2011-01-05 23:47:01

标签: c++ string segmentation-fault

在构造结构时会发生这种情况,我的代码: 此行http://wklej.org/hash/c42680a7f9d/txt/http://wklej.org/hash/5fefcecc371/txt/回溯:http://wklej.org/id/451070/txt/ 任何帮助都是适当的 对不起,我没有在这里复制代码,所以我把它发布在任何其他网站上;(

4 个答案:

答案 0 :(得分:2)

使用调试器并获得堆栈跟踪。

问题几乎可以肯定是将错误的C字符串传递给std :: string构造函数。也许指针无效或C字符串没有终止,构造函数读入受保护的内存。

但是如果没有更多信息,我无法分辨出错误是什么。调试器应该立即指出它。

此外,您的Socket包含指针,但只定义构造函数和析构函数。您还需要一个复制构造函数和赋值运算符。如果不应该发生这两个操作,那么将它们定义为private而没有实现。

另外,我从你的回溯中看到,这是GCC的旧版本。这个版本可能没有使std :: string在多线程程序中安全使用的修复程序。我不知道什么时候修复了,但libstdc ++库的一些旧版本没有锁定字符串上的引用计数,并且当不同的线程释放字符串内存同时也写入它时可能会崩溃。

答案 1 :(得分:2)

我已将您的代码放在此处,以便能够对其进行编辑:

#ifdef _WIN32
    #define _WIN32_WINNT 0x0501
#endif

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/noncopyable.hpp>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <sstream>
#include <string>

#ifdef assert
    #undef assert
#endif

#define assert(x)\
    if (!x) { \
        std::clog << "[Error - __FUNCTION__] Asseration to: " << #x << " failed. line: " << __LINE__ << ", file: " << __FILE__ << "." << std::endl;\
        std::exit(100);\
    }

template<typename _Tp>
inline std::string toString(_Tp __p)
{
    std::stringstream ss;
    ss << __p;
    std::string ret;
    ss >> ret;
    return ret;
}

struct Proxy;

typedef std::vector<Proxy*> ProxyVec;

struct Proxy
{
    std::string name;
    uint32_t port;
};

ProxyVec loadProxies(const std::string& fileName)
{
    std::FILE *f = fopen(fileName.c_str(), "r");
    if (!f) {
        std::clog << "[Error - loadProxies] Cannot open: " << fileName << "." << std::endl;
        delete f;
        f = NULL;
        return ProxyVec();
    }

    char buffer[1024];
    ProxyVec ret;
    int32_t __n = 0;
    while (fgets(buffer, sizeof(buffer), f)) {
        ++__n;
        std::string str(buffer);
        if (str.find("\n") != std::string::npos)
            str = str.substr(0, str.length()-1);

        if (str.find("\r") != std::string::npos)
            str = str.substr(0, str.length()-1);

        size_t sep = str.rfind(":");
        if (sep == std::string::npos) {
            std::clog << "[Error - loadProxies] Cannot load proxy #" << __n << "." << std::endl;
            continue;
        }

        std::string hostname = str.substr(0, sep);
        uint32_t port = static_cast<uint32_t>(std::atoi(str.substr(sep+1, str.length()-sep).c_str()));
        std::clog << "Loading proxy: " << hostname << ":" << port << "." << std::endl;
        Proxy proxy;
        proxy.name = hostname;
        proxy.port = port;
        ret.push_back(&proxy);
    }
    std::clog << "Loaded: " << __n << " proxies." << std::endl;
    return ret;
}

class Socket
{
    public:
        Socket(boost::asio::io_service& service, const std::string& host, 
            const std::string& port, const std::string& targetHost, const std::string& targetPort);
        ~Socket();

        void write(const std::string& message);
        std::string receivedData() const;
        bool connected() const;
        void receive();
        void handle();

    private:
        struct SocketData
        {
            SocketData(boost::asio::io_service& service, const std::string& _host, const std::string& _port,
                const std::string& _targetHost, const std::string& _targetPort):
                socket(service),
                write(service),
                read(service),
                resolver(service),
                buffers(),
                host(_host),
                port(_port),
                targetHost(_targetHost),
                targetPort(_targetPort),
                connected(false)
            {
            }
            boost::asio::ip::tcp::socket socket;
            boost::asio::io_service::strand write, read;
            boost::asio::ip::tcp::resolver resolver;
            boost::array<char, 1024> buffers;
            std::string host, port;
            std::string targetHost, targetPort;
            bool connected;
        };
            // FIXME: Use shared_ptr instead.
        SocketData* d;

    protected:
        //handle resolve func
        void handle_resolve(const boost::system::error_code&,
            boost::asio::ip::tcp::resolver::iterator);

        //handle connection func
        void handle_connect(const boost::system::error_code&,
            boost::asio::ip::tcp::resolver::iterator);

        //handle write func
        void handle_write(const boost::system::error_code&, size_t);

        //handle read func
        void handle_read(const boost::system::error_code&, size_t);

    private:
        void connectionThread();
};

Socket::Socket(boost::asio::io_service& service, const std::string& host, const std::string& port,
    const std::string& targetHost, const std::string& targetPort)
    : d(new SocketData(service, host, port, targetHost, targetPort))
{
    boost::thread thread(boost::bind(&Socket::connectionThread, this));
    // FIXME: This function is blocking. The constructur will never exit.
    //        Use thread_group.join_all() as last line in main() instead.
    thread.join();
}

Socket::~Socket()
{
    d->socket.close();
    delete d;
    d = NULL;
}

void Socket::connectionThread()
{
    if (!d)
        return;

    if (d->connected)
        return;

    boost::asio::ip::tcp::resolver::query query(d->host, d->port);
    d->resolver.async_resolve(query,
        boost::bind(&Socket::handle_resolve, this,
            boost::asio::placeholders::error,
                boost::asio::placeholders::iterator));
}

void Socket::handle_resolve(const boost::system::error_code& e,
    boost::asio::ip::tcp::resolver::iterator ep_iter)
{
    if (!e) {
        boost::asio::ip::tcp::endpoint iter = *ep_iter;
        d->socket.async_connect(iter,
            boost::bind(&Socket::handle_connect, this,
                boost::asio::placeholders::error, ++ep_iter));
    } else {
        std::clog << "[Error - Socket::handle_resolve] " << e.message() << "." << std::endl;
    }
}

void Socket::handle_connect(const boost::system::error_code& e,
    boost::asio::ip::tcp::resolver::iterator ep_iter)
{
    if (!e) {
        std::cout << "[Notice - Socket::handle_connect] Connected to host." << std::endl;
        d->connected = true;
        write("CONNECT " + d->targetHost + ":" + d->targetPort + " HTTP/1.1\r\n\r\n");
        receive();
    } else if (ep_iter != boost::asio::ip::tcp::resolver::iterator()) {
        d->socket.close();
        boost::asio::ip::tcp::endpoint ep = *ep_iter;
        d->socket.async_connect(ep,
            boost::bind(&Socket::handle_connect, this,
                boost::asio::placeholders::error, ++ep_iter));
    } else {
        std::clog << "[Error - Server::handle_connect] " << e.message() << "." << std::endl;
    }
}

void Socket::handle_write(const boost::system::error_code& e,
    size_t bytes)
{
    assert(!e || bytes < 0);
}

void Socket::handle_read(const boost::system::error_code& e,
    size_t bytes)
{
    assert(!e || bytes < 0);
    std::cout << receivedData() << std::endl;
    receive();
}

void Socket::write(const std::string& message)
{
    boost::asio::async_write(d->socket, boost::asio::buffer(message),
        d->write.wrap(
            boost::bind(&Socket::handle_write, this,
                boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred)));
}

std::string Socket::receivedData() const
{
    return std::string(d->buffers.data());
}

void Socket::receive()
{
    d->socket.async_read_some(boost::asio::buffer(d->buffers),
        d->read.wrap(
            boost::bind(&Socket::handle_read, this,
                boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred)));
}

void Socket::handle()
{
    assert(!d->targetHost.empty());
    assert(!d->targetPort.empty());

    std::string str(d->buffers.data());
    std::clog << "Received: " << str << "." << std::endl;
    if (str.substr(0, 4) == "PING")
        write("PO" + str.substr(2) + "\r\n");
    else if (str.find("MODE") != std::string::npos)
        write("JOIN #OTland\r\n");
    else if (str.find("JOIN") != std::string::npos)
        write("PRIVMSG #OTland :Hello\r\n");
}

bool Socket::connected() const
{
    return d->connected;
}

void handler(const std::string& fileName, const std::string& host, const std::string& port, uint32_t threads);

int main(int argc, char **argv)
{
    if (argc < 5) {
        std::clog << "[Error - main] Usage: " << argv[0] << " <proxy_file> <host> <port> <threads>" << std::endl;
        return 1;
    }

    std::string file(argv[1]);
    std::string host(argv[2]);
    std::string port(argv[3]);
    uint32_t threads = static_cast<uint32_t>(std::atoi(argv[4]));
    if (!threads)
        threads = 1;

    for (uint32_t __i = 0; __i < threads; ++__i)
            // FIXME: Use the thread.join() there.
        handler(file, host, port, threads);
}

typedef std::vector<Socket*> SocketVec;

void handler(const std::string& fileName, const std::string& host,
    const std::string& port, uint32_t threads)
{
    assert(!fileName.empty());
    assert(!host.empty());
    assert(!port.empty());

    ProxyVec proxies = loadProxies(fileName);
    assert(proxies.size());

    SocketVec sockets;
    for (ProxyVec::const_iterator it = proxies.begin(); it != proxies.end(); ++it) {
        boost::asio::io_service io;
        Socket socket(io, (*it)->name, toString((*it)->port), host, port);
            // FIXME: socket is a local variable and it's address is invalid outside
            //        this loop -> memory leak -> seg-fault.
        sockets.push_back(&socket);
    }

    for (SocketVec::const_iterator it = sockets.begin(); it != sockets.end(); ++it) {
        if (!(*it)->connected())
            continue;

        (*it)->handle();
    }
    // FIXME: I'm not sure if I understand this architecture. A new thread is
    //        started with this function as handler ? Who waits until this new created
    //        thread is finished ? Where is the join() ?
    (void) new boost::thread(boost::bind(handler, fileName, host, port, threads));
}

答案 2 :(得分:1)

我认为这不是您唯一的问题,但在handler的这个代码段中,您将在堆栈中创建Socket个对象。您创建的每个Socket对象将在for循环结束时销毁。这意味着sockets向量中的对象是无效对象。这样做也可能会破坏内存堆,足以产生您所看到的错误。

SocketVec sockets;
for (ProxyVec::const_iterator it = proxies.begin(); it != proxies.end(); ++it) {
    boost::asio::io_service io;
    Socket socket(io, (*it)->name, toString((*it)->port), host, port);
    sockets.push_back(&socket);
}

将其更改为:

SocketVec sockets;
for (ProxyVec::const_iterator it = proxies.begin(); it != proxies.end(); ++it) {
    boost::asio::io_service io;
    Socket* socket = new Socket(io, (*it)->name, toString((*it)->port), host, port);
    sockets.push_back(socket);
}

答案 3 :(得分:0)

这个答案最初是对Dan's答案的评论,但在看了你的代码后,我觉得有必要给出一个完整的答案。您真的需要仔细查看Boost.Asio examples并了解它们的工作原理。特别注意异步示例,看起来你并没有掌握对象生命周期的概念以及处理程序的工作方式。特别是,您应该在跳转到多个线程之前掌握单线程程序。当你已经征服了它时,你应该使用一个线程池来调用io_service::run而不是每个线程io_service。它最终将使您的程序逻辑更容易理解。

您还应该查看valgrind,您的代码中存在大量错误,例如:

==19853== Invalid read of size 4
==19853==    at 0x10000D0E4: handler(std::string const&, std::string const&, std::string const&, unsigned int) (in ./a.out)
==19853==    by 0x10000D5E6: main (in ./a.out)
==19853==  Address 0x7fff5fbff398 is not stack'd, malloc'd or (recently) free'd