Bugfix - allow 4X deeper computation by default, make limit configurable ()

This commit is contained in:
Finn Bear 2023-05-08 23:37:07 -07:00 committed by GitHub
parent bfbadc6fdd
commit 3d76645908
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 38 additions and 5 deletions
lib
src/cli

View file

@ -1,10 +1,16 @@
use once_cell::sync::Lazy;
#[cfg(not(target_arch = "wasm32"))]
#[allow(dead_code)]
/// Specifies how many concurrent jobs can be buffered in the worker channel.
pub const MAX_CONCURRENT_TASKS: usize = 64;
/// Specifies how deep various forms of computation will go before the query fails.
pub const MAX_COMPUTATION_DEPTH: u8 = 30;
///
/// For reference, use ~15 per MiB of stack in release mode.
pub const MAX_COMPUTATION_DEPTH: Lazy<u8> = Lazy::new(|| {
option_env!("SURREAL_MAX_COMPUTATION_DEPTH").and_then(|s| s.parse::<u8>().ok()).unwrap_or(120)
});
/// Specifies the names of parameters which can not be specified in a query.
pub const PROTECTED_PARAM_NAMES: &[&str] = &["auth", "scope", "token", "session"];

View file

@ -83,7 +83,7 @@ impl Options {
/// stack frame it uses relative to a simple function call). When in doubt, use a value of 1.
pub fn dive(&self, cost: u8) -> Result<Options, Error> {
let dive = self.dive.saturating_add(cost);
if dive <= cnf::MAX_COMPUTATION_DEPTH {
if dive <= *cnf::MAX_COMPUTATION_DEPTH {
Ok(Options {
auth: self.auth.clone(),
ns: self.ns.clone(),

View file

@ -184,7 +184,7 @@ fn excessive_cast_chain_depth() -> Result<(), Error> {
// Ensure a good stack size for tests
with_enough_stack(async {
// Run a casting query which will fail
let mut res = run_queries(&cast_chain(35)).await?;
let mut res = run_queries(&cast_chain(125)).await?;
//
assert_eq!(res.len(), 1);
//
@ -212,6 +212,13 @@ fn with_enough_stack(
#[allow(unused_mut)]
let mut builder = Builder::new();
// Roughly how much stack is allocated for surreal server workers in release mode
#[cfg(not(debug_assertions))]
{
builder = builder.stack_size(8_000_000);
}
// Same for debug mode
#[cfg(debug_assertions)]
{
builder = builder.stack_size(16_000_000);

View file

@ -5,9 +5,13 @@ use crate::env;
use crate::err::Error;
use crate::iam;
use crate::net;
use futures::Future;
#[tokio::main]
pub async fn init(matches: &clap::ArgMatches) -> Result<(), Error> {
pub fn init(matches: &clap::ArgMatches) -> Result<(), Error> {
with_enough_stack(init_impl(matches))
}
async fn init_impl(matches: &clap::ArgMatches) -> Result<(), Error> {
// Initialize opentelemetry and logging
crate::o11y::builder().with_log_level(matches.get_one::<String>("log").unwrap()).init();
// Check if a banner should be outputted
@ -28,3 +32,19 @@ pub async fn init(matches: &clap::ArgMatches) -> Result<(), Error> {
// All ok
Ok(())
}
/// Rust's default thread stack size of 2MiB doesn't allow sufficient recursion depth.
fn with_enough_stack<T>(fut: impl Future<Output = T> + Send) -> T {
let stack_size = 8 * 1024 * 1024;
// Stack frames are generally larger in debug mode.
#[cfg(debug_assertions)]
let stack_size = stack_size * 2;
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.thread_stack_size(stack_size)
.build()
.unwrap()
.block_on(fut)
}