Skip to content

[CERT C Review Batch 3/5] Review proposed Rust categorization #429

Description

@PLeVasseur

Context

Thanks for taking a look at this batch.

This issue is part of the follow-on work from #336, where Félix finished a first pass mapping CERT C rules into Rust-oriented categories.

The goal here is to get a focused review on one slice of the 103 rules without making anyone wade through the whole set at once.

If you notice something that cuts across batches, or you want to leave a more global comment, please put that on #336.

If you want to read the original CERT wording before reviewing a mapping, the rule IDs in the table below link directly to the CMU SEI Confluence page for each rule. You may also find the top-level SEI CERT C Coding Standard useful for broader context.

Reviewer note

Please feel free to leave working notes here as you go.

When you feel done with this batch, please leave a short final summary on #336 and link back to this issue so the parent thread stays the main record of the outcome.

Review goal

For each rule below, please check whether the current proposed bucket still feels right for Rust.

If you disagree, are unsure, or think the rule should be merged with another concern, that is useful feedback too. A short rationale is enough.

Current buckets:

  • Does not map to Rust
  • Definitely maps to Rust
  • Maybe
  • Maps directly to Unsafe Rust

Rules in this batch

Please do not feel boxed in by the current buckets. If one of these looks miscategorized, that is exactly the kind of feedback we want.

ID CERT C rule Current proposed bucket Notes Feedback
PRE32 Do not use preprocessor directives in invocations of function-like macros Does not map to Rust
Why not?This rule is needed in C due to how its preprocessor works. It's very C-preprocessor-specific, and doesn't map to Rust
feedback
DCL31 Declare identifiers before using them Does not map to Rust
Why not?Inferred types in Rust must always type-check. Not doing so results in a compile-time error. Therefore, the use case for this rule doesn't exist in Rust.
feedback
DCL37 Do not declare or define a reserved identifier
Click for contextIn C, reserved identifiers include more than just keywords. They include library functions and variables (eg memcpy, errno)), including some well-known ones (eg abs). C also lists many identifiers as potentially reserved (eg anything beginning with str).
It is possible to redefine (and thus override) such global identifiers in C, such as by adding
#define errno my_errno to a header, which would break most C programs.
Does not map to Rust
Why not? Rust's scoping rules already prevent this kind of breakage. Any form of behavior override is locally scoped, and explicitly opted into by the affected parts.
1, 2, 3
EXP37 Call functions with the correct number and type of arguments Does not map to Rust
Why not?This is enforced by the type system
feedback
EXP44 Do not rely on side effects in operands to sizeof, _Alignof or _Generic Does not map to Rust
Why not? This is C-specific
feedback
EXP47 Do not call va_arg with an argument of the incorrect type Does not map to Rust
Why not?Variadic Functions don't exist in Safe Rust. They do exist in Unsafe Rust, in the form of C's Variadic Functions. These exist as a way to declare and implement variadic functions for FFI contexts.

That being said, this rule doesn't map to Rust, because while it is possible to implement C variadic functions incorrectly, that issue is covered by the more general rule of Callers of any unsafe fn shall abide by the function's Safety contract.

Addendum: it is very reasonable to argue for a rule along the lines of "C-variadic functions should not be used outside of FFI contexts", but such a rule would not be a mapping of CERT-C's EXP47 rule. That is left for future work.
1, 2, 3
STR34 Cast characters to unsigned char before converting to larger integer sizes Does not map to Rust
Why not?Characters in Rust are not integers.
They are unicode scalar values.
feedback
FIO30 Exclude user input from format strings Does not map to Rust
Why not?Format strings are evaluated at compile time in Rust
feedback
FIO41 Do not call getc(), putc(), getwc() or putwc() with a stream argument that has side effects Does not map to Rust
Why not?This rule arises from how those APIs are implemented (as C macros), and not from a more general aspect of the situation.
feedback
ENV30 Do not modify the object referenced by the return value of certain functions Does not map to Rust
Why not?Immutability, when required, is always enforced in Rust.

