LCOV - code coverage report
Current view: top level - source/scriptinterface - ScriptExceptions.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 30 45 66.7 %
Date: 2023-01-19 00:18:29 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /* Copyright (C) 2021 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : 
      19             : #include "precompiled.h"
      20             : 
      21             : #include "ScriptExceptions.h"
      22             : 
      23             : #include "ps/CLogger.h"
      24             : #include "ps/CStr.h"
      25             : #include "scriptinterface/FunctionWrapper.h"
      26             : #include "scriptinterface/ScriptRequest.h"
      27             : 
      28        1292 : bool ScriptException::IsPending(const ScriptRequest& rq)
      29             : {
      30        1292 :     return JS_IsExceptionPending(rq.cx);
      31             : }
      32             : 
      33         253 : bool ScriptException::CatchPending(const ScriptRequest& rq)
      34             : {
      35         253 :     if (!JS_IsExceptionPending(rq.cx))
      36         244 :         return false;
      37             : 
      38          18 :     JS::RootedValue excn(rq.cx);
      39           9 :     ENSURE(JS_GetPendingException(rq.cx, &excn));
      40           9 :     JS_ClearPendingException(rq.cx);
      41             : 
      42           9 :     if (excn.isUndefined())
      43             :     {
      44           0 :         LOGERROR("JavaScript error: (undefined)");
      45           0 :         return true;
      46             :     }
      47             : 
      48             :     // As of SM45/52, there is no way to recover a stack in case the thrown thing is not an Error object.
      49           9 :     if (!excn.isObject())
      50             :     {
      51           0 :         CStr error;
      52           0 :         Script::FromJSVal(rq, excn, error);
      53           0 :         LOGERROR("JavaScript error: %s", error);
      54           0 :         return true;
      55             :     }
      56             : 
      57          18 :     JS::RootedObject excnObj(rq.cx, &excn.toObject());
      58           9 :     JSErrorReport* report = JS_ErrorFromException(rq.cx, excnObj);
      59             : 
      60           9 :     if (!report)
      61             :     {
      62           0 :         CStr error;
      63           0 :         Script::FromJSVal(rq, excn, error);
      64           0 :         LOGERROR("JavaScript error: %s", error);
      65           0 :         return true;
      66             :     }
      67             : 
      68          18 :     std::stringstream msg;
      69           9 :     msg << "JavaScript error: ";
      70           9 :     if (report->filename)
      71             :     {
      72           2 :         msg << report->filename;
      73           2 :         msg << " line " << report->lineno << "\n";
      74             :     }
      75             : 
      76           9 :     msg << report->message().c_str();
      77             : 
      78          18 :     JS::RootedObject stackObj(rq.cx, ExceptionStackOrNull(excnObj));
      79          18 :     JS::RootedValue stackVal(rq.cx, JS::ObjectOrNullValue(stackObj));
      80             : 
      81           9 :     if (!stackVal.isNull())
      82             :     {
      83           0 :         std::string stackText;
      84           0 :         ScriptFunction::Call(rq, stackVal, "toString", stackText);
      85             : 
      86           0 :         std::istringstream stream(stackText);
      87           0 :         for (std::string line; std::getline(stream, line);)
      88           0 :             msg << "\n  " << line;
      89             :     }
      90             : 
      91           9 :     LOGERROR("%s", msg.str().c_str());
      92           9 :     return true;
      93             : }
      94             : 
      95           3 : void ScriptException::Raise(const ScriptRequest& rq, const char* format, ...)
      96             : {
      97             :     va_list ap;
      98           3 :     va_start(ap, format);
      99             :     // SM is single-threaded, so a static thread_local buffer needs no locking.
     100             :     thread_local static char buffer[256];
     101           3 :     vsprintf_s(buffer, ARRAY_SIZE(buffer), format, ap);
     102           3 :     va_end(ap);
     103             :     // Rather annoyingly, there are no va_list versions of this function, hence the preformatting above.
     104           3 :     JS_ReportErrorUTF8(rq.cx, "%s", buffer);
     105           3 : }

Generated by: LCOV version 1.13