Skip to main content

synth_frontend/
validator.rs

1//! WebAssembly Component Validator
2
3use synth_core::{Component, Error, Result};
4
5/// Component validator
6pub struct ComponentValidator;
7
8impl ComponentValidator {
9    /// Create a new validator
10    pub fn new() -> Self {
11        Self
12    }
13
14    /// Validate a component
15    pub fn validate(&self, component: &Component) -> Result<()> {
16        // Basic validation checks
17
18        // Check that we have at least one module
19        if component.modules.is_empty() {
20            return Err(Error::validation("Component must have at least one module"));
21        }
22
23        // Validate memory requirements
24        let total_memory = component.total_memory_size();
25        if total_memory == 0 {
26            tracing::warn!("Component has no linear memory");
27        }
28
29        // Check for memory limits (e.g., 4GB limit for 32-bit)
30        const MAX_MEMORY_32BIT: u64 = 4 * 1024 * 1024 * 1024; // 4GB
31        if total_memory > MAX_MEMORY_32BIT {
32            return Err(Error::validation(format!(
33                "Total memory ({} bytes) exceeds 32-bit limit",
34                total_memory
35            )));
36        }
37
38        // Validate each module
39        for module in &component.modules {
40            self.validate_module(module)?;
41        }
42
43        Ok(())
44    }
45
46    /// Validate a single module
47    fn validate_module(&self, module: &synth_core::CoreModule) -> Result<()> {
48        // Check module has valid binary
49        if module.binary.is_empty() {
50            return Err(Error::validation("Module has empty binary"));
51        }
52
53        // Check WebAssembly magic number
54        if module.binary.len() < 8 {
55            return Err(Error::validation("Module binary too short"));
56        }
57
58        let magic = &module.binary[0..4];
59        if magic != b"\x00asm" {
60            return Err(Error::validation("Invalid WebAssembly magic number"));
61        }
62
63        // Validate memories
64        for memory in &module.memories {
65            // Check that initial size is not larger than maximum
66            if let Some(max) = memory.maximum
67                && memory.initial > max
68            {
69                return Err(Error::validation(format!(
70                    "Memory initial size ({}) exceeds maximum ({})",
71                    memory.initial, max
72                )));
73            }
74
75            // Check reasonable limits (e.g., 4GB = 65536 pages for 32-bit)
76            const MAX_PAGES_32BIT: u32 = 65536;
77            if memory.initial > MAX_PAGES_32BIT {
78                return Err(Error::validation(format!(
79                    "Memory initial size ({} pages) exceeds 32-bit limit",
80                    memory.initial
81                )));
82            }
83        }
84
85        Ok(())
86    }
87}
88
89impl Default for ComponentValidator {
90    fn default() -> Self {
91        Self::new()
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98    use synth_core::{Component, CoreModule};
99
100    #[test]
101    fn test_validate_empty_component() {
102        let component = Component::new("test".to_string());
103        let validator = ComponentValidator::new();
104
105        let result = validator.validate(&component);
106        assert!(result.is_err()); // Should fail - no modules
107    }
108
109    #[test]
110    fn test_validate_valid_component() {
111        let mut component = Component::new("test".to_string());
112
113        // Add a module with valid WebAssembly magic
114        let module = CoreModule {
115            id: "module0".to_string(),
116            binary: vec![0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00],
117            functions: Vec::new(),
118            memories: Vec::new(),
119            tables: Vec::new(),
120            globals: Vec::new(),
121        };
122        component.modules.push(module);
123
124        let validator = ComponentValidator::new();
125        let result = validator.validate(&component);
126        assert!(result.is_ok());
127    }
128}