Refine section on progress tracking.
This commit is contained in:
parent
954f971ddf
commit
b690ebac69
48
README.md
48
README.md
@ -26,11 +26,11 @@ Features
|
|||||||
* Re-entrant scripting [`Engine`] can be made `Send + Sync` (via the [`sync`] feature).
|
* Re-entrant scripting [`Engine`] can be made `Send + Sync` (via the [`sync`] feature).
|
||||||
* Sand-boxed - the scripting [`Engine`], if declared immutable, cannot mutate the containing environment unless explicitly permitted (e.g. via a `RefCell`).
|
* Sand-boxed - the scripting [`Engine`], if declared immutable, cannot mutate the containing environment unless explicitly permitted (e.g. via a `RefCell`).
|
||||||
* Rugged (protection against [stack-overflow](#maximum-call-stack-depth) and [runaway scripts](#maximum-number-of-operations) etc.).
|
* Rugged (protection against [stack-overflow](#maximum-call-stack-depth) and [runaway scripts](#maximum-number-of-operations) etc.).
|
||||||
* Track script evaluation [progress](#tracking-progress) and manually terminate a script run.
|
* Track script evaluation [progress](#tracking-progress-and-force-terminate-script-run) and manually terminate a script run.
|
||||||
* [`no-std`](#optional-features) support.
|
* [`no-std`](#optional-features) support.
|
||||||
* [Function overloading](#function-overloading).
|
* [Function overloading](#function-overloading).
|
||||||
* [Operator overloading](#operator-overloading).
|
* [Operator overloading](#operator-overloading).
|
||||||
* Organize code base with dynamically-loadable [Modules].
|
* Organize code base with dynamically-loadable [modules].
|
||||||
* Scripts are [optimized](#script-optimization) (useful for template-based machine-generated scripts) for repeated evaluations.
|
* Scripts are [optimized](#script-optimization) (useful for template-based machine-generated scripts) for repeated evaluations.
|
||||||
* Support for [minimal builds](#minimal-builds) by excluding unneeded language [features](#optional-features).
|
* Support for [minimal builds](#minimal-builds) by excluding unneeded language [features](#optional-features).
|
||||||
* Very few additional dependencies (right now only [`num-traits`](https://crates.io/crates/num-traits/)
|
* Very few additional dependencies (right now only [`num-traits`](https://crates.io/crates/num-traits/)
|
||||||
@ -2434,8 +2434,8 @@ engine.set_module_resolver(None);
|
|||||||
Ruggedization - protect against DoS attacks
|
Ruggedization - protect against DoS attacks
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
|
|
||||||
For scripting systems open to user-land scripts, it is always best to limit the amount of resources used by a script
|
For scripting systems open to untrusted user-land scripts, it is always best to limit the amount of resources used by
|
||||||
so that it does not consume more resources that it is allowed to.
|
a script so that it does not consume more resources that it is allowed to.
|
||||||
|
|
||||||
The most important resources to watch out for are:
|
The most important resources to watch out for are:
|
||||||
|
|
||||||
@ -2476,38 +2476,46 @@ A good rule-of-thumb is that one simple non-trivial expression consumes on avera
|
|||||||
One _operation_ can take an unspecified amount of time and real CPU cycles, depending on the particulars.
|
One _operation_ can take an unspecified amount of time and real CPU cycles, depending on the particulars.
|
||||||
For example, loading a constant consumes very few CPU cycles, while calling an external Rust function,
|
For example, loading a constant consumes very few CPU cycles, while calling an external Rust function,
|
||||||
though also counted as only one operation, may consume much more computing resources.
|
though also counted as only one operation, may consume much more computing resources.
|
||||||
If it helps to visualize, think of an _operation_ as roughly equals to one _instruction_ of a hypothetical CPU.
|
To help visualize, think of an _operation_ as roughly equals to one _instruction_ of a hypothetical CPU
|
||||||
|
which includes _specialized_ instructions, such as _function call_, _load module_ etc., each taking up
|
||||||
|
one CPU cycle to execute.
|
||||||
|
|
||||||
The _operation count_ is intended to be a very course-grained measurement of the amount of CPU that a script
|
The _operations count_ is intended to be a very course-grained measurement of the amount of CPU that a script
|
||||||
is consuming, and allows the system to impose a hard upper limit.
|
has consumed, allowing the system to impose a hard upper limit on computing resources.
|
||||||
|
|
||||||
A script exceeding the maximum operations count will terminate with an error result.
|
A script exceeding the maximum operations count terminates with an error result.
|
||||||
This check can be disabled via the [`unchecked`] feature for higher performance
|
This can be disabled via the [`unchecked`] feature for higher performance (but higher risks as well).
|
||||||
(but higher risks as well).
|
|
||||||
|
|
||||||
### Tracking progress
|
### Tracking progress and force-terminate script run
|
||||||
|
|
||||||
To track script evaluation progress and to force-terminate a script prematurely (for any reason),
|
It is impossible to know when, or even whether, a script run will end
|
||||||
provide a closure to the `Engine::on_progress` method:
|
(a.k.a. the [Halting Problem](http://en.wikipedia.org/wiki/Halting_problem)).
|
||||||
|
When dealing with third-party untrusted scripts that may be malicious, to track evaluation progress and
|
||||||
|
to force-terminate a script prematurely (for any reason), provide a closure to the `Engine::on_progress` method:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
engine.on_progress(|&count| { // 'count' is the number of operations performed
|
engine.on_progress(|&count| { // parameter is '&u64' - number of operations already performed
|
||||||
if count % 1000 == 0 {
|
if count % 1000 == 0 {
|
||||||
println!("{}", count); // print out a progress log every 1,000 operations
|
println!("{}", count); // print out a progress log every 1,000 operations
|
||||||
}
|
}
|
||||||
true // return 'true' to continue the script
|
true // return 'true' to continue running the script
|
||||||
// returning 'false' will terminate the script
|
// return 'false' to immediately terminate the script
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
The closure passed to `Engine::on_progress` will be called once every operation.
|
The closure passed to `Engine::on_progress` will be called once for every operation.
|
||||||
Return `false` to terminate the script immediately.
|
Return `false` to terminate the script immediately.
|
||||||
|
|
||||||
|
Notice that the _operations count_ value passed into the closure does not indicate the _percentage_ of work
|
||||||
|
already done by the script (and thus it is not real _progress_ tracking), because it is impossible to determine
|
||||||
|
how long a script may run. It is possible, however, to calculate this percentage based on an estimated
|
||||||
|
total number of operations for a typical run.
|
||||||
|
|
||||||
### Maximum number of modules
|
### Maximum number of modules
|
||||||
|
|
||||||
Rhai by default does not limit how many [modules] are loaded via the [`import`] statement.
|
Rhai by default does not limit how many [modules] can be loaded via [`import`] statements.
|
||||||
This can be changed via the `Engine::set_max_modules` method, with zero being unlimited (the default).
|
This can be changed via the `Engine::set_max_modules` method, with zero being unlimited (the default).
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
@ -2528,7 +2536,7 @@ Rhai by default limits function calls to a maximum depth of 128 levels (16 level
|
|||||||
This limit may be changed via the `Engine::set_max_call_levels` method.
|
This limit may be changed via the `Engine::set_max_call_levels` method.
|
||||||
|
|
||||||
When setting this limit, care must be also taken to the evaluation depth of each _statement_
|
When setting this limit, care must be also taken to the evaluation depth of each _statement_
|
||||||
within the function. It is entirely possible for a malicous script to embed an recursive call deep
|
within the function. It is entirely possible for a malicous script to embed a recursive call deep
|
||||||
inside a nested expression or statement block (see [maximum statement depth](#maximum-statement-depth)).
|
inside a nested expression or statement block (see [maximum statement depth](#maximum-statement-depth)).
|
||||||
|
|
||||||
The limit can be disabled via the [`unchecked`] feature for higher performance
|
The limit can be disabled via the [`unchecked`] feature for higher performance
|
||||||
@ -2627,7 +2635,7 @@ For example, in the following:
|
|||||||
|
|
||||||
```rust
|
```rust
|
||||||
{
|
{
|
||||||
let x = 999; // NOT eliminated: Rhai doesn't check yet whether a variable is used later on
|
let x = 999; // NOT eliminated: variable may be used later on (perhaps even an 'eval')
|
||||||
123; // eliminated: no effect
|
123; // eliminated: no effect
|
||||||
"hello"; // eliminated: no effect
|
"hello"; // eliminated: no effect
|
||||||
[1, 2, x, x*2, 5]; // eliminated: no effect
|
[1, 2, x, x*2, 5]; // eliminated: no effect
|
||||||
|
@ -1 +0,0 @@
|
|||||||
theme: jekyll-theme-slate
|
|
Loading…
Reference in New Issue
Block a user