@@ -2,21 +2,19 @@ use crate::module_info::ModuleInfo;
2
2
3
3
pub const EARLIEST_PROBABLY_SAFE_CLANG_VERSION : & str = "15.0.7" ;
4
4
5
- /// Represents the detected likelihood of the allocation bug fixed in
6
- /// https://github.com/WebAssembly/wasi-libc/pull/377 being present in a Wasm
7
- /// module.
5
+ /// This error represents the likely presence of the allocation bug fixed in
6
+ /// https://github.com/WebAssembly/wasi-libc/pull/377 in a Wasm module.
8
7
#[ derive( Debug , PartialEq ) ]
9
- pub enum WasiLibc377Bug {
10
- ProbablySafe ,
11
- ProbablyUnsafe { clang_version : String } ,
12
- Unknown ,
8
+ pub struct WasiLibc377Bug {
9
+ clang_version : Option < String > ,
13
10
}
14
11
15
12
impl WasiLibc377Bug {
16
- pub fn detect ( module_info : & ModuleInfo ) -> anyhow:: Result < Self > {
13
+ /// Detects the likely presence of this bug.
14
+ pub fn check ( module_info : & ModuleInfo ) -> Result < ( ) , Self > {
17
15
if module_info. probably_uses_wit_bindgen ( ) {
18
16
// Modules built with wit-bindgen are probably safe.
19
- return Ok ( Self :: ProbablySafe ) ;
17
+ return Ok ( ( ) ) ;
20
18
}
21
19
if let Some ( clang_version) = & module_info. clang_version {
22
20
// Clang/LLVM version is a good proxy for wasi-sdk
@@ -25,12 +23,12 @@ impl WasiLibc377Bug {
25
23
if let Some ( ( major, minor, patch) ) = parse_clang_version ( clang_version) {
26
24
let earliest_safe =
27
25
parse_clang_version ( EARLIEST_PROBABLY_SAFE_CLANG_VERSION ) . unwrap ( ) ;
28
- return if ( major, minor, patch) >= earliest_safe {
29
- Ok ( Self :: ProbablySafe )
26
+ if ( major, minor, patch) >= earliest_safe {
27
+ return Ok ( ( ) ) ;
30
28
} else {
31
- Ok ( Self :: ProbablyUnsafe {
32
- clang_version : clang_version. clone ( ) ,
33
- } )
29
+ return Err ( Self {
30
+ clang_version : Some ( clang_version. clone ( ) ) ,
31
+ } ) ;
34
32
} ;
35
33
} else {
36
34
tracing:: warn!(
@@ -39,10 +37,27 @@ impl WasiLibc377Bug {
39
37
) ;
40
38
}
41
39
}
42
- Ok ( Self :: Unknown )
40
+ // If we can't assert that the module uses wit-bindgen OR was compiled
41
+ // with a new-enough wasi-sdk, conservatively assume it may be buggy.
42
+ Err ( Self {
43
+ clang_version : None ,
44
+ } )
43
45
}
44
46
}
45
47
48
+ impl std:: fmt:: Display for WasiLibc377Bug {
49
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
50
+ write ! (
51
+ f,
52
+ "This Wasm module may have been compiled with wasi-sdk version <19 which \
53
+ contains a critical memory safety bug. For more information, see: \
54
+ https://github.com/fermyon/spin/issues/2552"
55
+ )
56
+ }
57
+ }
58
+
59
+ impl std:: error:: Error for WasiLibc377Bug { }
60
+
46
61
fn parse_clang_version ( ver : & str ) -> Option < ( u16 , u16 , u16 ) > {
47
62
// Strip optional trailing detail after space
48
63
let ver = ver. split ( ' ' ) . next ( ) . unwrap ( ) ;
@@ -59,47 +74,42 @@ mod tests {
59
74
60
75
#[ test]
61
76
fn wasi_libc_377_detect ( ) {
62
- use WasiLibc377Bug :: * ;
63
- for ( wasm, expected) in [
64
- ( r#"(module)"# , Unknown ) ,
77
+ for ( wasm, safe) in [
78
+ ( r#"(module)"# , false ) ,
65
79
(
66
80
r#"(module (func (export "cabi_realloc") (unreachable)))"# ,
67
- ProbablySafe ,
81
+ true ,
68
82
) ,
69
83
(
70
84
r#"(module (func (export "some_other_function") (unreachable)))"# ,
71
- Unknown ,
85
+ false ,
72
86
) ,
73
87
(
74
88
r#"(module (@producers (processed-by "clang" "16.0.0 extra-stuff")))"# ,
75
- ProbablySafe ,
89
+ true ,
76
90
) ,
77
91
(
78
92
r#"(module (@producers (processed-by "clang" "15.0.7")))"# ,
79
- ProbablySafe ,
93
+ true ,
80
94
) ,
81
95
(
82
96
r#"(module (@producers (processed-by "clang" "15.0.6")))"# ,
83
- ProbablyUnsafe {
84
- clang_version : "15.0.6" . into ( ) ,
85
- } ,
97
+ false ,
86
98
) ,
87
99
(
88
100
r#"(module (@producers (processed-by "clang" "14.0.0 extra-stuff")))"# ,
89
- ProbablyUnsafe {
90
- clang_version : "14.0.0 extra-stuff" . into ( ) ,
91
- } ,
101
+ false ,
92
102
) ,
93
103
(
94
104
r#"(module (@producers (processed-by "clang" "a.b.c")))"# ,
95
- Unknown ,
105
+ false ,
96
106
) ,
97
107
] {
98
108
eprintln ! ( "WAT: {wasm}" ) ;
99
109
let module = wat:: parse_str ( wasm) . unwrap ( ) ;
100
110
let module_info = ModuleInfo :: from_module ( & module) . unwrap ( ) ;
101
- let detected = WasiLibc377Bug :: detect ( & module_info) . unwrap ( ) ;
102
- assert_eq ! ( detected, expected ) ;
111
+ let detected = WasiLibc377Bug :: check ( & module_info) ;
112
+ assert ! ( detected. is_ok ( ) == safe , "{wasm} -> {detected:?}" ) ;
103
113
}
104
114
}
105
115
}
0 commit comments