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 CBotExternalCallClassfix-squashed-planets
parent
993a6adf6e
commit
309f80b25f
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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?
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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?
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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?
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue