dotscope 0.6.0

A high-performance, cross-platform framework for analyzing and reverse engineering .NET PE executables
Documentation
//! `CustomAttribute` table loader implementation.
//!
//! This module provides the [`crate::metadata::tables::customattribute::loader::CustomAttributeLoader`]
//! implementation for loading `CustomAttribute` metadata from the ECMA-335 `CustomAttribute` table (0x0C).
//! The loader processes custom attribute instances that decorate metadata elements with additional
//! compile-time information, integrating this data with existing metadata entries.
//!
//! # Architecture
//!
//! The loader follows the standard metadata loading pattern, implementing the
//! [`crate::metadata::loader::MetadataLoader`] trait to process table data and integrate
//! custom attribute instances with previously loaded metadata elements across all table types.
//!
//! # Key Components
//!
//! - [`crate::metadata::tables::customattribute::loader::CustomAttributeLoader`] - Main loader implementation
//! - [`crate::metadata::tables::customattribute::CustomAttributeRaw`] - Raw table row structure
//! - [`crate::metadata::loader::LoaderContext`] - Context for loading operations
//!
//! # Table Structure
//!
//! The `CustomAttribute` table contains zero or more rows that associate attributes with metadata elements:
//! - **Parent**: Coded index referencing the metadata element decorated with the attribute
//! - **Type**: Coded index referencing the attribute constructor (`MethodDef` or `MemberRef`)
//! - **Value**: Blob heap reference containing the serialized attribute arguments
//!
//! # Custom Attribute Processing
//!
//! Custom attributes provide extensible metadata decoration throughout .NET assemblies:
//! - **Attribute constructors**: Resolution of constructor methods that define attribute structure
//! - **Argument serialization**: Decoding of serialized attribute constructor and property arguments
//! - **Target validation**: Ensuring attributes are applicable to their target metadata elements
//! - **Reflection support**: Providing runtime access to attribute data and metadata
//!
//! # Dependencies
//!
//! This loader depends on virtually all other metadata tables being loaded first, as custom
//! attributes can be applied to almost any metadata element type.
//!
//! # Integration
//!
//! This module integrates with:
//! - [`crate::metadata::loader`] - Core metadata loading infrastructure
//! - [`crate::metadata::tables`] - All metadata table types for attribute targets
//! - [`crate::metadata::streams::Blob`] - Blob heap for attribute data
//! - [`crate::metadata::tables::customattribute`] - `CustomAttribute` table types
//!
//! # Thread Safety
//!
//! The loader is thread-safe and uses parallel iteration for performance when processing
//! multiple `CustomAttribute` entries. Updates to target elements are handled through
//! atomic operations.
//!
//! # References
//!
//! - [ECMA-335 II.22.10](https://ecma-international.org/wp-content/uploads/ECMA-335_6th_edition_june_2012.pdf) - `CustomAttribute` table specification

use crate::{
    metadata::{
        diagnostics::DiagnosticCategory,
        loader::{LoaderContext, MetadataLoader},
        tables::CustomAttributeRaw,
    },
    prelude::TableId,
    Result,
};

/// Loader for the `CustomAttribute` metadata table
///
/// Implements [`crate::metadata::loader::MetadataLoader`] to process the `CustomAttribute` table (0x0C)
/// which contains custom attribute instances applied to various metadata elements. Custom attributes
/// provide extensible metadata decoration throughout .NET assemblies.
///
/// # Attribute Processing
///
/// The loader handles various custom attribute scenarios:
/// - **Built-in attributes**: System attributes like `[Obsolete]`, `[Serializable]`, etc.
/// - **User-defined attributes**: Custom attribute classes defined within the assembly
/// - **Framework attributes**: Attributes from external assemblies and the Base Class Library
/// - **Compiler attributes**: Attributes generated by language compilers for metadata
///
/// # Thread Safety
///
/// This type is [`Send`] and [`Sync`] as it contains no mutable state and all operations
/// are read-only during the metadata loading phase. The loader uses parallel iteration
/// for performance when processing multiple `CustomAttribute` entries.
pub(crate) struct CustomAttributeLoader;

