std::vector segv,因为不可能的损坏



我在以下代码中有一个分段错误(在 _answers.push_back(tmp); 上)。

格德布 说

(gdb) p tmp
$7 = "HTTP/1.0 200 OKrnContent-Type: text/plain; charset=UTF-8rnSet-Cookie: color=black;path=/rnSet-Cookie: code=f69a2d941420d23be97bbb1ae963295647a91c4f3faf9c5fa80727399927d9d5;path=/rnSet-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.0rnHost: " + _host + "rnAccept: */*rnrn";
  _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 << "rnrn";
  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 + "rnrn";
  _network.sendQuery(req);
}

我还通过遵循 segv 跟踪 (basic_string.h:400) 看到了以下代码:

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

乍一看:std::string tmp(_buff);是错误的,因为_buff可能不会以 null 终止,从而将 271275648142580811 字节读取到内存中。

此外,sendQuery 的参数是一个本地字符串,因此一旦函数退出,该字符串就会被释放,并且async_write继续从无效内存中读取,这是未定义的行为。任何事情都可能发生。

此外,所有请求都使用相同的传入缓冲区,因此如果同时发生多个请求,则会得到未定义或无用的行为。

最新更新