dotscope 0.6.0

A high-performance, cross-platform framework for analyzing and reverse engineering .NET PE executables
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
//! Owned accessibility validator for visibility rules and access control validation.
//!
//! This validator provides comprehensive validation of accessibility and visibility rules
//! for types and members within the context of fully resolved .NET metadata. It operates
//! on resolved type structures to ensure ECMA-335 compliance for access control patterns
//! and inheritance visibility. This validator runs with priority 160 in the owned validation stage.
//!
//! # Architecture
//!
//! The accessibility validation system implements comprehensive access control validation in sequential order:
//! 1. **Type Accessibility** - Validates type visibility and accessibility rules according to ECMA-335
//! 2. **Member Accessibility** - Ensures member accessibility consistency with containing types
//! 3. **Interface Accessibility** - Validates interface implementation accessibility requirements
//! 4. **Inheritance Accessibility** - Validates accessibility inheritance patterns and rules
//!
//! The implementation validates accessibility constraints according to ECMA-335 specifications,
//! ensuring proper access control patterns across type hierarchies and member definitions.
//! All validation includes cross-reference checking and inheritance rule verification.
//!
//! # Key Components
//!
//! - [`crate::metadata::validation::validators::owned::members::accessibility::OwnedAccessibilityValidator`] - Main validator implementation providing comprehensive accessibility validation
//! - [`crate::metadata::validation::validators::owned::members::accessibility::OwnedAccessibilityValidator::validate_type_accessibility`] - Type visibility and accessibility rule validation
//! - [`crate::metadata::validation::validators::owned::members::accessibility::OwnedAccessibilityValidator::validate_member_accessibility`] - Member accessibility consistency validation
//! - [`crate::metadata::validation::validators::owned::members::accessibility::OwnedAccessibilityValidator::validate_interface_accessibility`] - Interface implementation accessibility validation
//! - [`crate::metadata::validation::validators::owned::members::accessibility::OwnedAccessibilityValidator::validate_inheritance_accessibility`] - Inheritance accessibility pattern validation
//!
//! # Usage Examples
//!
//! ```rust,no_run
//! use dotscope::metadata::validation::{OwnedAccessibilityValidator, OwnedValidator, OwnedValidationContext};
//!
//! # fn get_context() -> OwnedValidationContext<'static> { unimplemented!() }
//! let context = get_context();
//! let validator = OwnedAccessibilityValidator::new();
//!
//! // Check if validation should run based on configuration
//! if validator.should_run(&context) {
//!     validator.validate_owned(&context)?;
//! }
//! # Ok::<(), dotscope::Error>(())
//! ```
//!
//! # Error Handling
//!
//! This validator returns [`crate::Error::ValidationOwnedFailed`] for:
//! - Invalid type visibility attributes (unknown visibility values)
//! - Inconsistent member accessibility relative to containing types
//! - Nested type accessibility violations (improper visibility combinations)
//! - Interface implementation accessibility requirements not met
//! - Literal fields that are not static (ECMA-335 violation)
//! - Interfaces containing non-constant fields
//! - Sealed interfaces (invalid combination)
//! - Types with empty names or invalid accessibility patterns
//!
//! # Thread Safety
//!
//! All validation operations are read-only and thread-safe. The validator implements [`Send`] + [`Sync`]
//! and can be used concurrently across multiple threads without synchronization as it operates on
//! immutable resolved metadata structures.
//!
//! # Integration
//!
//! This validator integrates with:
//! - [`crate::metadata::validation::validators::owned::members`] - Part of the owned member validation stage
//! - [`crate::metadata::validation::engine::ValidationEngine`] - Orchestrates validator execution
//! - [`crate::metadata::validation::traits::OwnedValidator`] - Implements the owned validation interface
//! - [`crate::metadata::cilobject::CilObject`] - Source of resolved type structures
//! - [`crate::metadata::validation::context::OwnedValidationContext`] - Provides validation execution context
//! - [`crate::metadata::validation::config::ValidationConfig`] - Controls validation execution via enable_semantic_validation flag
//!
//! # References
//!
//! - [ECMA-335 II.23.1.15](https://ecma-international.org/wp-content/uploads/ECMA-335_6th_edition_june_2012.pdf) - TypeAttributes specification
//! - [ECMA-335 II.10.1](https://ecma-international.org/wp-content/uploads/ECMA-335_6th_edition_june_2012.pdf) - Type accessibility rules
//! - [ECMA-335 II.10.2](https://ecma-international.org/wp-content/uploads/ECMA-335_6th_edition_june_2012.pdf) - Member accessibility rules
//! - [ECMA-335 II.10.3](https://ecma-international.org/wp-content/uploads/ECMA-335_6th_edition_june_2012.pdf) - Inheritance and accessibility

