Changeset - r28378:9db411cc3b19
[Not reviewed]
master
0 5 0
Jonathan G Rennison - 4 months ago 2024-01-02 18:02:12
j.g.rennison@gmail.com
Change: Limit total script ops that can be consumed by a list valuate (#11670)
5 files changed with 36 insertions and 0 deletions:
0 comments (0 inline, 0 general)
src/3rdparty/squirrel/squirrel/sqvm.cpp
Show inline comments
 
@@ -116,6 +116,8 @@ SQVM::SQVM(SQSharedState *ss)
 
	_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;
 
@@ -744,6 +746,10 @@ exception_restore:
 
		{
 
			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
src/3rdparty/squirrel/squirrel/sqvm.h
Show inline comments
 
@@ -168,6 +168,8 @@ public:
 

	
 
	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()
 
@@ -175,6 +177,11 @@ public:
 
		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;
src/script/api/script_list.cpp
Show inline comments
 
@@ -11,7 +11,9 @@
 
#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"
 

	
 
@@ -866,6 +868,14 @@ SQInteger ScriptList::Valuate(HSQUIRRELV
 
	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);
 

	
src/script/api/script_list.hpp
Show inline comments
 
@@ -13,6 +13,9 @@
 

	
 
#include "script_object.hpp"
 

	
 
/** Maximum number of operations allowed for valuating a list. */
 
static const int MAX_VALUATE_OPS = 500000;
 

	
 
class ScriptListSorter;
 

	
 
/**
src/script/api/script_vehiclelist.cpp
Show inline comments
 
@@ -15,6 +15,8 @@
 
#include "../../depot_map.h"
 
#include "../../vehicle_base.h"
 
#include "../../train.h"
 
#include "../../core/backup_type.hpp"
 
#include <../squirrel/sqvm.h>
 

	
 
#include "../../safeguards.h"
 

	
 
@@ -41,6 +43,14 @@ ScriptVehicleList::ScriptVehicleList(HSQ
 
	bool backup_allow = ScriptObject::GetAllowDoCommand();
 
	ScriptObject::SetAllowDoCommand(false);
 

	
 
	/* Limit the total number of ops that can be consumed by a filter operation, if a filter function is present */
 
	SQInteger new_ops_error_threshold = vm->_ops_till_suspend_error_threshold;
 
	if (nparam >= 1 && 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 = "vehicle filter function";
 
	}
 
	AutoRestoreBackup ops_error_threshold_backup(vm->_ops_till_suspend_error_threshold, new_ops_error_threshold);
 

	
 
	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;
0 comments (0 inline, 0 general)