Skip to content

Commit 94f869c

Browse files
karthiknadigCopilot
andcommitted
fix: count duplicate brace alternatives toward work limit
Address Copilot review on #541 by charging every alternative before allocation and deduplication. Add exact-budget and public-API regressions and clarify the documented work-step bound. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 56a0d62 commit 94f869c

2 files changed

Lines changed: 30 additions & 2 deletions

File tree

‎crates/pet-fs/src/glob.rs‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,12 @@ fn expand_braces_bounded(pattern: &str, limit: usize) -> Result<Vec<String>, Glo
168168
if let Some((open, close)) = group {
169169
expanded = true;
170170
for alternative in pattern[open + 1..close].split(',') {
171+
if steps == MAX_BRACE_EXPANSION_STEPS {
172+
return Err(GlobExpansionError::BraceWorkLimitExceeded {
173+
limit: MAX_BRACE_EXPANSION_STEPS,
174+
});
175+
}
176+
steps += 1;
171177
let variant =
172178
format!("{}{alternative}{}", &pattern[..open], &pattern[close + 1..]);
173179
if unique.insert(variant.clone()) {
@@ -743,6 +749,27 @@ mod tests {
743749
));
744750
}
745751

752+
#[test]
753+
fn duplicate_brace_alternatives_count_toward_work_limit() {
754+
let within_limit = format!("{{{}}}", vec!["a"; MAX_BRACE_EXPANSION_STEPS - 2].join(","));
755+
assert_eq!(expand_braces_bounded(&within_limit, 1).unwrap(), vec!["a"]);
756+
757+
let over_limit = format!("{{{}}}", vec!["a"; MAX_BRACE_EXPANSION_STEPS].join(","));
758+
assert_eq!(
759+
expand_braces_bounded(&over_limit, 1).unwrap_err(),
760+
GlobExpansionError::BraceWorkLimitExceeded {
761+
limit: MAX_BRACE_EXPANSION_STEPS
762+
},
763+
);
764+
assert_eq!(
765+
expand_glob_patterns_bounded(&[PathBuf::from(over_limit)], bounded_limits(1, 1))
766+
.unwrap_err(),
767+
GlobExpansionError::BraceWorkLimitExceeded {
768+
limit: MAX_BRACE_EXPANSION_STEPS
769+
},
770+
);
771+
}
772+
746773
#[test]
747774
fn bounded_expansion_reports_malformed_and_limited_patterns() {
748775
assert!(matches!(

‎docs/JSONRPC.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,9 @@ refreshes with the same normalized expanded paths, options, and configuration ge
187187
join one operation; different options or generations do not.
188188

189189
Expansion allows at most 1,024 distinct brace-expanded patterns and 10,000
190-
filesystem candidates per request. Brace expansion also stops after 10,000 intermediate
191-
patterns per input pattern. Invalid patterns, traversal failures, or exceeded
190+
filesystem candidates per request. Brace expansion also stops after 10,000 work steps
191+
per input pattern, counting each pending pattern and each alternative before formatting
192+
or deduplication (including duplicate alternatives). Invalid patterns, traversal failures, or exceeded
192193
limits return a JSON-RPC error (`-4`) and no partial refresh inventory. Limits are
193194
checked between filesystem entries; they are not a timeout and cannot interrupt an
194195
operating-system filesystem call already in progress.

0 commit comments

Comments
 (0)