use crate::{
    metadata::{
        // method::{MethodAccessFlags, MethodModifiers}, // Unused imports
        tables::{FieldAttributes, TypeAttributes},
        validation::{
            context::{OwnedValidationContext, ValidationContext},
            traits::OwnedValidator,
        },
    },
    Error, Result,
};

/// Foundation validator for accessibility rules, visibility constraints, and access control consistency.
///
/// Ensures the structural integrity and consistency of accessibility rules for types and members
/// in resolved .NET metadata, validating proper access control patterns, inheritance visibility,
/// and interface implementation requirements. This validator operates on resolved type structures
/// to provide essential guarantees about accessibility compliance.
///
/// The validator implements comprehensive coverage of accessibility validation according to
/// ECMA-335 specifications, ensuring proper access control patterns across type hierarchies
/// and member definitions in the resolved metadata object model.
///
/// # Thread Safety
///
/// This validator is [`Send`] and [`Sync`] as all validation operations are read-only
/// and operate on immutable resolved metadata structures.
pub struct OwnedAccessibilityValidator;

impl OwnedAccessibilityValidator {
    /// Creates a new accessibility validator instance.
    ///
    /// Initializes a validator instance that can be used to validate accessibility rules
    /// across multiple assemblies. The validator is stateless and can be reused safely
    /// across multiple validation operations.
    ///
    /// # Returns
    ///
    /// A new [`crate::metadata::validation::validators::owned::members::accessibility::OwnedAccessibilityValidator`] instance ready for validation operations.
    ///
    /// # Thread Safety
    ///
    /// The returned validator is thread-safe and can be used concurrently.
    #[must_use]
    pub fn new() -> Self {
        Self
    }

    /// Validates type visibility and accessibility rules.
    ///
    /// Ensures that type visibility attributes are valid and consistent with
    /// ECMA-335 specifications for type accessibility. Validates nested type
    /// visibility rules and interface sealing constraints.
    ///
    /// # Arguments
    ///
    /// * `context` - Owned validation context containing resolved type structures via [`crate::metadata::validation::context::OwnedValidationContext`]
    ///
    /// # Returns
    ///
    /// * `Ok(())` - All type accessibility rules are valid
    /// * `Err(`[`crate::Error::ValidationOwnedFailed`]`)` - Accessibility violations found
    ///
    /// # Errors
    ///
    /// Returns [`crate::Error::ValidationOwnedFailed`] if:
    /// - Type visibility attributes contain invalid values
    /// - Nested types have inappropriate visibility flags
    /// - Interfaces are marked as sealed (invalid combination)
    fn validate_type_accessibility(&self, context: &OwnedValidationContext) -> Result<()> {
        for type_entry in context.all_types() {
            let visibility = type_entry.flags & TypeAttributes::VISIBILITY_MASK;

            match visibility {
                TypeAttributes::NOT_PUBLIC
                | TypeAttributes::PUBLIC
                | TypeAttributes::NESTED_PUBLIC
                | TypeAttributes::NESTED_PRIVATE
                | TypeAttributes::NESTED_FAMILY
                | TypeAttributes::NESTED_ASSEMBLY
                | TypeAttributes::NESTED_FAM_AND_ASSEM
                | TypeAttributes::NESTED_FAM_OR_ASSEM => {
                    // Valid visibility
                }
                _ => {
                    return Err(Error::ValidationOwnedFailed {
                        validator: self.name().to_string(),
                        message: format!(
                            "Type '{}' has invalid visibility: 0x{:02X}",
                            type_entry.name, visibility
                        ),
                    });
                }
            }

            // Validate that types which ARE nested have proper nested visibility
            // Check if this type has an enclosing type (i.e., this type IS nested)
            if type_entry.enclosing_type.get().is_some() {
                // This is a nested type - it must use nested visibility flags (0x02-0x07)
                // It cannot use top-level visibility (NOT_PUBLIC=0x00, PUBLIC=0x01)
                // and cannot use values beyond NESTED_FAM_OR_ASSEM (>0x07)
                if !(TypeAttributes::NESTED_PUBLIC..=TypeAttributes::NESTED_FAM_OR_ASSEM)
                    .contains(&visibility)
                {
                    return Err(Error::ValidationOwnedFailed {
                        validator: self.name().to_string(),
                        message: format!(
                            "Nested type '{}' has invalid visibility flags: 0x{:02X} (must be between NESTED_PUBLIC=0x02 and NESTED_FAM_OR_ASSEM=0x07)",
                            type_entry.name, visibility
                        ),

                    });
                }
            }

            if type_entry.flags & TypeAttributes::INTERFACE != 0
                && type_entry.flags & TypeAttributes::SEALED != 0
            {
                // SEALED flag
                return Err(Error::ValidationOwnedFailed {
                    validator: self.name().to_string(),
                    message: format!("Interface '{}' cannot be sealed", type_entry.name),
                });
            }
        }

        Ok(())
    }

    /// Validates member accessibility consistency with containing types.
    ///
    /// Ensures that members have appropriate accessibility relative to their
    /// containing types and that accessibility rules are logically consistent.
    /// Validates field and method accessibility patterns.
    ///
    /// # Arguments
    ///
    /// * `context` - Owned validation context containing resolved type structures via [`crate::metadata::validation::context::OwnedValidationContext`]
    ///
    /// # Returns
    ///
    /// * `Ok(())` - All member accessibility rules are consistent
    /// * `Err(`[`crate::Error::ValidationOwnedFailed`]`)` - Member accessibility violations found
    ///
    /// # Errors
    ///
    /// Returns [`crate::Error::ValidationOwnedFailed`] if:
    /// - Methods have empty names
    /// - Literal fields are not marked as static (ECMA-335 requirement)
    fn validate_member_accessibility(&self, context: &OwnedValidationContext) -> Result<()> {
        for type_entry in context.all_types() {
            let type_visibility = type_entry.flags & TypeAttributes::VISIBILITY_MASK;

            for (_, method_ref) in type_entry.methods.iter() {
                if let Some(method) = method_ref.upgrade() {
                    // ToDo: For full validation, we would need to resolve the method reference
                    // to get its actual accessibility flags. Here we're working with references.

                    if method.name.is_empty() {
                        return Err(Error::ValidationOwnedFailed {
                            validator: self.name().to_string(),
                            message: format!("Method in type '{}' has empty name", type_entry.name),
                        });
                    }
                }
            }

            for (_, field) in type_entry.fields.iter() {
                let field_access = field.flags & FieldAttributes::FIELD_ACCESS_MASK;

                if field_access == FieldAttributes::PUBLIC
                    && type_visibility == TypeAttributes::NOT_PUBLIC
                {
                    // Public field in internal type - this is sometimes valid
                    // but worth noting for consistency
                }

                if field.flags & 0x0040 != 0 && field.flags & FieldAttributes::STATIC == 0 {
                    // LITERAL flag but not static
                    let field_name = &field.name;
                    let type_name = &type_entry.name;
                    return Err(Error::ValidationOwnedFailed {
                        validator: self.name().to_string(),
                        message: format!(
                            "Literal field '{field_name}' in type '{type_name}' must be static"
                        ),
                    });
                }
            }
        }

        Ok(())
    }

    /// Validates interface implementation accessibility requirements.
    ///
    /// Ensures that types implementing interfaces have appropriate accessibility
    /// and that interface members are properly accessible. Validates interface
    /// field constraints and implementation patterns.
    ///
    /// # Arguments
    ///
    /// * `context` - Owned validation context containing resolved type structures via [`crate::metadata::validation::context::OwnedValidationContext`]
    ///
    /// # Returns
    ///
    /// * `Ok(())` - All interface accessibility requirements are met
    /// * `Err(`[`crate::Error::ValidationOwnedFailed`]`)` - Interface accessibility violations found
    ///
    /// # Errors
    ///
    /// Returns [`crate::Error::ValidationOwnedFailed`] if:
    /// - Interface types have empty names
    /// - Interfaces contain non-static fields
    /// - Interfaces contain non-constant fields
    fn validate_interface_accessibility(&self, context: &OwnedValidationContext) -> Result<()> {
        for type_entry in context.all_types() {
            for (_, interface_ref) in type_entry.interfaces.iter() {
                let type_visibility = type_entry.flags & TypeAttributes::VISIBILITY_MASK;
                if let Some(interface_type) = interface_ref.upgrade() {
                    let interface_visibility =
                        interface_type.flags & TypeAttributes::VISIBILITY_MASK;

                    if interface_visibility == TypeAttributes::PUBLIC
                        && type_visibility == TypeAttributes::NOT_PUBLIC
                    {
                        // Internal type implementing public interface - this is valid
                    }

                    if interface_type.name.is_empty() {
                        return Err(Error::ValidationOwnedFailed {
                            validator: self.name().to_string(),
                            message: format!(
                                "Type '{}' implements interface with empty name",
                                type_entry.name
                            ),
                        });
                    }
                }
            }

            if type_entry.flags & TypeAttributes::INTERFACE != 0 {
                for (_, field) in type_entry.fields.iter() {
                    if field.flags & FieldAttributes::STATIC == 0 {
                        return Err(Error::ValidationOwnedFailed {
                            validator: self.name().to_string(),
                            message: format!(
                                "Interface '{}' contains non-static field '{}'",
                                type_entry.name, field.name
                            ),
                        });
                    }

                    if field.flags & 0x0040 == 0 {
                        // Not LITERAL
                        return Err(Error::ValidationOwnedFailed {
                            validator: self.name().to_string(),
                            message: format!(
                                "Interface '{}' contains non-constant field '{}'",
                                type_entry.name, field.name
                            ),
                        });
                    }
                }
            }
        }

        Ok(())
    }

