편집 (솔루션)함수의 두 번째 호출에서 세그먼트 화 오류가 발생 했습니까?
나는 -fsanitize = 주소 & Valgrind의와 디버깅의 조언을 따랐습니다. 나는 단지 -fsanitize (전에는 들어 보지 못했던 것)를 사용하여 문제가 무엇인지 알아 냈습니다. 다른 함수에서 소멸자에 대한 호출이 있었고 객체가 두 번 파괴되었습니다. 이 시점에서 기억은 완전히 위험에 처했습니다.
도움과 다른 권장 사항에 대해서도 고마워.
나는 (CouchDB를가 HTTP API를 가지고 아파치에 의해 데이터베이스입니다) CouchDB를 소켓을 사용하여 이야기 ++ C의 코드를 쓰고 있어요. 나는 그것을 다룰 전체 클래스를 만들었고 기본적으로 연결하고 닫는 소켓 클라이언트입니다.
내 기능 중 하나는 HTTP 요청을 보낸 다음 응답을 읽고이를 사용하여 첫 번째 호출에서는 정상적으로 작동하지만 두 번째 호출에서는 실패합니다.
그러나 실패 곳은 일관성이다 때때로 그것은 반환에 SIGABORT의 문자열 함수, 다른 시간 중 하나 그것의 내부는 segfault입니다. 나는 그것이 추락 한 곳에서 신호를 보냈습니다. ->
최악의 경우는 실제로는 10 번째 시간 인 "두 번째"시간에만 실행될 때만 실패한다는 것입니다. 설명 : 클래스가 인스턴스화되면 소켓이 생성되고 sendRequest
이 8 번 호출됩니다 (항상 작동합니다), 소켓을 닫습니다. 그럼 난 명령을 수신하고 명령을 실행하는 원격 사용자 객체를 생성하는 소켓 서버를 제어하는 또 다른 클래스가, 원격 사용자 명령은 다음 DB를 조작 할 수있는 CouchDB를 클래스를 호출합니다. 명령이 처음 요청되면 작동하지만 두 번째 명령이 실패하고 프로그램이 중단됩니다.
추가 정보 : 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 나는 이것에 대해 생각하지 않았다. 문제가 될 수있는 클래스 중 하나에서 변경 사항을 수정해야합니다. 내가 어떻게 찾을 수 있는지에 대한 조언이 있으면 알려줘. – user8977154
솔직히 말해서 대부분 스 니키 (snarky)였습니다. 왜냐하면 두 가지 코드 스 니펫을 제공했기 때문에 여기서 제공된 코드를 입력 할 때 프로그램이 정상적으로 작동한다는 것을 알 수있는 방법이 없습니다. 현재 나의 의심은 당신이 생각하는만큼 많은 데이터를 반환하지 않는'recv' 콜의 행에 더 가깝다. 실패하거나 연결을 끊지 않는 recv는 0부터'sizeof (buffer)'까지 모든 값을 반환 할 수 있으므로 첫 번째 recv에는 유효한 정수 또는 청크 된 태그를 찾고 읽는 데 너무 적은 양이 포함될 수 있습니다. 또한 다음'recv'에서 찾을 것으로 예상되는 데이터를 포함 할 수 있습니다. – user4581301