impl MetadataLoader for CustomAttributeLoader {
    /// Load `CustomAttribute` metadata and associate with target elements
    ///
    /// Processes all rows in the `CustomAttribute` table, resolving references to target metadata
    /// elements and attribute constructors, as well as deserializing attribute argument data.
    /// Each processed attribute is applied to its target element and stored in the
    /// loader context for subsequent access.
    ///
    /// # Arguments
    ///
    /// * `context` - [`crate::metadata::loader::LoaderContext`] containing metadata tables, heap references, and storage collections
    ///
    /// # Returns
    ///
    /// * `Ok(())` - All `CustomAttribute` entries successfully processed and applied
    /// * `Err(`[`crate::Error`]`)` - Processing failed due to malformed data or missing dependencies
    ///
    /// # Errors
    ///
    /// Returns [`crate::Error`] in the following cases:
    /// - Target metadata element references are invalid or missing
    /// - Attribute constructor references are invalid or missing
    /// - Blob heap references are invalid or corrupted
    /// - `CustomAttribute` table structure is malformed
    /// - Attribute data deserialization fails
    /// - Integration with target elements fails
    ///
    /// # Thread Safety
    ///
    /// This method is thread-safe and uses parallel iteration for performance.
    /// Updates to target elements are handled through atomic operations.
    fn load(&self, context: &LoaderContext) -> Result<()> {
        let (Some(header), Some(blob)) = (context.meta, context.blobs) else {
            return Ok(());
        };
        let Some(table) = header.table::<CustomAttributeRaw>() else {
            return Ok(());
        };

        table.par_iter().try_for_each(|row| {
            let token_msg = || format!("custom attribute 0x{:08x}", row.token.value());

            let Some(owned) = context.handle_result(
                row.to_owned(
                    |coded_index| context.get_ref(coded_index),
                    blob,
                    Some(context.types),
                ),
                DiagnosticCategory::CustomAttribute,
                token_msg,
            )?
            else {
                return Ok(());
            };

            context.handle_error(
                owned.apply(),
                DiagnosticCategory::CustomAttribute,
                token_msg,
            )?;
            context.custom_attribute.insert(row.token, owned);
            Ok(())
        })
    }

    /// Returns the table identifier for `CustomAttribute`
    ///
    /// Provides the [`crate::prelude::TableId::CustomAttribute`] constant used to identify this table
    /// type within the metadata loading framework.
    fn table_id(&self) -> Option<TableId> {
        Some(TableId::CustomAttribute)
    }

    /// Returns the table dependencies for `CustomAttribute` loading
    ///
    /// Specifies the extensive list of tables that `CustomAttribute` loading depends on.
    /// Custom attributes can be applied to almost any metadata element, requiring
    /// that all potential target tables are loaded before attribute associations
    /// are established. This dependency ordering prevents resolution failures
    /// during the loading process.
    ///
    /// Dependencies include type system tables, member tables, module tables,
    /// assembly tables, security tables, generic tables, resource tables, and
    /// signature tables to cover all possible attribute targets.
    fn dependencies(&self) -> &'static [TableId] {
        &[
            TableId::MethodDef,
            TableId::Field,
            TableId::TypeRef,
            TableId::TypeDef,
            TableId::Param,
            TableId::InterfaceImpl,
            TableId::MemberRef,
            TableId::Module,
            TableId::DeclSecurity,
            TableId::NestedClass,
            TableId::Property,
            TableId::Event,
            TableId::StandAloneSig,
            TableId::ModuleRef,
            TableId::TypeSpec,
            TableId::Assembly,
            TableId::AssemblyRef,
            TableId::File,
            TableId::ExportedType,
            TableId::ManifestResource,
            TableId::GenericParam,
            TableId::GenericParamConstraint,
            TableId::MethodSpec,
        ]
    }
}