abi_stable/abi_stability/
abi_checking.rs

1//! Functions and types related to the layout checking.
2
3use 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////////////////////////////////////////////////////////////////////////////////
42
43/// What is AbiChecker::check_fields being called with.
44#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
45#[repr(C)]
46enum FieldContext {
47    Fields,
48    Subfields,
49    PhantomFields,
50}
51
52//////
53
54#[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//////
69
70#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
71pub enum CheckingState {
72    Checking { layer: u32 },
73    Compatible,
74    Error,
75}
76
77//////
78
79/// Represents an error where a value was expected,but another value was found.
80#[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///////////////////////////////////////////////
132
133#[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
165///////////////////////////////////////////////
166
167struct 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    /// Layer 0 is checking a type layout,
178    ///
179    /// Layer 1 is checking the type layout
180    ///     of a const parameter/ExtraCheck,
181    ///
182    /// Layer 2 is checking the type layout
183    ///     of a const parameter/ExtraCheck
184    ///     of a const parameter/ExtraCheck,
185    ///
186    /// It is an error to attempt to check the layout of types that are
187    /// in the middle of being checked in outer layers.
188    current_layer: u32,
189
190    error_index: usize,
191}
192
193///////////////////////////////////////////////
194
195impl 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            // Checking phantom fields
470            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                    // No checks are necessary
542                }
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    /// Combines the prefix types into a global map of prefix types.
775    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 t_lay=pair.this_prefix;
787            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_fields=pair.this_prefix.fields;
791            // let o_fields=pair.other_prefix.fields;
792
793            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    /// Combines the nonexhaustive enums into a global map of nonexhaustive enums.
874    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    /// Combines the ExtraChecksBox into a global map.
981    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
1077/// Checks that the layout of `interface` is compatible with `implementation`.
1078///
1079/// # Warning
1080///
1081/// This function is not symmetric,
1082/// the first parameter must be the expected layout,
1083/// and the second must be actual layout.
1084///
1085pub 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
1146/// Checks that the layout of `interface` is compatible with `implementation`,
1147pub(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
1176/// Checks that the layout of `interface` is compatible with `implementation`,
1177///
1178/// If this function is called within a dynamic library,
1179/// it must be called during or after the function that exports its root module is called.
1180///
1181/// **DO NOT** call this in the static initializer of a dynamic library,
1182/// since this library relies on setting up its global state before
1183/// calling the root module loader.
1184///
1185/// # Warning
1186///
1187/// This function is not symmetric,
1188/// the first parameter must be the expected layout,
1189/// and the second must be actual layout.
1190///
1191///
1192pub 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
1262///////////////////////////////////////////////
1263
1264thread_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
1278///////////////////////////////////////////////
1279
1280use 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
1311///////////////////////////////////////////////
1312
1313pub(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}