Skip to content

Commit f85f5af

Browse files
Apply recursion limit without std
1 parent 75a1040 commit f85f5af

4 files changed

Lines changed: 61 additions & 47 deletions

File tree

‎.github/workflows/rust.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ jobs:
8181
uses: ./.github/actions/setup-builder
8282
with:
8383
targets: 'thumbv6m-none-eabi'
84+
- run: cargo test --release --no-default-features --test no_std_recursion
8485
- run: cargo check --no-default-features --target thumbv6m-none-eabi
8586
- run: cargo check --no-default-features --features visitor --target thumbv6m-none-eabi
8687

‎src/lib.rs‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,6 @@
159159
// Allow proc-macros to find this crate
160160
extern crate self as sqlparser;
161161

162-
#[cfg(not(feature = "std"))]
163162
extern crate alloc;
164163

165164
#[macro_use]

‎src/parser/mod.rs‎

Lines changed: 4 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -72,46 +72,25 @@ macro_rules! parser_err {
7272
mod alter;
7373
mod merge;
7474

75-
#[cfg(feature = "std")]
76-
/// Implementation [`RecursionCounter`] if std is available
7775
mod recursion {
78-
use std::cell::Cell;
79-
use std::rc::Rc;
76+
use alloc::rc::Rc;
77+
use core::cell::Cell;
8078

8179
use super::ParserError;
8280

83-
/// Tracks remaining recursion depth. This value is decremented on
84-
/// each call to [`RecursionCounter::try_decrease()`], when it reaches 0 an error will
85-
/// be returned.
86-
///
87-
/// Note: Uses an [`std::rc::Rc`] and [`std::cell::Cell`] in order to satisfy the Rust
88-
/// borrow checker so the automatic [`DepthGuard`] decrement a
89-
/// reference to the counter.
90-
///
91-
/// Note: when "recursive-protection" feature is enabled, this crate uses additional stack overflow protection
92-
/// for some of its recursive methods. See [`recursive::recursive`] for more information.
9381
pub(crate) struct RecursionCounter {
9482
remaining_depth: Rc<Cell<usize>>,
9583
}
9684

9785
impl RecursionCounter {
98-
/// Creates a [`RecursionCounter`] with the specified maximum
99-
/// depth
10086
pub fn new(remaining_depth: usize) -> Self {
10187
Self {
10288
remaining_depth: Rc::new(remaining_depth.into()),
10389
}
10490
}
10591

106-
/// Decreases the remaining depth by 1.
107-
///
108-
/// Returns [`Err`] if the remaining depth falls to 0.
109-
///
110-
/// Returns a [`DepthGuard`] which will adds 1 to the
111-
/// remaining depth upon drop;
11292
pub fn try_decrease(&self) -> Result<DepthGuard, ParserError> {
11393
let old_value = self.remaining_depth.get();
114-
// ran out of space
11594
if old_value == 0 {
11695
Err(ParserError::RecursionLimitExceeded)
11796
} else {
@@ -121,7 +100,6 @@ mod recursion {
121100
}
122101
}
123102

124-
/// Guard that increases the remaining depth by 1 on drop
125103
pub struct DepthGuard {
126104
remaining_depth: Rc<Cell<usize>>,
127105
}
@@ -131,33 +109,13 @@ mod recursion {
131109
Self { remaining_depth }
132110
}
133111
}
112+
134113
impl Drop for DepthGuard {
135114
fn drop(&mut self) {
136115
let old_value = self.remaining_depth.get();
137-
self.remaining_depth.set(old_value + 1);
138-
}
139-
}
140-
}
141-
142-
#[cfg(not(feature = "std"))]
143-
mod recursion {
144-
/// Implementation [`RecursionCounter`] if std is NOT available (and does not
145-
/// guard against stack overflow).
146-
///
147-
/// Has the same API as the std [`RecursionCounter`] implementation
148-
/// but does not actually limit stack depth.
149-
pub(crate) struct RecursionCounter {}
150-
151-
impl RecursionCounter {
152-
pub fn new(_remaining_depth: usize) -> Self {
153-
Self {}
154-
}
155-
pub fn try_decrease(&self) -> Result<DepthGuard, super::ParserError> {
156-
Ok(DepthGuard {})
116+
self.remaining_depth.set(old_value.saturating_add(1));
157117
}
158118
}
159-
160-
pub struct DepthGuard {}
161119
}
162120

163121
#[derive(PartialEq, Eq)]

‎tests/no_std_recursion.rs‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
#![cfg(not(feature = "std"))]
18+
19+
use sqlparser::dialect::GenericDialect;
20+
use sqlparser::parser::{Parser, ParserError};
21+
22+
#[test]
23+
fn with_recursion_limit_applies_without_default_features() {
24+
let dialect = GenericDialect {};
25+
let result = Parser::new(&dialect)
26+
.with_recursion_limit(1)
27+
.try_with_sql("SELECT * FROM foo WHERE (a OR (b OR (c OR d)))")
28+
.unwrap()
29+
.parse_statements();
30+
31+
assert_eq!(result, Err(ParserError::RecursionLimitExceeded));
32+
}
33+
34+
#[test]
35+
fn default_recursion_limit_applies_without_default_features() {
36+
let dialect = GenericDialect {};
37+
let sql = format!(
38+
"SELECT * FROM t WHERE {}a = 1{}",
39+
"(".repeat(200),
40+
")".repeat(200)
41+
);
42+
43+
let result = Parser::parse_sql(&dialect, &sql);
44+
45+
assert_eq!(result, Err(ParserError::RecursionLimitExceeded));
46+
}
47+
48+
#[test]
49+
fn deeply_nested_not_does_not_abort_without_default_features() {
50+
let dialect = GenericDialect {};
51+
let sql = format!("SELECT * FROM t WHERE {}a", "NOT ".repeat(1024));
52+
53+
let result = Parser::parse_sql(&dialect, &sql);
54+
55+
assert!(result.is_err());
56+
}

0 commit comments

Comments
 (0)