std::vector segv 因为不太可能的损坏
std::vector segv because of an improbable corruption
我在以下代码中存在分段错误(在 _answers.push_back(tmp);
上)。
gdb 说
(gdb) p tmp
= "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()
= 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
乍一看:std::string tmp(_buff);
是错误的,因为_buff
可能不是空终止的,因此将271275648142580811字节读入内存。
此外,sendQuery 的参数是一个本地字符串,所以一旦函数退出,字符串就会被释放,并且 async_write 继续从无效内存中读取,这是未定义的行为。什么事都有可能发生。
此外,所有请求都使用相同的传入缓冲区,因此如果多个请求同时发生,则会出现未定义或无用的行为。
我在以下代码中存在分段错误(在 _answers.push_back(tmp);
上)。
gdb 说
(gdb) p tmp
= "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()
= 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
乍一看:std::string tmp(_buff);
是错误的,因为_buff
可能不是空终止的,因此将271275648142580811字节读入内存。
此外,sendQuery 的参数是一个本地字符串,所以一旦函数退出,字符串就会被释放,并且 async_write 继续从无效内存中读取,这是未定义的行为。什么事都有可能发生。
此外,所有请求都使用相同的传入缓冲区,因此如果多个请求同时发生,则会出现未定义或无用的行为。