1use std::{cmp::Ordering, fmt, mem};
4
5#[allow(unused_imports)]
6use core_extensions::{matches, SelfOps};
7
8use std::{
9 borrow::Borrow,
10 cell::Cell,
11 collections::hash_map::{Entry, HashMap},
12};
13
14use crate::{
15 abi_stability::{
16 extra_checks::{
17 ExtraChecksBox, ExtraChecksError, ExtraChecksRef, TypeChecker, TypeCheckerMut,
18 },
19 ConstGeneric,
20 },
21 prefix_type::{FieldAccessibility, FieldConditionality},
22 sabi_types::{CmpIgnored, ParseVersionError, VersionStrings},
23 std_types::{RArc, RBox, RBoxError, RErr, RNone, ROk, RResult, RSome, RStr, RVec, UTypeId},
24 traits::IntoReprC,
25 type_layout::{
26 tagging::TagErrors, FmtFullType, IncompatibleWithNonExhaustive, IsExhaustive, ReprAttr,
27 TLData, TLDataDiscriminant, TLDiscriminant, TLEnum, TLField, TLFieldOrFunction, TLFunction,
28 TLNonExhaustive, TLPrimitive, TypeLayout,
29 },
30 type_level::downcasting::TD_Opaque,
31 utils::{max_by, min_max_by},
32};
33
34mod errors;
35
36pub use self::errors::{
37 AbiInstability, AbiInstability as AI, AbiInstabilityError, AbiInstabilityErrors,
38 ExtraCheckError,
39};
40
41#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
45#[repr(C)]
46enum FieldContext {
47 Fields,
48 Subfields,
49 PhantomFields,
50}
51
52#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
55#[repr(C)]
56struct CheckingUTypeId {
57 type_id: UTypeId,
58}
59
60impl CheckingUTypeId {
61 fn new(this: &'static TypeLayout) -> Self {
62 Self {
63 type_id: this.get_utypeid(),
64 }
65 }
66}
67
68#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
71pub enum CheckingState {
72 Checking { layer: u32 },
73 Compatible,
74 Error,
75}
76
77#[derive(Debug, PartialEq, Eq, Clone)]
81#[repr(C)]
82pub struct ExpectedFound<T> {
83 pub expected: T,
84 pub found: T,
85}
86
87#[allow(clippy::missing_const_for_fn)]
88impl<T> ExpectedFound<T> {
89 pub fn new<O, F>(this: O, other: O, mut field_getter: F) -> ExpectedFound<T>
90 where
91 F: FnMut(O) -> T,
92 {
93 ExpectedFound {
94 expected: field_getter(this),
95 found: field_getter(other),
96 }
97 }
98
99 pub fn as_ref(&self) -> ExpectedFound<&T> {
100 ExpectedFound {
101 expected: &self.expected,
102 found: &self.found,
103 }
104 }
105
106 pub fn map<F, U>(self, mut f: F) -> ExpectedFound<U>
107 where
108 F: FnMut(T) -> U,
109 {
110 ExpectedFound {
111 expected: f(self.expected),
112 found: f(self.found),
113 }
114 }
115
116 pub fn display_str(&self) -> Option<ExpectedFound<String>>
117 where
118 T: fmt::Display,
119 {
120 Some(self.as_ref().map(|x| format!("{:#}", x)))
121 }
122
123 pub fn debug_str(&self) -> Option<ExpectedFound<String>>
124 where
125 T: fmt::Debug,
126 {
127 Some(self.as_ref().map(|x| format!("{:#?}", x)))
128 }
129}
130
131#[derive(Debug)]
134#[repr(C)]
135pub struct CheckedPrefixTypes {
136 this: &'static TypeLayout,
137 this_prefix: __PrefixTypeMetadata,
138 other: &'static TypeLayout,
139 other_prefix: __PrefixTypeMetadata,
140}
141
142#[derive(Debug, Copy, Clone)]
143#[repr(C)]
144pub struct NonExhaustiveEnumWithContext {
145 layout: &'static TypeLayout,
146 enum_: TLEnum,
147 nonexhaustive: &'static TLNonExhaustive,
148}
149
150#[derive(Debug, Clone)]
151#[repr(C)]
152pub struct ExtraChecksBoxWithContext {
153 t_lay: &'static TypeLayout,
154 o_lay: &'static TypeLayout,
155 extra_checks: ExtraChecksBox,
156}
157
158#[derive(Debug, Copy, Clone)]
159#[repr(C)]
160pub struct CheckedNonExhaustiveEnums {
161 this: NonExhaustiveEnumWithContext,
162 other: NonExhaustiveEnumWithContext,
163}
164
165struct AbiChecker {
168 stack_trace: RVec<ExpectedFound<TLFieldOrFunction>>,
169 checked_prefix_types: RVec<CheckedPrefixTypes>,
170 checked_nonexhaustive_enums: RVec<CheckedNonExhaustiveEnums>,
171 checked_extra_checks: RVec<ExtraChecksBoxWithContext>,
172
173 visited: HashMap<(CheckingUTypeId, CheckingUTypeId), CheckingState>,
174
175 errors: RVec<AbiInstabilityError>,
176
177 current_layer: u32,
189
190 error_index: usize,
191}
192
193impl AbiChecker {
196 fn new() -> Self {
197 Self {
198 stack_trace: RVec::new(),
199 checked_prefix_types: RVec::new(),
200 checked_nonexhaustive_enums: RVec::new(),
201 checked_extra_checks: RVec::new(),
202
203 visited: HashMap::default(),
204 errors: RVec::new(),
205 current_layer: 0,
206 error_index: 0,
207 }
208 }
209
210 #[inline]
211 fn check_fields<I, F>(
212 &mut self,
213 errs: &mut RVec<AbiInstability>,
214 t_lay: &'static TypeLayout,
215 o_lay: &'static TypeLayout,
216 ctx: FieldContext,
217 t_fields: I,
218 o_fields: I,
219 ) where
220 I: ExactSizeIterator<Item = F>,
221 F: Borrow<TLField>,
222 {
223 if t_fields.len() == 0 && o_fields.len() == 0 {
224 return;
225 }
226
227 let t_data = t_lay.data();
228
229 let is_prefix = match &t_data {
230 TLData::PrefixType { .. } => true,
231 TLData::Enum(enum_) => !enum_.exhaustiveness.is_exhaustive(),
232 _ => false,
233 };
234 match (t_fields.len().cmp(&o_fields.len()), is_prefix) {
235 (Ordering::Greater, _) | (Ordering::Less, false) => {
236 push_err(
237 errs,
238 &t_fields,
239 &o_fields,
240 |x| x.len(),
241 AI::FieldCountMismatch,
242 );
243 }
244 (Ordering::Equal, _) | (Ordering::Less, true) => {}
245 }
246
247 let acc_fields: Option<(FieldAccessibility, FieldAccessibility)> =
248 match (&t_data, &o_lay.data()) {
249 (TLData::PrefixType(t_prefix), TLData::PrefixType(o_prefix)) => {
250 Some((t_prefix.accessible_fields, o_prefix.accessible_fields))
251 }
252 _ => None,
253 };
254
255 for (field_i, (this_f, other_f)) in t_fields.zip(o_fields).enumerate() {
256 let this_f = this_f.borrow();
257 let other_f = other_f.borrow();
258 if this_f.name() != other_f.name() {
259 push_err(errs, this_f, other_f, |x| *x, AI::UnexpectedField);
260 continue;
261 }
262
263 let t_field_abi = this_f.layout();
264 let o_field_abi = other_f.layout();
265
266 let is_accessible = match (ctx, acc_fields) {
267 (FieldContext::Fields, Some((l, r))) => {
268 l.at(field_i).is_accessible() && r.at(field_i).is_accessible()
269 }
270 _ => true,
271 };
272
273 if is_accessible {
274 if this_f.lifetime_indices() != other_f.lifetime_indices() {
275 push_err(errs, this_f, other_f, |x| *x, AI::FieldLifetimeMismatch);
276 }
277
278 self.stack_trace.push(ExpectedFound {
279 expected: (*this_f).into(),
280 found: (*other_f).into(),
281 });
282
283 let sf_ctx = FieldContext::Subfields;
284
285 let func_ranges = this_f.function_range().iter().zip(other_f.function_range());
286 for (t_func, o_func) in func_ranges {
287 self.error_index += 1;
288 let errs_index = self.error_index;
289 let mut errs_ = RVec::<AbiInstability>::new();
290 let errs = &mut errs_;
291
292 self.stack_trace.push(ExpectedFound {
293 expected: t_func.into(),
294 found: o_func.into(),
295 });
296
297 if t_func.paramret_lifetime_indices != o_func.paramret_lifetime_indices {
298 push_err(errs, t_func, o_func, |x| x, AI::FnLifetimeMismatch);
299 }
300
301 if t_func.qualifiers() != o_func.qualifiers() {
302 push_err(errs, t_func, o_func, |x| x, AI::FnQualifierMismatch);
303 }
304
305 self.check_fields(
306 errs,
307 t_lay,
308 o_lay,
309 sf_ctx,
310 t_func.get_params_ret_iter(),
311 o_func.get_params_ret_iter(),
312 );
313
314 if !errs_.is_empty() {
315 self.errors.push(AbiInstabilityError {
316 stack_trace: self.stack_trace.clone(),
317 errs: errs_,
318 index: errs_index,
319 _priv: (),
320 });
321 }
322
323 self.stack_trace.pop();
324 }
325
326 let _ = self.check_inner(t_field_abi, o_field_abi);
327 self.stack_trace.pop();
328 } else {
329 self.stack_trace.push(ExpectedFound {
330 expected: (*this_f).into(),
331 found: (*other_f).into(),
332 });
333
334 let t_field_layout = &t_field_abi;
335 let o_field_layout = &o_field_abi;
336 if t_field_layout.size() != o_field_layout.size() {
337 push_err(errs, t_field_layout, o_field_layout, |x| x.size(), AI::Size);
338 }
339 if t_field_layout.alignment() != o_field_layout.alignment() {
340 push_err(
341 errs,
342 t_field_layout,
343 o_field_layout,
344 |x| x.alignment(),
345 AI::Alignment,
346 );
347 }
348 self.stack_trace.pop();
349 }
350 }
351 }
352
353 fn check_inner(
354 &mut self,
355 this: &'static TypeLayout,
356 other: &'static TypeLayout,
357 ) -> Result<(), ()> {
358 let t_cuti = CheckingUTypeId::new(this);
359 let o_cuti = CheckingUTypeId::new(other);
360 let cuti_pair = (t_cuti, o_cuti);
361
362 self.error_index += 1;
363 let errs_index = self.error_index;
364 let mut errs_ = RVec::<AbiInstability>::new();
365 let mut top_level_errs_ = RVec::<AbiInstabilityError>::new();
366 let t_lay = &this;
367 let o_lay = &other;
368
369 let start_errors = self.errors.len();
370
371 match self.visited.entry(cuti_pair) {
372 Entry::Occupied(mut entry) => match entry.get_mut() {
373 CheckingState::Checking { layer } if self.current_layer == *layer => return Ok(()),
374 cs @ CheckingState::Checking { .. } => {
375 *cs = CheckingState::Error;
376 self.errors.push(AbiInstabilityError {
377 stack_trace: self.stack_trace.clone(),
378 errs: rvec![AbiInstability::CyclicTypeChecking {
379 interface: this,
380 implementation: other,
381 }],
382 index: errs_index,
383 _priv: (),
384 });
385 return Err(());
386 }
387 CheckingState::Compatible => {
388 return Ok(());
389 }
390 CheckingState::Error => {
391 return Err(());
392 }
393 },
394 Entry::Vacant(entry) => {
395 entry.insert(CheckingState::Checking {
396 layer: self.current_layer,
397 });
398 }
399 }
400
401 (|| {
402 let errs = &mut errs_;
403 let top_level_errs = &mut top_level_errs_;
404 if t_lay.name() != o_lay.name() {
405 push_err(errs, t_lay, o_lay, |x| x.full_type(), AI::Name);
406 return;
407 }
408 let (t_package, t_ver_str) = t_lay.package_and_version();
409 let (o_package, o_ver_str) = o_lay.package_and_version();
410 if t_package != o_package {
411 push_err(errs, t_lay, o_lay, |x| x.package(), AI::Package);
412 return;
413 }
414
415 if this.is_nonzero() != other.is_nonzero() {
416 push_err(errs, this, other, |x| x.is_nonzero(), AI::NonZeroness);
417 }
418
419 if t_lay.repr_attr() != o_lay.repr_attr() {
420 push_err(errs, t_lay, o_lay, |x| x.repr_attr(), AI::ReprAttr);
421 }
422
423 {
424 let x = (|| {
425 let l = t_ver_str.parsed()?;
426 let r = o_ver_str.parsed()?;
427 Ok(l.is_loosely_compatible(r))
428 })();
429 match x {
430 Ok(false) => {
431 push_err(
432 errs,
433 t_lay,
434 o_lay,
435 |x| x.package_version(),
436 AI::PackageVersion,
437 );
438 }
439 Ok(true) => {}
440 Err(parse_error) => {
441 errs.push(AI::PackageVersionParseError(parse_error));
442 return;
443 }
444 }
445 }
446 {
447 let t_gens = t_lay.generics();
448 let o_gens = o_lay.generics();
449
450 let t_consts = t_gens.const_params();
451 let o_consts = o_gens.const_params();
452 if t_gens.lifetime_count() != o_gens.lifetime_count()
453 || t_gens.const_params().len() != o_gens.const_params().len()
454 {
455 push_err(errs, t_lay, o_lay, |x| x.full_type(), AI::GenericParamCount);
456 }
457
458 let mut ty_checker = TypeCheckerMut::from_ptr(&mut *self, TD_Opaque);
459 for (l, r) in t_consts.iter().zip(o_consts.iter()) {
460 match l.is_equal(r, ty_checker.sabi_reborrow_mut()) {
461 Ok(false) | Err(_) => {
462 push_err(errs, l, r, |x| *x, AI::MismatchedConstParam);
463 }
464 Ok(true) => {}
465 }
466 }
467 }
468
469 self.check_fields(
471 errs,
472 this,
473 other,
474 FieldContext::PhantomFields,
475 this.phantom_fields().iter(),
476 other.phantom_fields().iter(),
477 );
478
479 match (t_lay.size().cmp(&o_lay.size()), this.is_prefix_kind()) {
480 (Ordering::Greater, _) | (Ordering::Less, false) => {
481 push_err(errs, t_lay, o_lay, |x| x.size(), AI::Size);
482 }
483 (Ordering::Equal, _) | (Ordering::Less, true) => {}
484 }
485 if t_lay.alignment() != o_lay.alignment() {
486 push_err(errs, t_lay, o_lay, |x| x.alignment(), AI::Alignment);
487 }
488
489 let t_discr = t_lay.data_discriminant();
490 let o_discr = o_lay.data_discriminant();
491 if t_discr != o_discr {
492 errs.push(AI::TLDataDiscriminant(ExpectedFound {
493 expected: t_discr,
494 found: o_discr,
495 }));
496 }
497
498 let t_tag = t_lay.tag().to_checkable();
499 let o_tag = o_lay.tag().to_checkable();
500 if let Err(tag_err) = t_tag.check_compatible(&o_tag) {
501 errs.push(AI::TagError { err: tag_err });
502 }
503
504 match (t_lay.extra_checks(), o_lay.extra_checks()) {
505 (None, _) => {}
506 (Some(_), None) => {
507 errs.push(AI::NoneExtraChecks);
508 }
509 (Some(t_extra_checks), Some(o_extra_checks)) => {
510 let mut ty_checker = TypeCheckerMut::from_ptr(&mut *self, TD_Opaque);
511
512 let res = handle_extra_checks_ret(
513 t_extra_checks.clone(),
514 o_extra_checks.clone(),
515 errs,
516 top_level_errs,
517 move || {
518 let ty_checker_ = ty_checker.sabi_reborrow_mut();
519 rtry!(t_extra_checks.check_compatibility(t_lay, o_lay, ty_checker_));
520
521 let ty_checker_ = ty_checker.sabi_reborrow_mut();
522 let opt = rtry!(t_extra_checks.combine(o_extra_checks, ty_checker_));
523
524 opt.map(|combined| ExtraChecksBoxWithContext {
525 t_lay,
526 o_lay,
527 extra_checks: combined,
528 })
529 .piped(ROk)
530 },
531 );
532
533 if let Ok(RSome(x)) = res {
534 self.checked_extra_checks.push(x);
535 }
536 }
537 }
538
539 match (t_lay.data(), o_lay.data()) {
540 (TLData::Opaque { .. }, _) => {
541 }
543
544 (TLData::Primitive(t_prim), TLData::Primitive(o_prim)) => {
545 if t_prim != o_prim {
546 errs.push(AI::MismatchedPrimitive(ExpectedFound {
547 expected: t_prim,
548 found: o_prim,
549 }));
550 }
551 }
552 (TLData::Primitive { .. }, _) => {}
553
554 (TLData::Struct { fields: t_fields }, TLData::Struct { fields: o_fields }) => {
555 self.check_fields(
556 errs,
557 this,
558 other,
559 FieldContext::Fields,
560 t_fields.iter(),
561 o_fields.iter(),
562 );
563 }
564 (TLData::Struct { .. }, _) => {}
565
566 (TLData::Union { fields: t_fields }, TLData::Union { fields: o_fields }) => {
567 self.check_fields(
568 errs,
569 this,
570 other,
571 FieldContext::Fields,
572 t_fields.iter(),
573 o_fields.iter(),
574 );
575 }
576 (TLData::Union { .. }, _) => {}
577
578 (TLData::Enum(t_enum), TLData::Enum(o_enum)) => {
579 self.check_enum(errs, this, other, t_enum, o_enum);
580 let t_as_ne = t_enum.exhaustiveness.as_nonexhaustive();
581 let o_as_ne = o_enum.exhaustiveness.as_nonexhaustive();
582 if let (Some(this_ne), Some(other_ne)) = (t_as_ne, o_as_ne) {
583 self.checked_nonexhaustive_enums
584 .push(CheckedNonExhaustiveEnums {
585 this: NonExhaustiveEnumWithContext {
586 layout: this,
587 enum_: t_enum,
588 nonexhaustive: this_ne,
589 },
590 other: NonExhaustiveEnumWithContext {
591 layout: other,
592 enum_: o_enum,
593 nonexhaustive: other_ne,
594 },
595 });
596 }
597 }
598 (TLData::Enum { .. }, _) => {}
599
600 (TLData::PrefixType(t_prefix), TLData::PrefixType(o_prefix)) => {
601 let this_prefix = __PrefixTypeMetadata::with_prefix_layout(t_prefix, t_lay);
602 let other_prefix = __PrefixTypeMetadata::with_prefix_layout(o_prefix, o_lay);
603
604 self.check_prefix_types(errs, &this_prefix, &other_prefix);
605
606 self.checked_prefix_types.push(CheckedPrefixTypes {
607 this,
608 this_prefix,
609 other,
610 other_prefix,
611 })
612 }
613 (TLData::PrefixType { .. }, _) => {}
614 }
615 })();
616
617 self.errors.extend(top_level_errs_);
618
619 let check_st = self.visited.get_mut(&cuti_pair).unwrap();
620 if errs_.is_empty()
621 && self.errors.len() == start_errors
622 && *check_st != CheckingState::Error
623 {
624 *check_st = CheckingState::Compatible;
625 Ok(())
626 } else {
627 *check_st = CheckingState::Error;
628
629 self.errors.push(AbiInstabilityError {
630 stack_trace: self.stack_trace.clone(),
631 errs: errs_,
632 index: errs_index,
633 _priv: (),
634 });
635
636 Err(())
637 }
638 }
639
640 fn check_enum(
641 &mut self,
642 errs: &mut RVec<AbiInstability>,
643 this: &'static TypeLayout,
644 other: &'static TypeLayout,
645 t_enum: TLEnum,
646 o_enum: TLEnum,
647 ) {
648 let TLEnum {
649 fields: t_fields, ..
650 } = t_enum;
651 let TLEnum {
652 fields: o_fields, ..
653 } = o_enum;
654
655 let t_fcount = t_enum.field_count.as_slice();
656 let o_fcount = o_enum.field_count.as_slice();
657
658 let t_exhaus = t_enum.exhaustiveness;
659 let o_exhaus = o_enum.exhaustiveness;
660
661 match (t_exhaus.as_nonexhaustive(), o_exhaus.as_nonexhaustive()) {
662 (Some(this_ne), Some(other_ne)) => {
663 if let Err(e) = this_ne.check_compatible(this) {
664 errs.push(AI::IncompatibleWithNonExhaustive(e))
665 }
666 if let Err(e) = other_ne.check_compatible(other) {
667 errs.push(AI::IncompatibleWithNonExhaustive(e))
668 }
669 }
670 (Some(_), None) | (None, Some(_)) => {
671 push_err(
672 errs,
673 t_enum,
674 o_enum,
675 |x| x.exhaustiveness,
676 AI::MismatchedExhaustiveness,
677 );
678 }
679 (None, None) => {}
680 }
681
682 if t_exhaus.is_exhaustive() && t_fcount.len() != o_fcount.len()
683 || t_exhaus.is_nonexhaustive() && t_fcount.len() > o_fcount.len()
684 {
685 push_err(errs, t_fcount, o_fcount, |x| x.len(), AI::TooManyVariants);
686 }
687
688 if let Err(d_errs) = t_enum.discriminants.compare(&o_enum.discriminants) {
689 errs.extend(d_errs);
690 }
691
692 let mut t_names = t_enum.variant_names.as_str().split(';');
693 let mut o_names = o_enum.variant_names.as_str().split(';');
694 let mut total_field_count = 0;
695 for (t_field_count, o_field_count) in t_fcount.iter().zip(o_fcount) {
696 let t_name = t_names.next().unwrap_or("<this unavailable>");
697 let o_name = o_names.next().unwrap_or("<other unavailable>");
698
699 total_field_count += usize::from(*t_field_count);
700
701 if t_field_count != o_field_count {
702 push_err(
703 errs,
704 *t_field_count,
705 *o_field_count,
706 |x| x as usize,
707 AI::FieldCountMismatch,
708 );
709 }
710
711 if t_name != o_name {
712 push_err(errs, t_name, o_name, RStr::from_str, AI::UnexpectedVariant);
713 continue;
714 }
715 }
716
717 let min_field_count = t_fields.len().min(o_fields.len());
718 if total_field_count != min_field_count {
719 push_err(
720 errs,
721 total_field_count,
722 min_field_count,
723 |x| x,
724 AI::FieldCountMismatch,
725 );
726 }
727
728 self.check_fields(
729 errs,
730 this,
731 other,
732 FieldContext::Fields,
733 t_fields.iter(),
734 o_fields.iter(),
735 );
736 }
737
738 fn check_prefix_types(
739 &mut self,
740 errs: &mut RVec<AbiInstability>,
741 this: &__PrefixTypeMetadata,
742 other: &__PrefixTypeMetadata,
743 ) {
744 if this.prefix_field_count != other.prefix_field_count {
745 push_err(
746 errs,
747 this,
748 other,
749 |x| x.prefix_field_count,
750 AI::MismatchedPrefixSize,
751 );
752 }
753
754 if this.conditional_prefix_fields != other.conditional_prefix_fields {
755 push_err(
756 errs,
757 this,
758 other,
759 |x| x.conditional_prefix_fields,
760 AI::MismatchedPrefixConditionality,
761 );
762 }
763
764 self.check_fields(
765 errs,
766 this.layout,
767 other.layout,
768 FieldContext::Fields,
769 this.fields.iter(),
770 other.fields.iter(),
771 );
772 }
773
774 fn final_prefix_type_checks(
776 &mut self,
777 globals: &CheckingGlobals,
778 ) -> Result<(), AbiInstabilityError> {
779 self.error_index += 1;
780 let mut errs_ = RVec::<AbiInstability>::new();
781 let errs = &mut errs_;
782
783 let mut prefix_type_map = globals.prefix_type_map.lock().unwrap();
784
785 for pair in mem::take(&mut self.checked_prefix_types) {
786 let errors_before = self.errors.len();
788 let t_utid = pair.this.get_utypeid();
789 let o_utid = pair.other.get_utypeid();
790 let t_index = prefix_type_map.get_index(&t_utid);
794 let mut o_index = prefix_type_map.get_index(&o_utid);
795
796 if t_index == o_index {
797 o_index = None;
798 }
799
800 let (min_prefix, mut max_prefix) = pair.this_prefix.min_max(pair.other_prefix);
801
802 match (t_index, o_index) {
803 (None, None) => {
804 max_prefix.combine_fields_from(&min_prefix);
805
806 let i = prefix_type_map
807 .get_or_insert(t_utid, max_prefix)
808 .into_inner()
809 .index;
810 prefix_type_map.associate_key(o_utid, i);
811 }
812 (Some(im_index), None) | (None, Some(im_index)) => {
813 max_prefix.combine_fields_from(&min_prefix);
814
815 let im_prefix = prefix_type_map.get_mut_with_index(im_index).unwrap();
816 let im_prefix_addr = im_prefix as *const _ as usize;
817
818 let (min_prefix, max_prefix) =
819 min_max_by(im_prefix, &mut max_prefix, |x| x.fields.len());
820
821 self.check_prefix_types(errs, min_prefix, max_prefix);
822 if !errs.is_empty() || errors_before != self.errors.len() {
823 break;
824 }
825
826 max_prefix.combine_fields_from(&*min_prefix);
827
828 if im_prefix_addr != (max_prefix as *mut _ as usize) {
829 mem::swap(min_prefix, max_prefix);
830 }
831
832 prefix_type_map.associate_key(t_utid, im_index);
833 prefix_type_map.associate_key(o_utid, im_index);
834 }
835 (Some(l_index), Some(r_index)) => {
836 let (l_prefix, r_prefix) =
837 prefix_type_map.get2_mut_with_index(l_index, r_index);
838 let l_prefix = l_prefix.unwrap();
839 let r_prefix = r_prefix.unwrap();
840
841 let (replace, with) = if l_prefix.fields.len() < r_prefix.fields.len() {
842 (l_index, r_index)
843 } else {
844 (r_index, l_index)
845 };
846
847 let (min_prefix, max_prefix) =
848 min_max_by(l_prefix, r_prefix, |x| x.fields.len());
849 self.check_prefix_types(errs, min_prefix, max_prefix);
850 if !errs.is_empty() || errors_before != self.errors.len() {
851 break;
852 }
853
854 max_prefix.combine_fields_from(&*min_prefix);
855
856 prefix_type_map.replace_with_index(replace, with);
857 }
858 }
859 }
860
861 if errs_.is_empty() {
862 Ok(())
863 } else {
864 Err(AbiInstabilityError {
865 stack_trace: self.stack_trace.clone(),
866 errs: errs_,
867 index: self.error_index,
868 _priv: (),
869 })
870 }
871 }
872
873 fn final_non_exhaustive_enum_checks(
875 &mut self,
876 globals: &CheckingGlobals,
877 ) -> Result<(), AbiInstabilityError> {
878 self.error_index += 1;
879 let mut errs_ = RVec::<AbiInstability>::new();
880 let errs = &mut errs_;
881
882 let mut nonexhaustive_map = globals.nonexhaustive_map.lock().unwrap();
883
884 for pair in mem::take(&mut self.checked_nonexhaustive_enums) {
885 let CheckedNonExhaustiveEnums { this, other } = pair;
886 let errors_before = self.errors.len();
887
888 let t_utid = this.layout.get_utypeid();
889 let o_utid = other.layout.get_utypeid();
890
891 let t_index = nonexhaustive_map.get_index(&t_utid);
892 let mut o_index = nonexhaustive_map.get_index(&o_utid);
893
894 if t_index == o_index {
895 o_index = None;
896 }
897
898 let mut max_ = max_by(this, other, |x| x.enum_.variant_count());
899
900 match (t_index, o_index) {
901 (None, None) => {
902 let i = nonexhaustive_map
903 .get_or_insert(t_utid, max_)
904 .into_inner()
905 .index;
906
907 nonexhaustive_map.associate_key(o_utid, i);
908 }
909 (Some(im_index), None) | (None, Some(im_index)) => {
910 let im_nonexh = nonexhaustive_map.get_mut_with_index(im_index).unwrap();
911 let im_nonexh_addr = im_nonexh as *const _ as usize;
912
913 let (min_nonexh, max_nonexh) =
914 min_max_by(im_nonexh, &mut max_, |x| x.enum_.variant_count());
915
916 self.check_enum(
917 errs,
918 min_nonexh.layout,
919 max_nonexh.layout,
920 min_nonexh.enum_,
921 max_nonexh.enum_,
922 );
923
924 if !errs.is_empty() || errors_before != self.errors.len() {
925 break;
926 }
927
928 if im_nonexh_addr != (max_nonexh as *mut _ as usize) {
929 mem::swap(min_nonexh, max_nonexh);
930 }
931
932 nonexhaustive_map.associate_key(t_utid, im_index);
933 nonexhaustive_map.associate_key(o_utid, im_index);
934 }
935 (Some(l_index), Some(r_index)) => {
936 let (l_nonexh, r_nonexh) =
937 nonexhaustive_map.get2_mut_with_index(l_index, r_index);
938 let l_nonexh = l_nonexh.unwrap();
939 let r_nonexh = r_nonexh.unwrap();
940
941 let (replace, with) =
942 if l_nonexh.enum_.variant_count() < r_nonexh.enum_.variant_count() {
943 (l_index, r_index)
944 } else {
945 (r_index, l_index)
946 };
947
948 let (min_nonexh, max_nonexh) =
949 min_max_by(l_nonexh, r_nonexh, |x| x.enum_.variant_count());
950
951 self.check_enum(
952 errs,
953 min_nonexh.layout,
954 max_nonexh.layout,
955 min_nonexh.enum_,
956 max_nonexh.enum_,
957 );
958
959 if !errs.is_empty() || errors_before != self.errors.len() {
960 break;
961 }
962
963 nonexhaustive_map.replace_with_index(replace, with);
964 }
965 }
966 }
967
968 if errs_.is_empty() {
969 Ok(())
970 } else {
971 Err(AbiInstabilityError {
972 stack_trace: self.stack_trace.clone(),
973 errs: errs_,
974 index: self.error_index,
975 _priv: (),
976 })
977 }
978 }
979
980 fn final_extra_checks(
982 &mut self,
983 globals: &CheckingGlobals,
984 ) -> Result<(), RVec<AbiInstabilityError>> {
985 self.error_index += 1;
986
987 let mut top_level_errs_ = RVec::<AbiInstabilityError>::new();
988
989 let mut errs_ = RVec::<AbiInstability>::new();
990 let errs = &mut errs_;
991 let top_level_errs = &mut top_level_errs_;
992
993 let mut extra_checker_map = globals.extra_checker_map.lock().unwrap();
994
995 for with_context in mem::take(&mut self.checked_extra_checks) {
996 let ExtraChecksBoxWithContext {
997 t_lay,
998 o_lay,
999 extra_checks,
1000 } = with_context;
1001
1002 let errors_before = self.errors.len();
1003 let type_checker = TypeCheckerMut::from_ptr(&mut *self, TD_Opaque);
1004 let t_utid = t_lay.get_utypeid();
1005 let o_utid = o_lay.get_utypeid();
1006
1007 let t_index = extra_checker_map.get_index(&t_utid);
1008 let mut o_index = extra_checker_map.get_index(&o_utid);
1009
1010 if t_index == o_index {
1011 o_index = None;
1012 }
1013
1014 match (t_index, o_index) {
1015 (None, None) => {
1016 let i = extra_checker_map
1017 .get_or_insert(t_utid, extra_checks)
1018 .into_inner()
1019 .index;
1020 extra_checker_map.associate_key(o_utid, i);
1021 }
1022 (Some(im_index), None) | (None, Some(im_index)) => {
1023 let other_checks = extra_checker_map.get_mut_with_index(im_index).unwrap();
1024
1025 combine_extra_checks(
1026 errs,
1027 top_level_errs,
1028 type_checker,
1029 other_checks,
1030 &[extra_checks.sabi_reborrow()],
1031 );
1032
1033 if !errs.is_empty() || errors_before != self.errors.len() {
1034 break;
1035 }
1036
1037 extra_checker_map.associate_key(t_utid, im_index);
1038 extra_checker_map.associate_key(o_utid, im_index);
1039 }
1040 (Some(l_index), Some(r_index)) => {
1041 let (l_extra_checks, r_extra_checks) =
1042 extra_checker_map.get2_mut_with_index(l_index, r_index);
1043 let l_extra_checks = l_extra_checks.unwrap();
1044 let r_extra_checks = r_extra_checks.unwrap();
1045
1046 combine_extra_checks(
1047 errs,
1048 top_level_errs,
1049 type_checker,
1050 l_extra_checks,
1051 &[r_extra_checks.sabi_reborrow(), extra_checks.sabi_reborrow()],
1052 );
1053
1054 if !errs.is_empty() || errors_before != self.errors.len() {
1055 break;
1056 }
1057
1058 extra_checker_map.replace_with_index(r_index, l_index);
1059 }
1060 }
1061 }
1062
1063 if errs_.is_empty() {
1064 Ok(())
1065 } else {
1066 top_level_errs.push(AbiInstabilityError {
1067 stack_trace: self.stack_trace.clone(),
1068 errs: errs_,
1069 index: self.error_index,
1070 _priv: (),
1071 });
1072 Err(top_level_errs_)
1073 }
1074 }
1075}
1076
1077pub fn check_layout_compatibility(
1086 interface: &'static TypeLayout,
1087 implementation: &'static TypeLayout,
1088) -> Result<(), AbiInstabilityErrors> {
1089 check_layout_compatibility_with_globals(interface, implementation, get_checking_globals())
1090}
1091
1092#[inline(never)]
1093pub fn check_layout_compatibility_with_globals(
1094 interface: &'static TypeLayout,
1095 implementation: &'static TypeLayout,
1096 globals: &CheckingGlobals,
1097) -> Result<(), AbiInstabilityErrors> {
1098 let mut errors: RVec<AbiInstabilityError>;
1099
1100 if interface.is_prefix_kind() || implementation.is_prefix_kind() {
1101 let mut errs = RVec::with_capacity(1);
1102 push_err(
1103 &mut errs,
1104 interface,
1105 implementation,
1106 |x| x.data_discriminant(),
1107 AI::TLDataDiscriminant,
1108 );
1109 errors = vec![AbiInstabilityError {
1110 stack_trace: vec![].into(),
1111 errs,
1112 index: 0,
1113 _priv: (),
1114 }]
1115 .into();
1116 } else {
1117 let mut checker = AbiChecker::new();
1118 let _ = checker.check_inner(interface, implementation);
1119 if checker.errors.is_empty() {
1120 if let Err(e) = checker.final_prefix_type_checks(globals) {
1121 checker.errors.push(e);
1122 }
1123 if let Err(e) = checker.final_non_exhaustive_enum_checks(globals) {
1124 checker.errors.push(e);
1125 }
1126 if let Err(e) = checker.final_extra_checks(globals) {
1127 checker.errors.extend(e);
1128 }
1129 }
1130 errors = checker.errors;
1131 }
1132
1133 if errors.is_empty() {
1134 Ok(())
1135 } else {
1136 errors.sort_by_key(|x| x.index);
1137 Err(AbiInstabilityErrors {
1138 interface,
1139 implementation,
1140 errors,
1141 _priv: (),
1142 })
1143 }
1144}
1145
1146pub(crate) extern "C" fn check_layout_compatibility_for_ffi(
1148 interface: &'static TypeLayout,
1149 implementation: &'static TypeLayout,
1150) -> RResult<(), RBoxError> {
1151 extern_fn_panic_handling! {
1152 let mut is_already_inside=false;
1153 INSIDE_LAYOUT_CHECKER.with(|inside|{
1154 is_already_inside=inside.get();
1155 inside.set(true);
1156 });
1157 let _guard=LayoutCheckerGuard;
1158
1159 if is_already_inside {
1160 let errors =
1161 vec![AbiInstabilityError {
1162 stack_trace: vec![].into(),
1163 errs:vec![AbiInstability::ReentrantLayoutCheckingCall].into(),
1164 index: 0,
1165 _priv:(),
1166 }].into_c();
1167
1168 Err(AbiInstabilityErrors{ interface, implementation, errors, _priv:() })
1169 }else{
1170 check_layout_compatibility(interface,implementation)
1171 }.map_err(RBoxError::new)
1172 .into_c()
1173 }
1174}
1175
1176pub extern "C" fn exported_check_layout_compatibility(
1193 interface: &'static TypeLayout,
1194 implementation: &'static TypeLayout,
1195) -> RResult<(), RBoxError> {
1196 extern_fn_panic_handling! {
1197 (crate::globals::initialized_globals().layout_checking)
1198 (interface,implementation)
1199 }
1200}
1201
1202impl AbiChecker {
1203 fn check_compatibility_inner(
1204 &mut self,
1205 interface: &'static TypeLayout,
1206 implementation: &'static TypeLayout,
1207 ) -> RResult<(), ()> {
1208 let error_count_before = self.errors.len();
1209
1210 self.current_layer += 1;
1211
1212 let res = self.check_inner(interface, implementation);
1213
1214 self.current_layer -= 1;
1215
1216 if error_count_before == self.errors.len() && res.is_ok() {
1217 ROk(())
1218 } else {
1219 RErr(())
1220 }
1221 }
1222}
1223
1224unsafe impl TypeChecker for AbiChecker {
1225 fn check_compatibility(
1226 &mut self,
1227 interface: &'static TypeLayout,
1228 implementation: &'static TypeLayout,
1229 ) -> RResult<(), ExtraChecksError> {
1230 self.check_compatibility_inner(interface, implementation)
1231 .map_err(|_| ExtraChecksError::TypeChecker)
1232 }
1233
1234 fn local_check_compatibility(
1235 &mut self,
1236 interface: &'static TypeLayout,
1237 implementation: &'static TypeLayout,
1238 ) -> RResult<(), ExtraChecksError> {
1239 let error_count_before = self.errors.len();
1240
1241 dbg!(error_count_before);
1242 println!(
1243 "interface:{} implementation:{}",
1244 interface.full_type(),
1245 implementation.full_type()
1246 );
1247
1248 self.check_compatibility_inner(interface, implementation)
1249 .map_err(|_| {
1250 AbiInstabilityErrors {
1251 interface,
1252 implementation,
1253 errors: self.errors.drain(error_count_before..).collect(),
1254 _priv: (),
1255 }
1256 .piped(RBoxError::new)
1257 .piped(ExtraChecksError::TypeCheckerErrors)
1258 })
1259 }
1260}
1261
1262thread_local! {
1265 static INSIDE_LAYOUT_CHECKER:Cell<bool>=Cell::new(false);
1266}
1267
1268struct LayoutCheckerGuard;
1269
1270impl Drop for LayoutCheckerGuard {
1271 fn drop(&mut self) {
1272 INSIDE_LAYOUT_CHECKER.with(|inside| {
1273 inside.set(false);
1274 });
1275 }
1276}
1277
1278use std::sync::Mutex;
1281
1282use crate::{
1283 multikey_map::MultiKeyMap, prefix_type::__PrefixTypeMetadata, sabi_types::LateStaticRef,
1284 utils::leak_value,
1285};
1286
1287#[derive(Debug)]
1288pub struct CheckingGlobals {
1289 pub prefix_type_map: Mutex<MultiKeyMap<UTypeId, __PrefixTypeMetadata>>,
1290 pub nonexhaustive_map: Mutex<MultiKeyMap<UTypeId, NonExhaustiveEnumWithContext>>,
1291 pub extra_checker_map: Mutex<MultiKeyMap<UTypeId, ExtraChecksBox>>,
1292}
1293
1294#[allow(clippy::new_without_default)]
1295impl CheckingGlobals {
1296 pub fn new() -> Self {
1297 CheckingGlobals {
1298 prefix_type_map: MultiKeyMap::new().piped(Mutex::new),
1299 nonexhaustive_map: MultiKeyMap::new().piped(Mutex::new),
1300 extra_checker_map: MultiKeyMap::new().piped(Mutex::new),
1301 }
1302 }
1303}
1304
1305static CHECKING_GLOBALS: LateStaticRef<&CheckingGlobals> = LateStaticRef::new();
1306
1307pub fn get_checking_globals() -> &'static CheckingGlobals {
1308 CHECKING_GLOBALS.init(|| CheckingGlobals::new().piped(leak_value))
1309}
1310
1311pub(crate) fn push_err<O, U, FG, VC>(
1314 errs: &mut RVec<AbiInstability>,
1315 this: O,
1316 other: O,
1317 field_getter: FG,
1318 mut variant_constructor: VC,
1319) where
1320 FG: FnMut(O) -> U,
1321 VC: FnMut(ExpectedFound<U>) -> AbiInstability,
1322{
1323 let x = ExpectedFound::new(this, other, field_getter);
1324 let x = variant_constructor(x);
1325 errs.push(x);
1326}
1327
1328fn handle_extra_checks_ret<F, R>(
1329 expected_extra_checks: ExtraChecksRef<'_>,
1330 found_extra_checks: ExtraChecksRef<'_>,
1331 errs: &mut RVec<AbiInstability>,
1332 top_level_errs: &mut RVec<AbiInstabilityError>,
1333 f: F,
1334) -> Result<R, ()>
1335where
1336 F: FnOnce() -> RResult<R, ExtraChecksError>,
1337{
1338 let make_extra_check_error = move |e: RBoxError| -> AbiInstability {
1339 ExtraCheckError {
1340 err: RArc::new(e),
1341 expected_err: ExpectedFound {
1342 expected: expected_extra_checks
1343 .piped_ref(RBoxError::from_fmt)
1344 .piped(RArc::new),
1345
1346 found: found_extra_checks
1347 .piped_ref(RBoxError::from_fmt)
1348 .piped(RArc::new),
1349 },
1350 }
1351 .piped(CmpIgnored::new)
1352 .piped(AI::ExtraCheckError)
1353 };
1354 match f() {
1355 ROk(x) => Ok(x),
1356 RErr(ExtraChecksError::TypeChecker) => Err(()),
1357 RErr(ExtraChecksError::TypeCheckerErrors(e)) => {
1358 match e.downcast::<AbiInstabilityErrors>() {
1359 Ok(e) => top_level_errs.extend(RBox::into_inner(e).errors),
1360 Err(e) => errs.push(make_extra_check_error(e)),
1361 }
1362 Err(())
1363 }
1364 RErr(ExtraChecksError::NoneExtraChecks) => {
1365 errs.push(AI::NoneExtraChecks);
1366 Err(())
1367 }
1368 RErr(ExtraChecksError::ExtraChecks(e)) => {
1369 errs.push(make_extra_check_error(e));
1370 Err(())
1371 }
1372 }
1373}
1374
1375fn combine_extra_checks(
1376 errs: &mut RVec<AbiInstability>,
1377 top_level_errs: &mut RVec<AbiInstabilityError>,
1378 mut ty_checker: TypeCheckerMut<'_>,
1379 extra_checks: &mut ExtraChecksBox,
1380 slic: &[ExtraChecksRef<'_>],
1381) {
1382 for other in slic {
1383 let other_ref = other.sabi_reborrow();
1384 let ty_checker = ty_checker.sabi_reborrow_mut();
1385 let opt_ret = handle_extra_checks_ret(
1386 extra_checks.sabi_reborrow(),
1387 other.sabi_reborrow(),
1388 errs,
1389 top_level_errs,
1390 || extra_checks.sabi_reborrow().combine(other_ref, ty_checker),
1391 );
1392
1393 match opt_ret {
1394 Ok(RSome(new)) => {
1395 *extra_checks = new;
1396 }
1397 Ok(RNone) => {}
1398 Err(_) => break,
1399 }
1400 }
1401}