I believe that Unsafe Rust could get away with doing this, jumping through some hoops. But that would lie in the vecinity of "Do not modify values whose validity invariant requires them to be immutable". Breaking validity invariants is, of course, UB.
feedback
ENV32 All exit handlers must return normally Does not map to Rust
Why not?Panicking doesn't have UB. Panics inside of panics will eventually abort the program.
feedback
ERR34 Detect errors when converting a string to a number Does not map to Rust
Why not?Functions in std that may fail, wrap their result in the Result<T, E> type, which forces the caller to handle the error case whenever it happens. Thus, this rule is already enforced by the compiler.
feedback
INT31 Ensure that integer conversions do not result in lost or misinterpreted data Definitely maps to Rust Already being worked in #185; still review mapping/category feedback
FLP32 Prevent or detect domain and range errors in math functions Definitely maps to Rust feedback
ENV33 Do not call system() Definitely maps to Rust
How would it map?The mapping is not exact (it doesn't involve system()):

If running commands, their input must always be sanitized, and their behavior should be made portable.

There is a Clippy lint that touches on this topic. We probably want a set of rules to address how system commands may be called.
1, 2, 3
MSC41 Never hard code sensitive information Definitely maps to Rust feedback
MEM31 Free dynamically allocated memory when no longer needed Maybe
RationaleThe Rust compiler mostly enforces this automatically.

Important exceptions in Safe Rust are std::rc::Rc/std::sync::Arc cycles, which the user should avoid using the corresponding std::rc::Weak and std::sync::Weak.

Memory leaks in Rust are relatively easy to avoid (compared to manual malloc and free in C), but they are nonetheless still possible. Furthermore, memory leaks are considered safe in Rust.

Much like the original rule, our mapping would describe a defect of low severity, as their worst possible consequence is a Denial of Service due to memory exhaustion.
feedback
DCL30 Declare objects with appropriate storage durations Maps directly to Unsafe Rust
How would it map? In Safe Rust, the borrow checker enforces all accesses to memory to be within the lifetime of said memory.

In Unsafe, the borrow checker is not disabled. However, it is possible to use unsafe features to extend the lifetime of references (e.g. transmute or raw pointers). This is not always UB; the user must document and justify their decision to extend a lifetime, explaining why it's correct to do so.

That being said, almost all of Unsafe can be used to perform a use-after-free. So it might be the case that this rule spawns multiple others.

Zulip thread: Quick questions about UB
feedback
EXP42 Do not compare padding data Maps directly to Unsafe Rust
How would it map? Byte-wise comparisons are impossible in Safe Rust.

You can do so in Unsafe Rust, but this is discouraged nonetheless: there's no guarantee as to what the value of padding bits will be. Just don't do it!

UCG: Padding may be a good supplementary source for this.
feedback
ENV31 Do not rely on an environment pointer following an operation that may invalidate it Maps directly to Unsafe Rust Recently moved into the unsafe bucket

RationaleThis interaction maps to Rust through the std::env::set_var and std::env::remove_var APIs.

In Unix, they are only safe to use in single-threaded programs. Such is the reality of those system APIs at the moment of writing (28-Feb-2026).

The rule would forbid both APIs in multithreaded code running on Unix systems.
feedback

What would help

  • Each rule is either confirmed, challenged, or marked as needing more discussion.
  • Any merged rules or overlapping concerns are called out explicitly.
  • Any rule that looks like a good follow-up coding guideline issue is noted.
  • A short summary is posted on #336 with a link back to this issue.

After opening this issue

Post this comment to request a reviewer from the Producer queue:

@guidelines-bot /r? producers

Metadata

Metadata

Labels

CERT CIssues or coding guidelines directly related to the CERT C Coding Guidelinesstatus: reviewer reassignment neededReviewer-bot exhausted the active reviewer cycle and reassignment may be neededtracking issueA tracking issue for longer running items

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions