[colobot] 44/100: Fix game crashing with syntax errors

Didier Raboud odyx at moszumanska.debian.org
Thu Jun 1 18:10:17 UTC 2017


This is an automated email from the git hooks/post-receive script.

odyx pushed a commit to branch debian/master
in repository colobot.

commit 2ff8251a811b6da93062bb885b8978afade0ef12
Author: melex750 <melex750 at users.noreply.github.com>
Date:   Tue Jan 24 13:47:00 2017 -0500

    Fix game crashing with syntax errors
---
 po/colobot.pot                       |  3 ++
 po/de.po                             |  3 ++
 po/fr.po                             |  3 ++
 po/pl.po                             |  3 ++
 po/ru.po                             |  3 ++
 src/CBot/CBotClass.cpp               | 25 ++++++----
 src/CBot/CBotDefParam.cpp            | 10 ++--
 src/CBot/CBotEnums.h                 |  1 +
 src/CBot/CBotInstr/CBotFunction.cpp  | 15 +++---
 src/CBot/CBotInstr/CBotListInstr.cpp |  2 +-
 src/CBot/CBotToken.cpp               |  7 +++
 src/common/restext.cpp               |  1 +
 test/unit/CBot/CBotToken_test.cpp    |  2 +-
 test/unit/CBot/CBot_test.cpp         | 90 ++++++++++++++++++++++++++++++++++++
 14 files changed, 144 insertions(+), 24 deletions(-)

diff --git a/po/colobot.pot b/po/colobot.pot
index fd5c3de..04eda13 100644
--- a/po/colobot.pot
+++ b/po/colobot.pot
@@ -1739,6 +1739,9 @@ msgstr ""
 msgid "Function needs return type \"void\""
 msgstr ""
 
+msgid "Class name expected"
+msgstr ""
+
 msgid "Dividing by zero"
 msgstr ""
 
diff --git a/po/de.po b/po/de.po
index e4c105a..440febf 100644
--- a/po/de.po
+++ b/po/de.po
@@ -356,6 +356,9 @@ msgstr ""
 msgid "Checkpoint"
 msgstr "Checkpoint"
 
+msgid "Class name expected"
+msgstr ""
+
 msgid "Climb\\Increases the power of the jet"
 msgstr "Steigen\\Leistung des Triebwerks steigern"
 
diff --git a/po/fr.po b/po/fr.po
index 905a016..98c7549 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -346,6 +346,9 @@ msgstr "Console de triche\\Montre la console de triche"
 msgid "Checkpoint"
 msgstr "Indicateur"
 
+msgid "Class name expected"
+msgstr ""
+
 msgid "Climb\\Increases the power of the jet"
 msgstr "Monter\\Augmenter la puissance du réacteur"
 
diff --git a/po/pl.po b/po/pl.po
index cd9f37c..f298098 100644
--- a/po/pl.po
+++ b/po/pl.po
@@ -348,6 +348,9 @@ msgstr "Konsola komend\\Pokaż konsolę komend"
 msgid "Checkpoint"
 msgstr "Punkt kontrolny"
 
+msgid "Class name expected"
+msgstr ""
+
 msgid "Climb\\Increases the power of the jet"
 msgstr "W górę\\Zwiększa moc silnika"
 
diff --git a/po/ru.po b/po/ru.po
index 233cb30..4042a18 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -353,6 +353,9 @@ msgstr "Консоль чит-кодов\\Показать консоль для
 msgid "Checkpoint"
 msgstr "Контрольная точка"
 
+msgid "Class name expected"
+msgstr ""
+
 msgid "Climb\\Increases the power of the jet"
 msgstr "Взлет и подъем\\Увеличивает мощность реактивного двигателя"
 
diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp
index c19cbf4..d787eb7 100644
--- a/src/CBot/CBotClass.cpp
+++ b/src/CBot/CBotClass.cpp
@@ -471,26 +471,27 @@ CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack)
 
     std::string name = p->GetString();
 
-    CBotClass* pOld = CBotClass::Find(name);
-    if ( (pOld != nullptr && pOld->m_IsDef) ||          /* public class exists in different program */
-         pStack->GetProgram()->ClassExists(name))       /* class exists in this program */
-    {
-        pStack->SetError( CBotErrRedefClass, p );
-        return nullptr;
-    }
-
     // a name of the class is there?
     if (IsOfType(p, TokenTypVar))
     {
+        CBotClass* pOld = CBotClass::Find(name);
+        if ((pOld != nullptr && pOld->m_IsDef) ||          /* public class exists in different program */
+            pStack->GetProgram()->ClassExists(name))       /* class exists in this program */
+        {
+            pStack->SetError(CBotErrRedefClass, p->GetPrev());
+            return nullptr;
+        }
+
         CBotClass* pPapa = nullptr;
         if ( IsOfType( p, ID_EXTENDS ) )
         {
             std::string name = p->GetString();
             pPapa = CBotClass::Find(name);
+            CBotToken* pp = p;
 
             if (!IsOfType(p, TokenTypVar) || pPapa == nullptr )
             {
-                pStack->SetError( CBotErrNotClass, p );
+                pStack->SetError(CBotErrNoClassName, pp);
                 return nullptr;
             }
         }
@@ -519,6 +520,9 @@ CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack)
 
         if (pStack->IsOk()) return classe;
     }
