@@ -95,13 +95,21 @@ impl GlobalDescriptorTable {
9595
9696 /// Adds the given segment descriptor to the GDT, returning the segment selector.
9797 ///
98- /// Panics if the GDT has no free entries left .
98+ /// Panics if the GDT doesn't have enough free entries to hold the Descriptor .
9999 #[ inline]
100100 #[ cfg_attr( feature = "const_fn" , rustversion:: attr( all( ) , const ) ) ]
101101 pub fn add_entry ( & mut self , entry : Descriptor ) -> SegmentSelector {
102102 let index = match entry {
103- Descriptor :: UserSegment ( value) => self . push ( value) ,
103+ Descriptor :: UserSegment ( value) => {
104+ if self . next_free > self . table . len ( ) - 1 {
105+ panic ! ( "GDT full" )
106+ }
107+ self . push ( value)
108+ }
104109 Descriptor :: SystemSegment ( value_low, value_high) => {
110+ if self . next_free > self . table . len ( ) - 2 {
111+ panic ! ( "GDT requires two free spaces to hold a SystemSegment" )
112+ }
105113 let index = self . push ( value_low) ;
106114 self . push ( value_high) ;
107115 index
@@ -157,14 +165,10 @@ impl GlobalDescriptorTable {
157165 #[ inline]
158166 #[ cfg_attr( feature = "const_fn" , rustversion:: attr( all( ) , const ) ) ]
159167 fn push ( & mut self , value : u64 ) -> usize {
160- if self . next_free < self . table . len ( ) {
161- let index = self . next_free ;
162- self . table [ index] = value;
163- self . next_free += 1 ;
164- index
165- } else {
166- panic ! ( "GDT full" ) ;
167- }
168+ let index = self . next_free ;
169+ self . table [ index] = value;
170+ self . next_free += 1 ;
171+ index
168172 }
169173
170174 /// Creates the descriptor pointer for this table. This pointer can only be
@@ -334,6 +338,7 @@ impl Descriptor {
334338#[ cfg( test) ]
335339mod tests {
336340 use super :: DescriptorFlags as Flags ;
341+ use super :: * ;
337342
338343 #[ test]
339344 #[ rustfmt:: skip]
@@ -347,4 +352,49 @@ mod tests {
347352 assert_eq ! ( Flags :: USER_CODE32 . bits( ) , 0x00cffb000000ffff ) ;
348353 assert_eq ! ( Flags :: USER_DATA . bits( ) , 0x00cff3000000ffff ) ;
349354 }
355+
356+ // Makes a GDT that has two free slots
357+ fn make_six_entry_gdt ( ) -> GlobalDescriptorTable {
358+ let mut gdt = GlobalDescriptorTable :: new ( ) ;
359+ gdt. add_entry ( Descriptor :: kernel_code_segment ( ) ) ;
360+ gdt. add_entry ( Descriptor :: kernel_data_segment ( ) ) ;
361+ gdt. add_entry ( Descriptor :: UserSegment ( DescriptorFlags :: USER_CODE32 . bits ( ) ) ) ;
362+ gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
363+ gdt. add_entry ( Descriptor :: user_code_segment ( ) ) ;
364+ gdt
365+ }
366+
367+ static TSS : TaskStateSegment = TaskStateSegment :: new ( ) ;
368+
369+ fn make_full_gdt ( ) -> GlobalDescriptorTable {
370+ let mut gdt = make_six_entry_gdt ( ) ;
371+ gdt. add_entry ( Descriptor :: tss_segment ( & TSS ) ) ;
372+ gdt
373+ }
374+
375+ #[ test]
376+ pub fn push_max_segments ( ) {
377+ // Make sure we don't panic with user segments
378+ let mut gdt = make_six_entry_gdt ( ) ;
379+ gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
380+ gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
381+ // Make sure we don't panic with system segments
382+ let _ = make_full_gdt ( ) ;
383+ }
384+
385+ #[ test]
386+ #[ should_panic]
387+ pub fn panic_user_segment ( ) {
388+ let mut gdt = make_full_gdt ( ) ;
389+ gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
390+ }
391+
392+ #[ test]
393+ #[ should_panic]
394+ pub fn panic_system_segment ( ) {
395+ let mut gdt = make_six_entry_gdt ( ) ;
396+ gdt. add_entry ( Descriptor :: user_data_segment ( ) ) ;
397+ // We have one free slot, but the GDT requires two
398+ gdt. add_entry ( Descriptor :: tss_segment ( & TSS ) ) ;
399+ }
350400}
0 commit comments