    /// Validates accessibility inheritance patterns.
    ///
    /// Ensures that derived types maintain appropriate accessibility relative
    /// to their base types and that inheritance accessibility rules are followed.
    /// Validates abstract and sealed type combinations.
    ///
    /// # Arguments
    ///
    /// * `context` - Owned validation context containing resolved type structures via [`crate::metadata::validation::context::OwnedValidationContext`]
    ///
    /// # Returns
    ///
    /// * `Ok(())` - All inheritance accessibility patterns are valid
    /// * `Err(`[`crate::Error::ValidationOwnedFailed`]`)` - Inheritance accessibility violations found
    ///
    /// # Errors
    ///
    /// Returns [`crate::Error::ValidationOwnedFailed`] if inheritance accessibility patterns are violated
    /// (specific violations depend on resolved type hierarchy analysis).
    fn validate_inheritance_accessibility(context: &OwnedValidationContext) {
        for type_entry in context.all_types() {
            // ToDo: For complete inheritance validation, we need to resolve
            // base type references and check accessibility consistency

            // Basic validation: sealed types cannot be abstract (except for static classes)
            if type_entry.flags & 0x0000_0100 != 0 {
                // SEALED flag
                if type_entry.flags & 0x0000_0080 != 0 {
                    // ABSTRACT flag - this is valid for static classes in C#
                    // Static classes are marked as both abstract and sealed by the compiler
                    // We allow this legitimate pattern
                }
            }

            // Abstract types can be interfaces - interfaces are inherently abstract
            if type_entry.flags & 0x0000_0080 != 0 {
                // ABSTRACT flag
                if type_entry.flags & TypeAttributes::INTERFACE != 0 {
                    // Interfaces can be marked as abstract - this is standard behavior
                }
            }
        }
    }
}

impl OwnedValidator for OwnedAccessibilityValidator {
    fn validate_owned(&self, context: &OwnedValidationContext) -> Result<()> {
        self.validate_type_accessibility(context)?;
        self.validate_member_accessibility(context)?;
        self.validate_interface_accessibility(context)?;
        Self::validate_inheritance_accessibility(context);

        Ok(())
    }

    fn name(&self) -> &'static str {
        "OwnedAccessibilityValidator"
    }

    fn priority(&self) -> u32 {
        160
    }

    fn should_run(&self, context: &OwnedValidationContext) -> bool {
        context.config().enable_semantic_validation
    }
}

impl Default for OwnedAccessibilityValidator {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
#[cfg_attr(feature = "skip-expensive-tests", allow(unused_imports))]
mod tests {
    use super::*;
    use crate::{
        metadata::validation::ValidationConfig,
        test::{
            factories::validation::members_accessibility::owned_accessibility_validator_file_factory,
            owned_validator_test,
        },
    };

    #[test]
    #[cfg(not(feature = "skip-expensive-tests"))]
    fn test_owned_accessibility_validator() -> Result<()> {
        let validator = OwnedAccessibilityValidator::new();
        let config = ValidationConfig {
            enable_semantic_validation: true,
            ..Default::default()
        };

        owned_validator_test(
            owned_accessibility_validator_file_factory,
            "OwnedAccessibilityValidator",
            "ValidationOwnedFailed",
            config,
            |context| validator.validate_owned(context),
        )
    }
}