+    else
+        pStack->SetError(CBotErrNoClassName, p);
+
     pStack->SetError(CBotErrNoTerminator, p);
     return nullptr;
 }
@@ -810,10 +814,11 @@ CBotClass* CBotClass::Compile(CBotToken* &p, CBotCStack* pStack)
             // TODO: Not sure how correct is that - I have no idea how the precompilation (Compile1 method) works ~krzys_h
             std::string name = p->GetString();
             CBotClass* pPapa = CBotClass::Find(name);
+            CBotToken* pp = p;
 
             if (!IsOfType(p, TokenTypVar) || pPapa == nullptr)
             {
-                pStack->SetError( CBotErrNotClass, p );
+                pStack->SetError(CBotErrNoClassName, pp);
                 return nullptr;
             }
             pOld->m_parent = pPapa;
diff --git a/src/CBot/CBotDefParam.cpp b/src/CBot/CBotDefParam.cpp
index ff4acf1..e66c862 100644
--- a/src/CBot/CBotDefParam.cpp
+++ b/src/CBot/CBotDefParam.cpp
@@ -52,7 +52,7 @@ CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack)
     {
         CBotDefParam* list = nullptr;
 
-        while (!IsOfType(p, ID_CLOSEPAR))
+        if (!IsOfType(p, ID_CLOSEPAR)) while (true)
         {
             CBotDefParam* param = new CBotDefParam();
             if (list == nullptr) list = param;
@@ -85,10 +85,12 @@ CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack)
                     var->SetUniqNum(param->m_nIdent);
                     pStack->AddVar(var);                                // place on the stack
 
-                    if (IsOfType(p, ID_COMMA) || p->GetType() == ID_CLOSEPAR)
-                        continue;
+                    if (IsOfType(p, ID_COMMA)) continue;
+                    if (IsOfType(p, ID_CLOSEPAR)) break;
+
+                    pStack->SetError(CBotErrClosePar, p->GetStart());
                 }
-                pStack->SetError(CBotErrClosePar, p->GetStart());
+                pStack->SetError(CBotErrNoVar, p->GetStart());
             }
             pStack->SetError(CBotErrNoType, p);
             delete list;
diff --git a/src/CBot/CBotEnums.h b/src/CBot/CBotEnums.h
index b7453e5..a34c9e7 100644
--- a/src/CBot/CBotEnums.h
+++ b/src/CBot/CBotEnums.h
@@ -238,6 +238,7 @@ enum CBotError : int
     CBotErrNoExpression  = 5043, //!< expression expected after =
     CBotErrAmbiguousCall = 5044, //!< ambiguous call to overloaded function
     CBotErrFuncNotVoid   = 5045, //!< function needs return type "void"
+    CBotErrNoClassName   = 5046, //!< class name expected
 
     // Runtime errors
     CBotErrZeroDiv       = 6000, //!< division by zero
diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp
index ddbd366..f08ddd9 100644
--- a/src/CBot/CBotInstr/CBotFunction.cpp
+++ b/src/CBot/CBotInstr/CBotFunction.cpp
@@ -177,7 +177,11 @@ CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunct
                 func->m_MasterClass = pp->GetString();
                 func->m_classToken = *pp;
                 CBotClass* pClass = CBotClass::Find(pp);
-                if ( pClass == nullptr ) goto bad;
+                if ( pClass == nullptr )
+                {
+                    pStk->SetError(CBotErrNoClassName, pp);
+                    goto bad;
+                }
 
 //              pp = p;
                 func->m_token = *p;
@@ -280,13 +284,8 @@ CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClas
             if ( IsOfType( p, ID_DBLDOTS ) )        // method for a class
             {
                 func->m_MasterClass = pp->GetString();
-                CBotClass* pClass = CBotClass::Find(pp);
-                if ( pClass == nullptr )
-                {
-                    pStk->SetError(CBotErrNotClass, pp);
-                    goto bad;
-                }
-
+                // existence of the class is checked
+                // later in CBotFunction::Compile()
                 pp = p;
                 func->m_token = *p;
                 if (!IsOfType(p, TokenTypVar)) goto bad;
diff --git a/src/CBot/CBotInstr/CBotListInstr.cpp b/src/CBot/CBotInstr/CBotListInstr.cpp
index 58413a4..0ae396f 100644
--- a/src/CBot/CBotInstr/CBotListInstr.cpp
+++ b/src/CBot/CBotInstr/CBotListInstr.cpp
@@ -52,7 +52,7 @@ CBotInstr* CBotListInstr::Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal
         if (IsOfType(p, ID_SEP)) continue;              // empty statement ignored
         if (p->GetType() == ID_CLBLK) break;
 
-        if (IsOfType(p, 0))
+        if (p->GetType() == TokenTypNone)
         {
             pStack->SetError(CBotErrCloseBlock, p->GetStart());
             delete inst;
diff --git a/src/CBot/CBotToken.cpp b/src/CBot/CBotToken.cpp
index 28e6690..e10901e 100644
--- a/src/CBot/CBotToken.cpp
+++ b/src/CBot/CBotToken.cpp
@@ -439,6 +439,13 @@ std::unique_ptr<CBotToken> CBotToken::CompileTokens(const std::string& program)
         pp = p;
     }
 
+    // terminator token
+    nxt = new CBotToken();
+    nxt->m_type = TokenTypNone;
+    nxt->m_end = nxt->m_start = pos;
+    prv->m_next = nxt;
+    nxt->m_prev = prv;
+
     return std::unique_ptr<CBotToken>(tokenbase);
 }
 
