@@ -113,12 +113,14 @@ SQVM::SQVM(SQSharedState *ss)
_lasterror = _null_;
_errorhandler = _null_;
_debughook = _null_;
_can_suspend = false;
_in_stackoverflow = false;
_ops_till_suspend = 0;
_ops_till_suspend_error_threshold = INT64_MIN;
_ops_till_suspend_error_label = nullptr;
_callsstack = nullptr;
_callsstacksize = 0;
_alloccallsstacksize = 0;
_top = 0;
_stackbase = 0;
ci = nullptr;
@@ -741,12 +743,16 @@ exception_restore:
//
{
for(;;)
DecreaseOps(1);
if (ShouldSuspend()) { _suspended = SQTrue; _suspended_traps = traps; return true; }
if (IsOpsTillSuspendError()) {
Raise_Error(fmt::format("excessive CPU usage in {}", _ops_till_suspend_error_label));
SQ_THROW();
}
const SQInstruction &_i_ = *ci->_ip++;
#ifdef _DEBUG_DUMP
dumpstack(_stackbase);
printf("%s %d %d %d %d\n",g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3);
#endif
@@ -165,19 +165,26 @@ public:
SQInteger _suspended_target;
SQInteger _suspended_traps;
VarArgs _suspend_varargs;
SQBool _can_suspend;
SQInteger _ops_till_suspend;
SQInteger _ops_till_suspend_error_threshold;
const char *_ops_till_suspend_error_label;
SQBool _in_stackoverflow;
bool ShouldSuspend()
return _can_suspend && _ops_till_suspend <= 0;
bool IsOpsTillSuspendError()
return _ops_till_suspend < _ops_till_suspend_error_threshold;
void DecreaseOps(SQInteger amount)
if (_ops_till_suspend - amount < _ops_till_suspend) _ops_till_suspend -= amount;
};
@@ -8,13 +8,15 @@
/** @file script_list.cpp Implementation of ScriptList. */
#include "../../stdafx.h"
#include "script_list.hpp"
#include "script_controller.hpp"
#include "../../debug.h"
#include "../../core/backup_type.hpp"
#include "../../script/squirrel.hpp"
#include <../squirrel/sqvm.h>
#include "../../safeguards.h"
/**
* Base class for any ScriptList sorter.
*/
@@ -863,12 +865,20 @@ SQInteger ScriptList::Valuate(HSQUIRRELV
/* Don't allow docommand from a Valuator, as we can't resume in
* mid C++-code. */
bool backup_allow = ScriptObject::GetAllowDoCommand();
ScriptObject::SetAllowDoCommand(false);
/* Limit the total number of ops that can be consumed by a valuate operation */
SQInteger new_ops_error_threshold = vm->_ops_till_suspend_error_threshold;
if (vm->_ops_till_suspend_error_threshold == INT64_MIN) {
new_ops_error_threshold = vm->_ops_till_suspend - MAX_VALUATE_OPS;
vm->_ops_till_suspend_error_label = "valuator function";
AutoRestoreBackup ops_error_threshold_backup(vm->_ops_till_suspend_error_threshold, new_ops_error_threshold);
/* Push the function to call */
sq_push(vm, 2);
for (ScriptListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) {
/* Check for changing of items. */
int previous_modification_count = this->modifications;
@@ -10,12 +10,15 @@
#ifndef SCRIPT_LIST_HPP
#define SCRIPT_LIST_HPP
#include "script_object.hpp"
/** Maximum number of operations allowed for valuating a list. */
static const int MAX_VALUATE_OPS = 500000;
class ScriptListSorter;
* Class that creates a list which can keep item/value pairs, which you can walk.
* @api ai game
@@ -12,12 +12,14 @@
#include "script_group.hpp"
#include "script_map.hpp"
#include "script_station.hpp"
#include "../../depot_map.h"
#include "../../vehicle_base.h"
#include "../../train.h"
ScriptVehicleList::ScriptVehicleList(HSQUIRRELVM vm)
EnforceDeityOrCompanyModeValid_Void();
@@ -38,12 +40,20 @@ ScriptVehicleList::ScriptVehicleList(HSQ
/* Limit the total number of ops that can be consumed by a filter operation, if a filter function is present */
if (nparam >= 1 && vm->_ops_till_suspend_error_threshold == INT64_MIN) {
vm->_ops_till_suspend_error_label = "vehicle filter function";
for (const Vehicle *v : Vehicle::Iterate()) {
if (v->owner != ScriptObject::GetCompany() && !ScriptCompanyMode::IsDeity()) continue;
if (!v->IsPrimaryVehicle() && !(v->type == VEH_TRAIN && ::Train::From(v)->IsFreeWagon())) continue;
if (nparam < 1) {
/* No filter, just add the item. */
Status change: