From 2ec65d5b8453cc78a02051d8541b0b765f40da32 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Tue, 3 Nov 2020 10:13:52 +0100 Subject: [PATCH] Implement Assertion properly, TID printing in debug builds --- include/Assert.h | 26 +++++++++++++++++++------- include/Client.hpp | 2 ++ include/Logger.h | 1 + src/Init/Config.cpp | 2 ++ src/Network/Auth.cpp | 2 ++ src/Network/GParser.cpp | 8 ++++++++ src/Network/Http.cpp | 5 ++++- src/Network/InitClient.cpp | 6 +++++- src/Network/Sync.cpp | 5 +++++ src/Network/TCPHandler.cpp | 4 ++++ src/logger.cpp | 8 +++++--- src/main.cpp | 5 +++++ 12 files changed, 62 insertions(+), 12 deletions(-) diff --git a/include/Assert.h b/include/Assert.h index f3bcc55..f0f8bde 100644 --- a/include/Assert.h +++ b/include/Assert.h @@ -1,9 +1,19 @@ // Author: lionkor +/* + * Asserts are to be used anywhere where assumptions about state are made + * implicitly. AssertNotReachable is used where code should never go, like in + * default switch cases which shouldn't trigger. They make it explicit + * that a place cannot normally be reached and make it an error if they do. + */ + #pragma once #include #include +#include +#include +#include #include "Logger.h" @@ -30,23 +40,25 @@ static const char* const ANSI_WHITE_BOLD = "\u001b[37;1m"; static const char* const ANSI_BOLD = "\u001b[1m"; static const char* const ANSI_UNDERLINE = "\u001b[4m"; -inline void _assert(const char* file, const char* function, unsigned line, - const char* condition_string, bool result) { +inline void _assert([[maybe_unused]] const char* file, [[maybe_unused]] const char* function, [[maybe_unused]] unsigned line, + [[maybe_unused]] const char* condition_string, [[maybe_unused]] bool result) { if (!result) { #if DEBUG - fprintf(stderr, - "%sASSERTION FAILED%s at %s%s:%u%s \n\t-> in %s%s%s, Line %u: \n\t\t-> " + std::stringstream ss; + ss << std::this_thread::get_id(); + fprintf(stdout, + "(debug build) TID %s: %sASSERTION FAILED%s at %s%s:%u%s in \n\t-> in %s%s%s, Line %u: \n\t\t-> " "Failed Condition: %s%s%s\n", - ANSI_RED_BOLD, ANSI_RESET, ANSI_UNDERLINE, file, line, ANSI_RESET, + ss.str().c_str(), ANSI_RED_BOLD, ANSI_RESET, ANSI_UNDERLINE, file, line, ANSI_RESET, ANSI_BOLD, function, ANSI_RESET, line, ANSI_RED, condition_string, ANSI_RESET); - fprintf(stderr, "%s... terminating with SIGABRT ...%s\n", ANSI_BOLD, ANSI_RESET); + fprintf(stdout, "%s... terminating with SIGABRT ...%s\n", ANSI_BOLD, ANSI_RESET); abort(); #else char buf[2048]; sprintf(buf, "%s=> ASSERTION `%s` FAILED IN RELEASE BUILD%s%s -> IGNORING FAILED ASSERTION " - "& HOPING IT WON'T CRASH%s\n", + "& HOPING IT WON'T CRASH%s", ANSI_RED_BOLD, condition_string, ANSI_RESET, ANSI_RED, ANSI_RESET); error(buf); #endif diff --git a/include/Client.hpp b/include/Client.hpp index 11f5c1f..9c6bfa6 100644 --- a/include/Client.hpp +++ b/include/Client.hpp @@ -10,6 +10,7 @@ #define SOCKET int #endif #include "Buffer.h" +#include "Assert.h" #include #include #include @@ -65,6 +66,7 @@ struct ClientInterface{ c = nullptr; } void AddClient(Client *c){ + Assert(c); Clients.insert(c); } int Size(){ diff --git a/include/Logger.h b/include/Logger.h index f3a4ea7..a8a3add 100644 --- a/include/Logger.h +++ b/include/Logger.h @@ -8,6 +8,7 @@ void InitLog(); #define DebugPrintTID(what) DebugPrintTIDInternal(what, __func__) void DebugPrintTIDInternal(const std::string& what, const std::string& func); // prints the current thread id in debug mode, to make tracing of crashes and asserts easier void ConsoleOut(const std::string& msg); +void QueueAbort(); void except(const std::string& toPrint); void debug(const std::string& toPrint); void error(const std::string& toPrint); diff --git a/src/Init/Config.cpp b/src/Init/Config.cpp index e24a744..3d91176 100644 --- a/src/Init/Config.cpp +++ b/src/Init/Config.cpp @@ -3,6 +3,7 @@ /// #include "Security/Enc.h" #include "Logger.h" +#include "Assert.h" #include #include #include @@ -77,6 +78,7 @@ std::string RemoveComments(const std::string& Line){ return Return; } void LoadConfig(std::ifstream& IFS){ + Assert(IFS.is_open()); std::string line; int index = 1; while (getline(IFS, line)) { diff --git a/src/Network/Auth.cpp b/src/Network/Auth.cpp index 2da1f9f..b2f3e9a 100644 --- a/src/Network/Auth.cpp +++ b/src/Network/Auth.cpp @@ -90,6 +90,8 @@ std::string GenerateM(RSA*key){ } void Identification(SOCKET TCPSock,Hold*S,RSA*Skey){ + Assert(S); + Assert(Skey); S->TCPSock = TCPSock; std::thread Timeout(Check,S); Timeout.detach(); diff --git a/src/Network/GParser.cpp b/src/Network/GParser.cpp index 86b7e82..9492bac 100644 --- a/src/Network/GParser.cpp +++ b/src/Network/GParser.cpp @@ -21,6 +21,7 @@ int FC(const std::string& s,const std::string& p,int n) { else return -1; } void Apply(Client*c,int VID,const std::string& pckt){ + Assert(c); std::string Packet = pckt; std::string VD = c->GetCarData(VID); Packet = Packet.substr(FC(Packet, ",", 2) + 1); @@ -31,6 +32,7 @@ void Apply(Client*c,int VID,const std::string& pckt){ } void VehicleParser(Client*c,const std::string& Pckt){ + Assert(c); if(c == nullptr || Pckt.length() < 4)return; std::string Packet = Pckt; char Code = Packet.at(1); @@ -94,10 +96,12 @@ void VehicleParser(Client*c,const std::string& Pckt){ SendToAll(c,Packet,false,true); return; default: + AssertNotReachable(); return; } } void SyncClient(Client*c){ + Assert(c); if(c->isSynced)return; c->isSynced = true; std::this_thread::sleep_for(std::chrono::seconds(1)); @@ -119,6 +123,7 @@ void SyncClient(Client*c){ info(c->GetName() + Sec(" is now synced!")); } void ParseVeh(Client*c, const std::string& Packet){ + Assert(c); #ifdef __WIN32 __try{ VehicleParser(c,Packet); @@ -129,6 +134,7 @@ void ParseVeh(Client*c, const std::string& Packet){ } void HandleEvent(Client*c ,const std::string&Data){ + Assert(c); std::stringstream ss(Data); std::string t,Name; int a = 0; @@ -149,6 +155,7 @@ void HandleEvent(Client*c ,const std::string&Data){ } void GlobalParser(Client*c, const std::string& Pack){ + Assert(c); [[maybe_unused]] static int lastRecv = 0; if(Pack.empty() || c == nullptr)return; std::string Packet = Pack.substr(0,Pack.find(char(0))); @@ -196,6 +203,7 @@ void GlobalParser(Client*c, const std::string& Pack){ } void GParser(Client*c, const std::string& Packet){ + Assert(c); #ifdef __WIN32 __try{ GlobalParser(c, Packet); diff --git a/src/Network/Http.cpp b/src/Network/Http.cpp index e95e5c7..b46e5c2 100644 --- a/src/Network/Http.cpp +++ b/src/Network/Http.cpp @@ -3,6 +3,7 @@ /// #define CURL_STATICLIB #include "Curl/curl.h" +#include "Assert.h" #include static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp){ ((std::string*)userp)->append((char*)contents, size * nmemb); @@ -13,6 +14,7 @@ std::string HttpRequest(const std::string& IP,int port){ CURLcode res; std::string readBuffer; curl = curl_easy_init(); + Assert(curl); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, IP.c_str()); curl_easy_setopt(curl, CURLOPT_PORT, port); @@ -30,6 +32,7 @@ std::string PostHTTP(const std::string& IP,const std::string& Fields){ CURLcode res; std::string readBuffer; curl = curl_easy_init(); + Assert(curl); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, IP.c_str()); curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, Fields.size()); @@ -42,4 +45,4 @@ std::string PostHTTP(const std::string& IP,const std::string& Fields){ if(res != CURLE_OK)return "-1"; } return readBuffer; -} \ No newline at end of file +} diff --git a/src/Network/InitClient.cpp b/src/Network/InitClient.cpp index e194e15..a31c0f1 100644 --- a/src/Network/InitClient.cpp +++ b/src/Network/InitClient.cpp @@ -24,6 +24,7 @@ int OpenID(){ return ID; } void Respond(Client*c, const std::string& MSG, bool Rel){ + Assert(c); char C = MSG.at(0); if(Rel || C == 'W' || C == 'Y' || C == 'V' || C == 'E'){ if(C == 'O' || C == 'T' || MSG.length() > 1000)SendLarge(c,MSG); @@ -31,6 +32,7 @@ void Respond(Client*c, const std::string& MSG, bool Rel){ }else UDPSend(c,MSG); } void SendToAll(Client*c, const std::string& Data, bool Self, bool Rel){ + Assert(c); char C = Data.at(0); for(Client*client : CI->Clients){ if(client != nullptr) { @@ -55,6 +57,7 @@ void UpdatePlayers(){ SendToAll(nullptr, Packet,true,true); } void OnDisconnect(Client*c,bool kicked){ + Assert(c); info(c->GetName() + Sec(" Connection Terminated")); if(c == nullptr)return; std::string Packet; @@ -73,6 +76,7 @@ void OnDisconnect(Client*c,bool kicked){ CI->RemoveClient(c); ///Removes the Client from existence } void OnConnect(Client*c){ + Assert(c); info(Sec("Client connected")); c->SetID(OpenID()); info(Sec("Assigned ID ") + std::to_string(c->GetID()) + Sec(" to ") + c->GetName()); @@ -82,4 +86,4 @@ void OnConnect(Client*c){ Respond(c,"M"+MapName,true); //Send the Map on connect info(c->GetName() + Sec(" : Connected")); TriggerLuaEvent(Sec("onPlayerJoining"),false,nullptr,new LuaArg{{c->GetID()}},false); -} \ No newline at end of file +} diff --git a/src/Network/Sync.cpp b/src/Network/Sync.cpp index e76cca1..75d5018 100644 --- a/src/Network/Sync.cpp +++ b/src/Network/Sync.cpp @@ -14,6 +14,7 @@ #endif // __linux void STCPSend(Client* c, std::string Data) { + Assert(c); if (c == nullptr) return; ssize_t BytesSent = send(c->GetTCPSock(), Data.c_str(), size_t(Data.size()), 0); @@ -28,6 +29,7 @@ void STCPSend(Client* c, std::string Data) { } } void SendFile(Client* c, const std::string& Name) { + Assert(c); info(c->GetName() + Sec(" requesting : ") + Name.substr(Name.find_last_of('/'))); struct stat Info {}; if (stat(Name.c_str(), &Info) != 0) { @@ -61,6 +63,7 @@ void SendFile(Client* c, const std::string& Name) { } void Parse(Client* c, const std::string& Packet) { + Assert(c); if (c == nullptr || Packet.empty()) return; char Code = Packet.at(0), SubCode = 0; @@ -84,6 +87,7 @@ void Parse(Client* c, const std::string& Packet) { } } bool STCPRecv(Client* c) { + Assert(c); if (c == nullptr) return false; char buf[200]; @@ -109,6 +113,7 @@ bool STCPRecv(Client* c) { } void SyncResources(Client* c) { + Assert(c); if (c == nullptr) return; try { diff --git a/src/Network/TCPHandler.cpp b/src/Network/TCPHandler.cpp index 1765fba..50364b8 100644 --- a/src/Network/TCPHandler.cpp +++ b/src/Network/TCPHandler.cpp @@ -8,6 +8,7 @@ #include void TCPSend(Client*c,const std::string&Data){ + Assert(c); if(c == nullptr)return; std::string Send = "\n" + Data.substr(0,Data.find(char(0))) + "\n"; ssize_t Sent = send(c->GetTCPSock(), Send.c_str(), size_t(Send.size()), 0); @@ -19,6 +20,7 @@ void TCPSend(Client*c,const std::string&Data){ } } void TCPHandle(Client*c,const std::string& data){ + Assert(c); #ifdef __WIN32 __try{ #endif // __WIN32 @@ -30,6 +32,7 @@ void TCPHandle(Client*c,const std::string& data){ #endif // __WIN32 } void TCPRcv(Client*c){ + Assert(c); if(c == nullptr || c->GetStatus() < 0)return; char buf[4096]; size_t len = 4096; @@ -53,6 +56,7 @@ void TCPRcv(Client*c){ TCPHandle(c,Buf); } void TCPClient(Client*c){ + Assert(c); if(c->GetTCPSock() == -1){ CI->RemoveClient(c); return; diff --git a/src/logger.cpp b/src/logger.cpp index 2e3f3fd..2fa24e2 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -11,9 +11,11 @@ #include void DebugPrintTIDInternal(const std::string& what, const std::string& func) { - std::stringstream ss; - ss << "Thread '" << std::this_thread::get_id() << "' in " << func << " is " << what; - debug(ss.str()); + // we need to print to cout here as we might crash before all console output is handled, + // due to segfaults or asserts. +#ifdef DEBUG + std::cout << "(debug build) Thread '" << std::this_thread::get_id() << "' in " << func << " is " << what << std::endl; +#endif // DEBUG } std::string getDate() { diff --git a/src/main.cpp b/src/main.cpp index ec81acd..5b7fd09 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,17 +1,22 @@ #include "Startup.h" +#include "Assert.h" #include #include [[noreturn]] void loop(){ + DebugPrintTID("test loop"); while(true){ std::cout.flush(); + Assert(false); std::this_thread::sleep_for(std::chrono::milliseconds(600)); } } int main(int argc, char* argv[]) { + DebugPrintTID("main"); #ifdef DEBUG std::thread t1(loop); t1.detach(); #endif + Assert(false); ConsoleInit(); InitServer(argc,argv); InitConfig();