Fix some bugs and memory leaks in CBOT

* Added CBotStack::StackOver() calls where it was possible
  to go out-of-bounds when calling CBotStack::AddStack().
* Fixed some bugs in CBotExternalCallClass
fix-squashed-planets
melex750 2021-06-11 22:46:23 -04:00
parent 993a6adf6e
commit 309f80b25f
10 changed files with 39 additions and 26 deletions

View File

@ -137,6 +137,7 @@ bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj)
while ( p != nullptr ) while ( p != nullptr )
{ {
pile = pile->AddStack(); pile = pile->AddStack();
if (pile->StackOver()) return pj->Return(pile);
if (pile->GetState() == 1) // already done? if (pile->GetState() == 1) // already done?
{ {
if (ppVars != nullptr && ppVars[i] != nullptr) ++i; if (ppVars != nullptr && ppVars[i] != nullptr) ++i;

View File

@ -82,19 +82,23 @@ int CBotExternalCallList::DoCall(CBotToken* token, CBotVar* thisVar, CBotVar** p
CBotExternalCall* pt = m_list[token->GetString()].get(); CBotExternalCall* pt = m_list[token->GetString()].get();
if (pStack->IsCallFinished()) return true; if (thisVar == nullptr && pStack->IsCallFinished()) return true; // only for non-method external call
CBotStack* pile = pStack->AddStackExternalCall(pt);
// lists the parameters depending on the contents of the stack (pStackVar) // if this is a method call we need to use AddStack()
CBotVar* pVar = MakeListVars(ppVar, true); CBotStack* pile = (thisVar != nullptr) ? pStack->AddStack() : pStack->AddStackExternalCall(pt);
// creates a variable to the result if (pile->GetState() == 0) // the first time?
CBotVar* pResult = rettype.Eq(CBotTypVoid) ? nullptr : CBotVar::Create("", rettype); {
// lists the parameters depending on the contents of the stack
CBotVar* pVar = MakeListVars(ppVar, true);
pile->SetVar(pVar);
pile->SetVar(pVar); CBotStack* pile2 = pile->AddStack();
// creates a variable to the result
CBotStack* pile2 = pile->AddStack(); CBotVar* pResult = rettype.Eq(CBotTypVoid) ? nullptr : CBotVar::Create("", rettype);
pile2->SetVar(pResult); pile2->SetVar(pResult);
pile->IncState(); // increment state to mark this step done
}
pile->SetError(CBotNoErr, token); // save token for the position in case of error pile->SetError(CBotNoErr, token); // save token for the position in case of error
return pt->Run(thisVar, pStack); return pt->Run(thisVar, pStack);
@ -107,7 +111,8 @@ bool CBotExternalCallList::RestoreCall(CBotToken* token, CBotVar* thisVar, CBotV
CBotExternalCall* pt = m_list[token->GetString()].get(); CBotExternalCall* pt = m_list[token->GetString()].get();
CBotStack* pile = pStack->RestoreStackEOX(pt); // if this is a method call we need to use RestoreStack()
CBotStack* pile = (thisVar != nullptr) ? pStack->RestoreStack() : pStack->RestoreStackEOX(pt);
if (pile == nullptr) return true; if (pile == nullptr) return true;
pile->RestoreStack(); pile->RestoreStack();
@ -163,8 +168,7 @@ bool CBotExternalCallDefault::Run(CBotVar* thisVar, CBotStack* pStack)
return false; return false;
} }
if (result != nullptr) pStack->SetCopyVar(result); pStack->Return(pile2); // return 'result' and clear extra stack
return true; return true;
} }
@ -187,8 +191,8 @@ CBotTypResult CBotExternalCallClass::Compile(CBotVar* thisVar, CBotVar* args, vo
bool CBotExternalCallClass::Run(CBotVar* thisVar, CBotStack* pStack) bool CBotExternalCallClass::Run(CBotVar* thisVar, CBotStack* pStack)
{ {
if (pStack->IsCallFinished()) return true; assert(thisVar != nullptr);
CBotStack* pile = pStack->AddStackExternalCall(this); CBotStack* pile = pStack->AddStack();
CBotVar* args = pile->GetVar(); CBotVar* args = pile->GetVar();
CBotStack* pile2 = pile->AddStack(); CBotStack* pile2 = pile->AddStack();
@ -207,9 +211,8 @@ bool CBotExternalCallClass::Run(CBotVar* thisVar, CBotStack* pStack)
return false; return false;
} }
if (result != nullptr) pStack->SetCopyVar(result); pStack->Return(pile2); // return 'result' and clear extra stack
return true; return true;
} }
} } // namespace CBot

View File

