// CWE-676: Use of potentially dangerous unsafe_* functions that bypass MoonBit's safety guarantees.
// Filters:
// - Skip performance-oriented unsafe ops (get/set/blit/reinterpret/read/write/pop)
// that only skip bounds checks but don't produce potentially invalid values.
// - Skip when call is inside a guard body — the guard validates input before the unsafe call.
// Only report type-conversion unsafe ops (to_*/from_*/new/cast) that can produce invalid values.
///|
priv struct Cwe676Visitor {
findings : Array[Finding]
file : String
source : String
severity : Severity
mut in_guard_body : Bool
}
///|
pub fn cwe676_info() -> RuleInfo {
{
id: { cwe: 676, variant: "unsafe-call" },
name: "Use of Potentially Dangerous unsafe_ Function",
description: "Calls to unsafe_* functions (unsafe_to_char, unsafe_to_byte, etc.) bypass runtime safety checks and may cause undefined behavior on invalid input.",
default_severity: Warning,
}
}
///|
pub fn run_cwe676(
impls : @list.List[@syntax.Impl],
file : String,
source : String,
findings : Array[Finding],
severity : Severity,
) -> Unit {
let visitor : Cwe676Visitor = {
findings,
file,
source,
severity,
in_guard_body: false,
}
impls.each(fn(impl_) { @syntax.IterVisitor::visit_Impl(visitor, impl_) })
}
///|
fn is_dangerous_unsafe(name : String) -> Bool {
if !name.has_prefix("unsafe_") {
return false
}
let suffix = name[7:].to_owned()
if suffix == "to_char" || suffix == "to_byte" {
return false
}
if suffix.has_prefix("to_") || suffix.has_prefix("from_") {
return true
}
suffix == "new" || suffix == "cast"
}
///|
impl @syntax.IterVisitor for Cwe676Visitor with fn visit_Expr_Guard(
env,
cond~,
otherwise~,
body~,
exclamation~,
guard_loc~,
loc~,
) {
let _ = (loc, exclamation, guard_loc)
@syntax.IterVisitor::base(env).visit_Expr(cond)
match otherwise {
Some(else_expr) => @syntax.IterVisitor::base(env).visit_Expr(else_expr)
None => ()
}
let prev = env.in_guard_body
env.in_guard_body = true
@syntax.IterVisitor::base(env).visit_Expr(body)
env.in_guard_body = prev
}
///|
impl @syntax.IterVisitor for Cwe676Visitor with fn visit_Expr_DotApply(
env,
self~,
method_name~,
args~,
return_self~,
loc~,
) {
if is_dangerous_unsafe(method_name.name) && !env.in_guard_body {
env.findings.push(
make_finding(
{ cwe: 676, variant: "unsafe-call" },
env.severity,
High,
"unsafe_* function bypasses runtime safety checks. Ensure input is validated before this call, or use a safe alternative.",
env.file,
env.source,
loc,
),
)
}
@syntax.IterVisitor::base(env).visit_Expr_DotApply(
self~,
method_name~,
args~,
return_self~,
loc~,
)
}
///|
impl @syntax.IterVisitor for Cwe676Visitor with fn visit_Expr_Apply(
env,
func~,
args~,
loc~,
) {
let unsafe_name = match func {
Ident(id~, ..) =>
match id.name {
Ident(name=n) => n
Dot(id=n, ..) => n
}
Method(method_name~, ..) => method_name.name
_ => ""
}
if is_dangerous_unsafe(unsafe_name) && !env.in_guard_body {
env.findings.push(
make_finding(
{ cwe: 676, variant: "unsafe-call" },
env.severity,
High,
"unsafe_* function bypasses runtime safety checks. Ensure input is validated before this call, or use a safe alternative.",
env.file,
env.source,
loc,
),
)
}
@syntax.IterVisitor::base(env).visit_Expr_Apply(func~, args~, loc~)
}