From fef8a8e35517199a46e72806151049142166429b Mon Sep 17 00:00:00 2001 From: krzys-h Date: Tue, 15 Mar 2016 20:34:00 +0100 Subject: [PATCH] Fixes to variable list in CBot debugger * fixed stack overflow with circular references (closes #434) * fixed displaying boolean variables * fixed buffer overflows with entries longer than 100 characters * removed hard-limit to 100 entries with at most 100 characters in CList (this also allows you to have more than 100 programs in a robot, up to 999) --- src/script/script.cpp | 96 ++++++++++++-------------- src/ui/controls/list.cpp | 23 +++--- src/ui/controls/list.h | 11 ++- src/ui/screen/screen_player_select.cpp | 12 ++-- 4 files changed, 68 insertions(+), 74 deletions(-) diff --git a/src/script/script.cpp b/src/script/script.cpp index 5dda7c45..894af4af 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -490,79 +490,71 @@ bool CScript::GetCursor(int &cursor1, int &cursor2) // Put of the variables in a list. -void PutList(const char *baseName, bool bArray, CBot::CBotVar *var, Ui::CList *list, int &rankList) +void PutList(const std::string& baseName, bool bArray, CBot::CBotVar *var, Ui::CList *list, int &rankList, std::set& previous) { - CBot::CBotVar *svar, *pStatic; - char varName[100]; - char buffer[100]; - std::string p; - int index, type; - - if ( var == nullptr && baseName[0] != 0 ) + if ( var == nullptr && !baseName.empty() ) { - sprintf(buffer, "%s = null;", baseName); - list->SetItemName(rankList++, buffer); + list->SetItemName(rankList++, StrUtils::Format("%s = null;", baseName.c_str()).c_str()); return; } - index = 0; - while ( var != nullptr ) + int index = 0; + while (var != nullptr) { var->Update(nullptr); - pStatic = var->GetStaticVar(); // finds the static element + CBot::CBotVar* pStatic = var->GetStaticVar(); // finds the static element - p = pStatic->GetName(); // variable name -//? if ( strcmp(p, "this") == 0 ) -//? { -//? var = var->GetNext(); -//? continue; -//? } - - if ( baseName[0] == 0 ) + std::string varName; + if (baseName.empty()) { - sprintf(varName, "%s", p.c_str()); + varName = StrUtils::Format("%s", pStatic->GetName().c_str()); } else { - if ( bArray ) + if (bArray) { - sprintf(varName, "%s[%d]", baseName, index); + varName = StrUtils::Format("%s[%d]", baseName.c_str(), index); } else { - sprintf(varName, "%s.%s", baseName, p.c_str()); + varName = StrUtils::Format("%s.%s", baseName.c_str(), pStatic->GetName().c_str()); } } - type = pStatic->GetType(); - - if ( type < CBot::CBotTypBoolean ) + if (previous.find(pStatic) != previous.end()) { - p = pStatic->GetValString(); - sprintf(buffer, "%s = %s;", varName, p.c_str()); - list->SetItemName(rankList++, buffer); - } - else if ( type == CBot::CBotTypString ) - { - p = pStatic->GetValString(); - sprintf(buffer, "%s = \"%s\";", varName, p.c_str()); - list->SetItemName(rankList++, buffer); - } - else if ( type == CBot::CBotTypArrayPointer ) - { - svar = pStatic->GetItemList(); - PutList(varName, true, svar, list, rankList); - } - else if ( type == CBot::CBotTypClass || - type == CBot::CBotTypPointer ) - { - svar = pStatic->GetItemList(); - PutList(varName, false, svar, list, rankList); + list->SetItemName(rankList++, StrUtils::Format("%s = [circular reference]", varName.c_str()).c_str()); } else { - sprintf(buffer, "%s = ?;", varName); - list->SetItemName(rankList++, buffer); + int type = pStatic->GetType(); + + if (type <= CBot::CBotTypBoolean) + { + list->SetItemName(rankList++, StrUtils::Format("%s = %s;", varName.c_str(), pStatic->GetValString().c_str()).c_str()); + } + else if (type == CBot::CBotTypString) + { + list->SetItemName(rankList++, StrUtils::Format("%s = \"%s\";", varName.c_str(), pStatic->GetValString().c_str()).c_str()); + } + else if (type == CBot::CBotTypArrayPointer) + { + previous.insert(pStatic); + PutList(varName, true, pStatic->GetItemList(), list, rankList, previous); + previous.erase(pStatic); + } + else if (type == CBot::CBotTypClass || + type == CBot::CBotTypPointer) + { + previous.insert(pStatic); + PutList(varName, false, pStatic->GetItemList(), list, rankList, previous); + previous.erase(pStatic); + } + else + { + //list->SetItemName(rankList++, StrUtils::Format("%s = ?;", varName.c_str()).c_str()); + assert(false); + } } index ++; @@ -589,13 +581,15 @@ void CScript::UpdateList(Ui::CList* list) level = 0; rank = 0; + std::set previous; while ( true ) { var = m_botProg->GetStackVars(funcName, level--); if ( funcName != progName ) break; - PutList("", false, var, list, rank); + PutList("", false, var, list, rank, previous); } + assert(previous.empty()); if ( total == list->GetTotal() ) // same total? { diff --git a/src/ui/controls/list.cpp b/src/ui/controls/list.cpp index b446bd2f..dc4de23e 100644 --- a/src/ui/controls/list.cpp +++ b/src/ui/controls/list.cpp @@ -354,7 +354,7 @@ void CList::Draw() float dp; int i; char text[100]; - char *pb, *pe; + const char *pb, *pe; if ((m_state & STATE_VISIBLE) == 0) return; @@ -451,14 +451,14 @@ void CList::Draw() ppos.y = pos.y + dim.y * 0.5f; ppos.y -= m_engine->GetText()->GetHeight(m_fontType, m_fontSize) / 2.0f; ddim.x = dim.x-dim.y; - DrawCase(m_items[i + m_firstLine].text, ppos, ddim.x, Gfx::TEXT_ALIGN_LEFT); + DrawCase(m_items[i + m_firstLine].text.c_str(), ppos, ddim.x, Gfx::TEXT_ALIGN_LEFT); } else { ppos.x = pos.x + dim.y * 0.5f; ppos.y = pos.y + dim.y * 0.5f; ppos.y -= m_engine->GetText()->GetHeight(m_fontType, m_fontSize) / 2.0f; - pb = m_items[i + m_firstLine].text; + pb = m_items[i + m_firstLine].text.c_str(); for (int j = 0; j < 10; j++) { pe = strchr(pb, '\t'); @@ -548,7 +548,7 @@ void CList::Draw() // Displays text in a box. -void CList::DrawCase(char *text, Math::Point pos, float width, Gfx::TextAlign justif) +void CList::DrawCase(const char* text, Math::Point pos, float width, Gfx::TextAlign justif) { if (justif == Gfx::TEXT_ALIGN_CENTER) pos.x += width / 2.0f; @@ -651,18 +651,19 @@ bool CList::GetBlink() // Specifies the text of a line. -void CList::SetItemName(int i, const char* name) +void CList::SetItemName(int i, const std::string& name) { - if ( i < 0 || i >= LISTMAXTOTAL ) + if ( i < 0 ) return; if ( i >= m_totalLine ) m_totalLine = i+1; // expands the list - if ( name[0] == 0 ) - strcpy(m_items[i].text, " "); + m_items.resize(m_totalLine); + if ( name.empty() ) + m_items[i].text = " "; else - strcpy(m_items[i].text, name); + m_items[i].text = name; UpdateButton(); UpdateScroll(); @@ -670,10 +671,10 @@ void CList::SetItemName(int i, const char* name) // Returns the text of a line. -char* CList::GetItemName(int i) +const std::string& CList::GetItemName(int i) { if ( i < 0 || i >= m_totalLine ) - return nullptr; + assert(false); return m_items[i].text; } diff --git a/src/ui/controls/list.h b/src/ui/controls/list.h index 190633c1..bfebf430 100644 --- a/src/ui/controls/list.h +++ b/src/ui/controls/list.h @@ -35,7 +35,6 @@ namespace Ui { const int LISTMAXDISPLAY = 20; // maximum number of visible lines -const int LISTMAXTOTAL = 100; // maximum total number of lines @@ -71,8 +70,8 @@ public: void SetBlink(bool bEnable); bool GetBlink(); - void SetItemName(int i, const char* name); - char* GetItemName(int i); + void SetItemName(int i, const std::string& name); + const std::string& GetItemName(int i); void SetCheck(int i, bool bMode); bool GetCheck(int i); @@ -93,7 +92,7 @@ protected: void UpdateButton(); void UpdateScroll(); void MoveScroll(); - void DrawCase(char *text, Math::Point pos, float width, Gfx::TextAlign justif); + void DrawCase(const char* text, Math::Point pos, float width, Gfx::TextAlign justif); private: // Overridden to avoid warning about hiding the virtual function @@ -116,11 +115,11 @@ protected: struct Item { - char text[100] = {}; + std::string text = ""; bool check = false; bool enable = true; }; - std::array m_items; + std::vector m_items; }; diff --git a/src/ui/screen/screen_player_select.cpp b/src/ui/screen/screen_player_select.cpp index 442efad6..f6d2c8c0 100644 --- a/src/ui/screen/screen_player_select.cpp +++ b/src/ui/screen/screen_player_select.cpp @@ -153,7 +153,7 @@ bool CScreenPlayerSelect::EventProcess(const Event &event) CWindow* pw; CList* pl; std::string name; - char* gamer; + std::string gamer; switch( event.type ) { @@ -289,7 +289,7 @@ void CScreenPlayerSelect::UpdateNameList() for ( i=0 ; iGetItemName(i)) == 0 ) + if ( name == pl->GetItemName(i) ) { pl->SetSelect(i); pl->ShowSelect(false); @@ -307,7 +307,7 @@ void CScreenPlayerSelect::UpdateNameEdit() CWindow* pw; CList* pl; CEdit* pe; - char* name; + std::string name; int sel; pw = static_cast(m_interface->SearchControl(EVENT_WINDOW5)); @@ -326,8 +326,8 @@ void CScreenPlayerSelect::UpdateNameEdit() else { name = pl->GetItemName(sel); - pe->SetText(name); - pe->SetCursor(strlen(name), 0); + pe->SetText(name.c_str()); + pe->SetCursor(name.length(), 0); } UpdateNameControl(); @@ -434,7 +434,7 @@ void CScreenPlayerSelect::NameDelete() return; } - char* gamer = pl->GetItemName(sel); + std::string gamer = pl->GetItemName(sel); m_main->SelectPlayer(gamer); if (!m_main->GetPlayerProfile()->Delete())