編集(ソリューション)関数の2番目の呼び出しでセグメンテーションフォルトが発生しましたか?
私は-fsanitize =アドレス& valgrindのとデバッグのアドバイスに従ってきました。私は-fsanitize(以前は聞いたことがない)を使用し、問題が何であるかを知っただけで、別の関数のデストラクタの呼び出しが残り、オブジェクトが2度破壊されていました。この時点でメモリは完全に危険にさらされていました。
お手数をおかけしていただきありがとうございます。
私はソケット(CouchDBのは、HTTP APIを持っているApacheのことで、データベースである)を使用してのCouchDBと話をするC++のコードを書いています。私はそれに対処するためのクラス全体を作成しました。それは基本的に接続して閉じるソケットクライアントです。
私の関数の1つは、HTTPリクエストを送信して応答を読み取り、それを処理することです。最初の呼び出しで正常に動作しますが、2回目に呼び出すと失敗します。
しかし、失敗した場所では一貫性がなく、時には文字列関数の中のSEGFAULTであり、それ以外のときは戻り値のSIGABORTです。私はそれが墜落した線に信号を送りました->
そして、最悪の部分は、実際には10回目の「秒」の時間だけ実行されると失敗するということです。説明:クラスがインスタンス化されてソケットが作成されると、sendRequest
が8回呼び出されます(すべての作業、常に)、ソケットを閉じます。次に、ソケットサーバーを制御する別のクラスがあります。ソケットサーバーはコマンドを受け取り、コマンドを実行するリモートユーザーオブジェクトを作成し、リモートユーザーコマンドはCouchDBクラスを呼び出してDBを操作します。コマンドが最初に要求されると動作しますが、2番目のコマンドが失敗してプログラムがクラッシュします。
追加情報:short int httpcode
行のgdbトレースでは、substr
のクラッシュが表示され、SIGABORTクラッシュトレースではfree()
の問題が示されます。
私はすでに何度もデバッグしましたが、文字列とバッファをインスタンス化する場所と方法についていくつか変更を加えましたが、私は失われています。何度もうまく動作するのは誰でも知っていますが、その後の呼び出しでクラッシュしますか?時々
CouchDB::response CouchDB::sendRequest(std::string req_method, std::string req_doc, std::string msg)
{
std::string responseBody;
char buffer[1024];
// zero message buffer
memset(buffer, 0, sizeof(buffer));
std::ostringstream smsg;
smsg << req_method << " /" << req_doc << " HTTP/1.1\r\n"
<< "Host: " << user_agent << "\r\n"
<< "Accept: application/json\r\n"
<< "Content-Length: " << msg.size() << "\r\n"
<< (msg.size() > 0 ? "Content-Type: application/json\r\n" : "")
<< "\r\n"
<< msg;
/*std::cout << "========== Request ==========\n"
<< smsg.str() << std::endl;*/
if (sendData((void*)smsg.str().c_str(), smsg.str().size())) {
perror("@CouchDB::sendRequest, Error writing to socket");
std::cerr << "@CouchDB::sendRequest, Make sure CouchDB is running in " << user_agent << std::endl;
return {-1, "ERROR"};
}
// response
int len = recv(socketfd, buffer, sizeof(buffer), 0);
if (len < 0) {
perror("@CouchDB::sendRequest, Error reading socket");
return {-1, "ERROR"};
}
else if (len == 0) {
std::cerr << "@CouchDB::sendRequest, Connection closed by server\n";
return {-1, "ERROR"};
}
responseBody.assign(buffer);
// HTTP code is the second thing after the protocol name and version
-> short int httpcode = std::stoi(responseBody.substr(responseBody.find(" ") + 1));
bool chunked = responseBody.find("Transfer-Encoding: chunked") != std::string::npos;
/*std::cout << "========= Response =========\n"
<< responseBody << std::endl;*/
// body starts after two CRLF
responseBody = responseBody.substr(responseBody.find("\r\n\r\n") + 4);
// chunked means that the response comes in multiple packets
// we must keep reading the socket until the server tells us it's over, or an error happen
if (chunked) {
std::string chunkBody;
unsigned long size = 1;
while (size > 0) {
while (responseBody.length() > 0) {
// chunked requests start with the size of the chunk in HEX
size = std::stoi(responseBody, 0, 16);
// the chunk is on the next line
size_t chunkStart = responseBody.find("\r\n") + 2;
chunkBody += responseBody.substr(chunkStart, size);
// next chunk might be in this same request, if so, there must have something after the next CRLF
responseBody = responseBody.substr(chunkStart + size + 2);
}
if (size > 0) {
len = recv(socketfd, buffer, sizeof(buffer), 0);
if (len < 0) {
perror("@CouchDB::sendRequest:chunked, Error reading socket");
return {-1, "ERROR"};
}
else if (len == 0) {
std::cerr << "@CouchDB::sendRequest:chunked, Connection closed by server\n";
return {-1, "ERROR"};
}
responseBody.assign(buffer);
}
}
// move created body from chunks to responseBody
-> responseBody = chunkBody;
}
return {httpcode, responseBody};
}
上記とそれを呼び出す関数SIGABORT
bool CouchDB::find(Database::db db_type, std::string keyValue, std::string &value)
{
if (!createSocket()) {
return false;
}
std::ostringstream doc;
std::ostringstream json;
doc << db_name << db_names[db_type] << "/_find";
json << "{\"selector\":{" << keyValue << "},\"limit\":1,\"use_index\":\"index\"}";
-> CouchDB::response status = sendRequest("POST", doc.str(), json.str());
close(socketfd);
if (status.httpcode == 200) {
value = status.body;
return true;
}
return false;
}
あなたはについての質問かもしれませんいくつかのビット:
CouchDB::response
はstruct {httpcode: int, body: std::string}
CouchDB::db
あるenum
です異なるデータベースを選択する すべてのバイトが、それはあなたの
int len = recv(socketfd, buffer, sizeof(buffer), 0);
バッファ内の最後の
'\0'
を上書きするかもしれない作り
エラーが30分後にプログラムがクラッシュするような方法でメモリを破壊するなど、まったく別の場所ではないことをどのように知っていますか? – user4581301
@ user4581301私はこれについて考えなかった。私は何かがあるかどうかを確認するために、問題の可能性があるクラスの1つをいくつか変更する必要があります。もしあなたが私がどのようにこれを見つけることができるかについてアドバイスがあれば教えてください。 – user8977154
正直言って、あなたがコードの2つのスニペットを与えてくれて、私がここにいるのは、提供されたコードを入力するときにプログラムが正常であることを知る方法がないので、現在私の疑惑は、あなたが思っているほど多くのデータを返さない 'recv'呼び出しの行に沿っています。失敗したり切断されたりしないrecvは、0から 'sizeof(buffer)'まで任意の量を返すことができるので、最初のrecvには、有効な整数またはチャンクタグを見つけて読み出すために、また、次の 'recv'で見つけることが期待されるデータを含めることもできます。 – user4581301