diff --git a/src/common/restext.cpp b/src/common/restext.cpp
index 789c68a..93bab6c 100644
--- a/src/common/restext.cpp
+++ b/src/common/restext.cpp
@@ -720,6 +720,7 @@ void InitializeRestext()
     stringsCbot[CBot::CBotErrNoExpression]  = TR("Expression expected after =");
     stringsCbot[CBot::CBotErrAmbiguousCall] = TR("Ambiguous call to overloaded function");
     stringsCbot[CBot::CBotErrFuncNotVoid]   = TR("Function needs return type \"void\"");
+    stringsCbot[CBot::CBotErrNoClassName]   = TR("Class name expected");
 
     stringsCbot[CBot::CBotErrZeroDiv]       = TR("Dividing by zero");
     stringsCbot[CBot::CBotErrNotInit]       = TR("Variable not initialized");
diff --git a/test/unit/CBot/CBotToken_test.cpp b/test/unit/CBot/CBotToken_test.cpp
index b51ca93..a36841a 100644
--- a/test/unit/CBot/CBotToken_test.cpp
+++ b/test/unit/CBot/CBotToken_test.cpp
@@ -60,7 +60,7 @@ protected:
             ASSERT_EQ(token->GetType(), correct.type) << "type mismatch at token #" << (i+1);
             i++;
         }
-        while((token = token->GetNext()) != nullptr);
+        while((token = token->GetNext()) != nullptr && !IsOfType(token, TokenTypNone));
         ASSERT_EQ(i, data.size()) << "not enough tokens processed";
     }
 };
diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp
index ca9ff91..71455e2 100644
--- a/test/unit/CBot/CBot_test.cpp
+++ b/test/unit/CBot/CBot_test.cpp
@@ -298,6 +298,96 @@ TEST_F(CBotUT, EmptyTest)
     );
 }
 
+TEST_F(CBotUT, FunctionCompileErrors)
+{
+    ExecuteTest(
+        "public",
+        CBotErrNoType
+    );
+
+    ExecuteTest(
+        "extern",
+        CBotErrNoType
+    );
+
+    ExecuteTest(
+        "public void",
+        CBotErrNoFunc
+    );
+
+    ExecuteTest(
+        "extern void",
+        CBotErrNoFunc
+    );
+
+    ExecuteTest(
+        "extern void MissingParameterType(",
+        CBotErrNoType
+    );
+
+    ExecuteTest(
+        "extern void MissingParamName(int",
+        CBotErrNoVar
+    );
+
+    ExecuteTest(
+        "extern void MissingCloseParen(int i",
+        CBotErrClosePar
+    );
+
+    ExecuteTest(
+        "extern void ParamTrailingComma(int i, ) {\n"
+        "}\n",
+        CBotErrNoType
+    );
+
+   ExecuteTest(
+        "extern void MissingOpenBlock(int i)",
+        CBotErrOpenBlock
+    );
+
+    ExecuteTest(
+        "extern void MissingCloseBlock()\n"
+        "{\n",
+        CBotErrCloseBlock
+    );
+
+}
+
+TEST_F(CBotUT, ClassCompileErrors)
+{
+    ExecuteTest(
+        "public class",
+        CBotErrNoClassName
+    );
+
+    ExecuteTest(
+        "public class 1234",
+        CBotErrNoClassName
+    );
+
+    ExecuteTest(
+        "public class TestClass",
+        CBotErrOpenBlock
+    );
+
+    ExecuteTest(
+        "public class TestClass\n"
+        "{\n",
+        CBotErrCloseBlock
+    );
+
+    ExecuteTest(
+        "public class TestClass extends",
+        CBotErrNoClassName
+    );
+
+    ExecuteTest(
+        "public class TestClass extends 1234",
+        CBotErrNoClassName
+    );
+}
+
 TEST_F(CBotUT, DivideByZero)
 {
     ExecuteTest(

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/colobot.git



More information about the Pkg-games-commits mailing list