// CWE-704: Incorrect Type Conversion — .cast() bypasses MoonBit's type system.
// Filter: skip files containing extern "js" — FFI bindings require .cast() as the only conversion mechanism.
///|
priv struct Cwe704Visitor {
findings : Array[Finding]
file : String
source : String
severity : Severity
}
///|
pub fn cwe704_info() -> RuleInfo {
{
id: { cwe: 704, variant: "unsafe-cast" },
name: "Unchecked Type Cast",
description: ".cast() bypasses type checking at runtime. Invalid casts can produce corrupted values or undefined behavior.",
default_severity: Warning,
}
}
///|
pub fn run_cwe704(
impls : @list.List[@syntax.Impl],
file : String,
source : String,
findings : Array[Finding],
severity : Severity,
) -> Unit {
if is_ffi_file(source) {
return
}
let visitor : Cwe704Visitor = { findings, file, source, severity }
impls.each(fn(impl_) { @syntax.IterVisitor::visit_Impl(visitor, impl_) })
}
///|
fn is_ffi_file(source : String) -> Bool {
source.contains("extern \"js\"") ||
source.contains("extern \"javascript\"") ||
source.contains("#external")
}
///|
impl @syntax.IterVisitor for Cwe704Visitor with fn visit_Expr_DotApply(
env,
self~,
method_name~,
args~,
return_self~,
loc~,
) {
if method_name.name == "cast" || method_name.name == "reinterpret_cast" {
env.findings.push(
make_finding(
{ cwe: 704, variant: "unsafe-cast" },
env.severity,
Medium,
"Unchecked .cast() bypasses type safety. The result may be invalid if the underlying value does not match the target type.",
env.file,
env.source,
loc,
),
)
}
@syntax.IterVisitor::base(env).visit_Expr_DotApply(
self~,
method_name~,
args~,
return_self~,
loc~,
)
}