@@ -37,6 +37,7 @@ pub(crate) trait Constrainable {
3737 fn write_file_name ( & self , arena : ArenaPtr , out : & mut String ) ;
3838 fn git_status ( & self ) -> Option < git2:: Status > ;
3939 fn write_relative_path ( & self , arena : ArenaPtr , out : & mut String ) ;
40+ fn is_overflow ( & self ) -> bool ;
4041}
4142
4243/// Windows stores paths with `\\`; `/` comes from user queries.
@@ -163,12 +164,13 @@ pub(crate) fn apply_constraints<'a, T: Constrainable + Sync>(
163164 items : & ' a [ T ] ,
164165 constraints : & [ Constraint < ' _ > ] ,
165166 arena : ArenaPtr ,
167+ overflow_arena : ArenaPtr ,
166168) -> Option < Vec < & ' a T > > {
167169 if constraints. is_empty ( ) {
168170 return None ;
169171 }
170- let plan = ConstraintPlan :: build ( constraints, items, arena) ;
171- Some ( plan. run ( items, arena) )
172+ let plan = ConstraintPlan :: build ( constraints, items, arena, overflow_arena ) ;
173+ Some ( plan. run ( items, arena, overflow_arena ) )
172174}
173175
174176#[ cfg( feature = "zlob" ) ]
@@ -217,6 +219,7 @@ impl<'q, 'c> ConstraintPlan<'q, 'c> {
217219 constraints : & ' c [ Constraint < ' q > ] ,
218220 items : & [ T ] ,
219221 arena : ArenaPtr ,
222+ overflow_arena : ArenaPtr ,
220223 ) -> Self {
221224 let mut extensions = SmallVec :: new ( ) ;
222225 let mut rest = SmallVec :: new ( ) ;
@@ -227,22 +230,28 @@ impl<'q, 'c> ConstraintPlan<'q, 'c> {
227230 }
228231 }
229232 let has_pre_filter = !extensions. is_empty ( ) || rest. iter ( ) . any ( |& c| !is_glob_node ( c) ) ;
230- let glob = build_glob_strategy ( & rest, has_pre_filter, items, arena) ;
233+ let glob = build_glob_strategy ( & rest, has_pre_filter, items, arena, overflow_arena ) ;
231234 Self {
232235 extensions,
233236 rest,
234237 glob,
235238 }
236239 }
237240
238- fn run < ' a , T : Constrainable + Sync > ( & self , items : & ' a [ T ] , arena : ArenaPtr ) -> Vec < & ' a T > {
241+ fn run < ' a , T : Constrainable + Sync > (
242+ & self ,
243+ items : & ' a [ T ] ,
244+ arena : ArenaPtr ,
245+ overflow_arena : ArenaPtr ,
246+ ) -> Vec < & ' a T > {
239247 if items. len ( ) >= PAR_THRESHOLD {
240248 use rayon:: prelude:: * ;
241249 items
242250 . par_iter ( )
243251 . enumerate ( )
244252 . map_init ( ConstraintsBuffers :: new, |scratch, ( i, item) | {
245- self . matches ( item, i, arena, scratch) . then_some ( item)
253+ self . matches ( item, i, arena, overflow_arena, scratch)
254+ . then_some ( item)
246255 } )
247256 . flatten ( )
248257 . collect ( )
@@ -251,7 +260,10 @@ impl<'q, 'c> ConstraintPlan<'q, 'c> {
251260 items
252261 . iter ( )
253262 . enumerate ( )
254- . filter_map ( |( i, item) | self . matches ( item, i, arena, & mut scratch) . then_some ( item) )
263+ . filter_map ( |( i, item) | {
264+ self . matches ( item, i, arena, overflow_arena, & mut scratch)
265+ . then_some ( item)
266+ } )
255267 . collect ( )
256268 }
257269 }
@@ -262,8 +274,17 @@ impl<'q, 'c> ConstraintPlan<'q, 'c> {
262274 item : & T ,
263275 index : usize ,
264276 arena : ArenaPtr ,
277+ overflow_arena : ArenaPtr ,
265278 scratch : & mut ConstraintsBuffers ,
266279 ) -> bool {
280+ // Overflow items' path chunks live in the overflow arena; reading them
281+ // through the base arena dereferences a wrong (possibly null) pointer.
282+ let arena = if item. is_overflow ( ) {
283+ overflow_arena
284+ } else {
285+ arena
286+ } ;
287+
267288 if !self . passes_extensions ( item, arena, scratch) {
268289 return false ;
269290 }
@@ -442,14 +463,15 @@ fn build_glob_strategy<T: Constrainable>(
442463 has_pre_filter : bool ,
443464 items : & [ T ] ,
444465 arena : ArenaPtr ,
466+ overflow_arena : ArenaPtr ,
445467) -> GlobStrategy {
446468 if !contains_glob ( rest) {
447469 return GlobStrategy :: None ;
448470 }
449471 if has_pre_filter {
450472 return GlobStrategy :: Inline ( compile_globs ( rest) ) ;
451473 }
452- let buf = PathBuffer :: collect ( items, arena) ;
474+ let buf = PathBuffer :: collect ( items, arena, overflow_arena ) ;
453475 let path_refs = buf. as_strs ( ) ;
454476 GlobStrategy :: Prepass ( precompute_masks ( rest, & path_refs) )
455477}
@@ -477,13 +499,18 @@ struct PathBuffer {
477499}
478500
479501impl PathBuffer {
480- fn collect < T : Constrainable > ( items : & [ T ] , arena : ArenaPtr ) -> Self {
502+ fn collect < T : Constrainable > ( items : & [ T ] , arena : ArenaPtr , overflow_arena : ArenaPtr ) -> Self {
481503 let mut bytes = Vec :: < u8 > :: new ( ) ;
482504 let mut offsets = Vec :: with_capacity ( items. len ( ) ) ;
483505 let mut tmp = String :: with_capacity ( 64 ) ;
484506 for item in items {
507+ let item_arena = if item. is_overflow ( ) {
508+ overflow_arena
509+ } else {
510+ arena
511+ } ;
485512 let start = bytes. len ( ) ;
486- item. write_relative_path ( arena , & mut tmp) ;
513+ item. write_relative_path ( item_arena , & mut tmp) ;
487514 bytes. extend_from_slice ( tmp. as_bytes ( ) ) ;
488515 #[ cfg( windows) ]
489516 for b in & mut bytes[ start..] {
@@ -607,6 +634,10 @@ mod tests {
607634 fn git_status ( & self ) -> Option < git2:: Status > {
608635 None
609636 }
637+
638+ fn is_overflow ( & self ) -> bool {
639+ false
640+ }
610641 }
611642
612643 #[ test]
@@ -830,13 +861,13 @@ mod tests {
830861 let mismatch = [ Constraint :: FilePath ( "트.c" ) ] ;
831862
832863 let exact_items = [ item. clone ( ) ] ;
833- let exact_matches =
834- apply_constraints ( & exact_items , & exact , arena_ptr ) . expect ( "constraints applied" ) ;
864+ let exact_matches = apply_constraints ( & exact_items , & exact , arena_ptr , arena_ptr )
865+ . expect ( "constraints applied" ) ;
835866 assert_eq ! ( exact_matches. len( ) , 1 ) ;
836867
837868 let mismatch_items = [ item] ;
838- let mismatch_matches =
839- apply_constraints ( & mismatch_items , & mismatch , arena_ptr ) . expect ( "constraints applied" ) ;
869+ let mismatch_matches = apply_constraints ( & mismatch_items , & mismatch , arena_ptr , arena_ptr )
870+ . expect ( "constraints applied" ) ;
840871 assert ! ( mismatch_matches. is_empty( ) ) ;
841872 }
842873
@@ -888,7 +919,7 @@ mod tests {
888919
889920 // Not(Glob("**/*.rs")) should exclude .rs files
890921 let constraints = vec ! [ Constraint :: Not ( Box :: new( Constraint :: Glob ( "**/*.rs" ) ) ) ] ;
891- let result = apply_constraints ( & items, & constraints, arena_ptr) . unwrap ( ) ;
922+ let result = apply_constraints ( & items, & constraints, arena_ptr, arena_ptr ) . unwrap ( ) ;
892923 let paths: Vec < & str > = result. iter ( ) . map ( |i| i. relative_path ) . collect ( ) ;
893924 assert ! (
894925 !paths. contains( & "src/main.rs" ) ,
@@ -926,15 +957,15 @@ mod tests {
926957 ] ;
927958
928959 let mixed = vec ! [ Constraint :: Extension ( "rs" ) , Constraint :: Glob ( "src/**" ) ] ;
929- let mixed_paths: Vec < & str > = apply_constraints ( & items, & mixed, arena_ptr)
960+ let mixed_paths: Vec < & str > = apply_constraints ( & items, & mixed, arena_ptr, arena_ptr )
930961 . unwrap ( )
931962 . iter ( )
932963 . map ( |i| i. relative_path )
933964 . collect ( ) ;
934965 assert_eq ! ( mixed_paths, vec![ "src/main.rs" ] ) ;
935966
936967 let pure_glob = vec ! [ Constraint :: Glob ( "src/**" ) ] ;
937- let glob_paths: Vec < & str > = apply_constraints ( & items, & pure_glob, arena_ptr)
968+ let glob_paths: Vec < & str > = apply_constraints ( & items, & pure_glob, arena_ptr, arena_ptr )
938969 . unwrap ( )
939970 . iter ( )
940971 . map ( |i| i. relative_path )
@@ -968,7 +999,7 @@ mod tests {
968999 Constraint :: Extension ( "rs" ) ,
9691000 Constraint :: Not ( Box :: new( Constraint :: Glob ( "vendor/**" ) ) ) ,
9701001 ] ;
971- let paths: Vec < & str > = apply_constraints ( & items, & constraints, arena_ptr)
1002+ let paths: Vec < & str > = apply_constraints ( & items, & constraints, arena_ptr, arena_ptr )
9721003 . unwrap ( )
9731004 . iter ( )
9741005 . map ( |i| i. relative_path )
0 commit comments