2016-01-23 2 views
-2

У меня есть ошибка сегментации в следующем коде (на _answers.push_back(tmp);).std :: vector segv из-за невероятного повреждения

Gdb сказал

(gdb) p tmp 
$7 = "HTTP/1.0 200 OK\r\nContent-Type: text/plain; charset=UTF-8\r\nSet-Cookie: color=black;path=/\r\nSet-Cookie: code=f69a2d941420d23be97bbb1ae963295647a91c4f3faf9c5fa80727399927d9d5;path=/\r\nSet-Cookie: game=c1e"... 
(gdb) call _answers.size() 
$8 = 271275648142580811 

Так что я предполагаю, что массив был поврежден. Но я не знаю, где это произошло.

// Network.hpp 
#pragma once 

#include <utility> 
#include <string> 
#include <vector> 
#include <boost/asio.hpp> 
#include <boost/bind.hpp> 

class Network 
{ 
    public: 
    Network(std::string const &, std::string const &); 
    ~Network() {}; 

    void init(); 
    void connect(); 
    void update(); 
    void sendQuery(const std::string); 
    bool isConnected(); 
    void reset(); 

    std::string getAnswer(); 

    void handleRead(const boost::system::error_code &, size_t); 
    void handleWrite(const boost::system::error_code &); 

    boost::asio::io_service _io_service; 

    private: 
    boost::asio::ip::tcp::resolver _resolver; 
    boost::asio::ip::tcp::socket _sock; 
    boost::asio::ip::tcp::resolver::iterator _it; 
    char _buff[2048]; 
    std::vector<std::string> _answers; 
    std::string const &_host; 
    std::string const &_port; 
    bool _answered; 
}; 

// Network.cpp 
Network::Network(std::string const &host, std::string const &port) : _resolver(_io_service), _sock(_io_service), _host(host), _port(port), _answered(true) {} 

void Network::connect() { 
    _answers.reserve(2048); 
    boost::asio::ip::tcp::resolver::query query(_host, _port); 
    boost::asio::ip::tcp::resolver::iterator iterator = _resolver.resolve(query); 
    boost::asio::connect(_sock.lowest_layer(), iterator); 
} 

void Network::handleRead(const boost::system::error_code &err, size_t bread) { 
    _answered = true; 
    if (err && err.value() != 2) 
    throw Gomoku::NetworkException(err.message()); 
    if (bread > 0) { 
    std::string tmp(_buff); 
    _answers.push_back(tmp); 
    } 
    memset(_buff, 0, 2048); 
} 

void Network::handleWrite(const boost::system::error_code &err) { 
    if (err) 
    throw Gomoku::NetworkException(err.message()); 
} 

void Network::reset() { 
    _io_service.poll(); 
    _io_service.reset(); 
    _answers.clear(); 
    _answered = true; 
} 

void Network::sendQuery(const std::string req) { 
    _io_service.poll(); 
    _io_service.reset(); 
    if (_answered == 0) 
    return; 
    _answered = false; 
    connect(); 
    const char *str = new char[req.length()]; 
    str = req.c_str(); 
    boost::asio::async_write(_sock, boost::asio::buffer(str, req.length()), boost::bind(&Network::handleWrite, this, boost::asio::placeholders::error)); 
    boost::asio::async_read(_sock, boost::asio::buffer(_buff, 2048), boost::bind(&Network::handleRead, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); 
} 

std::string Network::getAnswer() { 
    if (_answers.empty()) 
    return ""; 
    std::string tmp = _answers.back(); 
    _answers.pop_back(); 
    return tmp; 
} 

// Player.cpp 
Player::Player(std::string const &host, std::string const &port) : _network(host, port) { 
    _myTurn = false; 
    _whiteScore = _blackScore = 0; 
    _host = host + ":" + port; 
    initMap(); 
} 

void Player::connect() { 
    std::string str = "GET /players/connect/ HTTP/1.0\r\nHost: " + _host + "\r\nAccept: */*\r\n\r\n"; 
    _network.sendQuery(str); 
} 

void Player::sendClick(std::pair<int, int> click, std::string const &header) { 
    std::stringstream ss; 
    ss << "POST /game/play/" << click.first << "/" << click.second << header << _cookie << "\r\n\r\n"; 
    std::string req = ss.str(); 
    _network.sendQuery(req); 
    _network._io_service.run(); 
    _network._io_service.reset(); 
    std::string ans = _network.getAnswer(); 
    parseAnswer(ans); 
    req = "GET /game/map.txt" + header + _cookie + "\r\n\r\n"; 
    _network.sendQuery(req); 
} 

Я также видел следующий код, следуя SEGV след (basic_string.h: 400):

: _M_dataplus(_M_local_data(), __str._M_get_allocator()) // TODO A traits 
+1

Ваша ошибка может иметь отношение к 'std :: string tmp (_buff); _answers.push_back (tmp); ', но удобно, вы не показали нам, как эта переменная была объявлена ​​или инициализирована. Пожалуйста, укажите полный, минимальный, компилируемый пример, который показывает эту ошибку. –

+1

'const char * str = new char [req.length()]; str = req.c_str(); 'Это утечка памяти. Кроме того, 'req' является параметром by-value, поэтому в основном является локальной переменной. Он выходит из сферы действия сразу после возвращения этой функции. – PaulMcKenzie

+0

Полный минимальный пример: я беру 4 файла. Но в любом случае _buff является допустимым символом [2048] с его \ 0 в конце и обрабатывается только '' 'boost :: asio :: async_read (_sock, boost :: asio :: buffer (_buff, 2048) , boost :: bind (& Network :: handleRead, this, boost :: asio :: placeholders :: error, boost :: asio :: placeholders :: bytes_transferred)); '' ' То же самое для _answers, ведьма - это простой std :: vector , обрабатывается только в этом файле. все переменные с «_XXX» - это переменные экземпляра, объявленные в заголовке – Arthur

ответ

2

На первый взгляд: std::string tmp(_buff); это неправильно, потому что _buff не может быть нулем, таким образом, чтение 271275648142580811 байтов в память.

Кроме того, параметр sendQuery является локальной строкой, поэтому, как только функция завершается, строка освобождается, а async_write продолжает читать из недопустимой памяти, что является неопределенным поведением. Все может случиться.

Кроме того, все запросы используют один и тот же входящий буфер, поэтому, если несколько экземпляров происходят одновременно, вы получаете неопределенное или бесполезное поведение.

+0

_buff имеет нулевой конец (проверено через gdb). – Arthur

+1

Нет, _buf _usually_ null завершено. Но не всегда. –

+1

@Arthur Если вы не затронете проблему утечки памяти и использования локальной переменной, оба указали вам ответ выше и мой комментарий, все остальное, с чем вы сталкиваетесь, является спорным. – PaulMcKenzie