@ -360,6 +360,7 @@ bool CBotDefClass::Execute(CBotStack* &pj)
if ( p != nullptr) while ( true ) if ( p != nullptr) while ( true )
{ {
pile2 = pile2->AddStack(); // place on the stack for the results pile2 = pile2->AddStack(); // place on the stack for the results
if (pile2->StackOver()) return pj->Return(pile2);
if ( pile2->GetState() == 0 ) if ( pile2->GetState() == 0 )
{ {
if (!p->Execute(pile2)) return false; // interrupted here? if (!p->Execute(pile2)) return false; // interrupted here?

View File

@ -445,7 +445,7 @@ bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
pile->IncState(); pile->IncState();
} }
if ( !m_block->Execute(pile) ) if (!pile->GetRetVar(m_block->Execute(pile)))
{ {
if ( pile->GetError() < 0 ) if ( pile->GetError() < 0 )
pile->SetError( CBotNoErr ); pile->SetError( CBotNoErr );

View File

@ -138,6 +138,7 @@ bool CBotInstrCall::Execute(CBotStack* &pj)
if ( p != nullptr) while ( true ) if ( p != nullptr) while ( true )
{ {
pile = pile->AddStack(); // place on the stack for the results pile = pile->AddStack(); // place on the stack for the results
if (pile->StackOver()) return pj->Return(pile);
if ( pile->GetState() == 0 ) if ( pile->GetState() == 0 )
{ {
if (!p->Execute(pile)) return false; // interrupted here? if (!p->Execute(pile)) return false; // interrupted here?

View File

@ -164,6 +164,7 @@ bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* pre
} }
ppVars[i++] = pile2->GetVar(); // construct the list of pointers ppVars[i++] = pile2->GetVar(); // construct the list of pointers
pile2 = pile2->AddStack(); // space on the stack for the result pile2 = pile2->AddStack(); // space on the stack for the result
if (pile2->StackOver()) return pj->Return(pile2);
p = p->GetNext(); p = p->GetNext();
if ( p == nullptr) break; if ( p == nullptr) break;
} }

View File

@ -189,6 +189,7 @@ bool CBotNew::Execute(CBotStack* &pj)
if (p != nullptr) while ( true) if (p != nullptr) while ( true)
{ {
pile2 = pile2->AddStack(); // space on the stack for the result pile2 = pile2->AddStack(); // space on the stack for the result
if (pile2->StackOver()) return pj->Return(pile2);
if (pile2->GetState() == 0) if (pile2->GetState() == 0)
{ {
if (!p->Execute(pile2)) return false; // interrupted here? if (!p->Execute(pile2)) return false; // interrupted here?

View File

@ -357,6 +357,7 @@ bool CBotTwoOpExpr::Execute(CBotStack* &pStack)
CBotStack* pStk2 = pStk1->AddStack(); // adds an item to the stack CBotStack* pStk2 = pStk1->AddStack(); // adds an item to the stack
// or return in case of recovery // or return in case of recovery
if (pStk2->StackOver()) return pStack->Return(pStk2);
// 2nd state, evalute right operand // 2nd state, evalute right operand
if ( pStk2->GetState() == 0 ) if ( pStk2->GetState() == 0 )
@ -514,7 +515,6 @@ bool CBotTwoOpExpr::Execute(CBotStack* &pStack)
pStk2->SetVar(result); // puts the result on the stack pStk2->SetVar(result); // puts the result on the stack
if ( err ) pStk2->SetError(err, &m_token); // and the possible error (division by zero) if ( err ) pStk2->SetError(err, &m_token); // and the possible error (division by zero)
// pStk1->Return(pStk2); // releases the stack
return pStack->Return(pStk2); // transmits the result return pStack->Return(pStk2); // transmits the result
} }

View File

@ -34,7 +34,7 @@
namespace CBot namespace CBot
{ {
CBotExternalCallList* CBotProgram::m_externalCalls = new CBotExternalCallList(); std::unique_ptr<CBotExternalCallList> CBotProgram::m_externalCalls;
CBotProgram::CBotProgram() CBotProgram::CBotProgram()
{ {
@ -395,6 +395,8 @@ int CBotProgram::GetVersion()
void CBotProgram::Init() void CBotProgram::Init()
{ {
m_externalCalls.reset(new CBotExternalCallList);
CBotProgram::DefineNum("CBotErrZeroDiv", CBotErrZeroDiv); // division by zero CBotProgram::DefineNum("CBotErrZeroDiv", CBotErrZeroDiv); // division by zero
CBotProgram::DefineNum("CBotErrNotInit", CBotErrNotInit); // uninitialized variable CBotProgram::DefineNum("CBotErrNotInit", CBotErrNotInit); // uninitialized variable
CBotProgram::DefineNum("CBotErrBadThrow", CBotErrBadThrow); // throw a negative value CBotProgram::DefineNum("CBotErrBadThrow", CBotErrBadThrow); // throw a negative value
@ -420,9 +422,10 @@ void CBotProgram::Free()
CBotToken::ClearDefineNum(); CBotToken::ClearDefineNum();
m_externalCalls->Clear(); m_externalCalls->Clear();
CBotClass::ClearPublic(); CBotClass::ClearPublic();
m_externalCalls.reset();
} }
CBotExternalCallList* CBotProgram::GetExternalCalls() const std::unique_ptr<CBotExternalCallList>& CBotProgram::GetExternalCalls()
{ {
return m_externalCalls; return m_externalCalls;
} }

View File

@ -19,11 +19,12 @@
#pragma once #pragma once
#include "CBot/CBotTypResult.h"
#include "CBot/CBotEnums.h" #include "CBot/CBotEnums.h"
#include <vector>
#include <list> #include <list>
#include <memory>
#include <string>
#include <vector>
namespace CBot namespace CBot
{ {
@ -31,6 +32,7 @@ namespace CBot
class CBotFunction; class CBotFunction;
class CBotClass; class CBotClass;
class CBotStack; class CBotStack;
class CBotTypResult;
class CBotVar; class CBotVar;
class CBotExternalCallList; class CBotExternalCallList;
@ -335,11 +337,11 @@ public:
/** /**
* \brief Returns static list of all registered external calls * \brief Returns static list of all registered external calls
*/ */
static CBotExternalCallList* GetExternalCalls(); static const std::unique_ptr<CBotExternalCallList>& GetExternalCalls();
private: private:
//! All external calls //! All external calls
static CBotExternalCallList* m_externalCalls; static std::unique_ptr<CBotExternalCallList> m_externalCalls;
//! All user-defined functions //! All user-defined functions
std::list<CBotFunction*> m_functions{}; std::list<CBotFunction*> m_functions{};
//! The entry point function //! The entry point function