Rust Cross Reference with CERT-C 2016 ======================================= The following tables provide a cross reference between the CERT-C 2025 guidelines and their applicability to Rust. The first table covers guidelines that are applicable to Rust in general, while the second table covers additional guidelines that are applicable in the presence of unsafe code. The third table lists guidelines that are not applicable to Rust. Table 1 – Guidelines applicable to Rust in general (safe Rust, no unsafe code present) -------------------------------------------------------------------------------------- .. list-table:: :widths: 14 14 14 14 14 :header-rows: 1 * - Guideline - Title - Category - Safety Critical rust Rule - Comment * - `FLP37 `__ - Do not use object representations to compare floating-point values - - - It might not be immediately obvious where this might be done on purpose. It is certainly not something one would imagine happening in a self-contained system that’s using floating point numbers. However, **when receiving raw floating point data**, it can be extremely tempting to “just compare the bits”. What’s worse is that **this approach would work for some values**, which might mask its lack of correctness. For completeness, it would be good to mention examples of FP values with different encodings that however compare equal under the standard. The simplest one here is, I think, ``0`` v/s ``-0``, which would bitwise compare different and yet are considered equal under the IEEE FP standard. **Bonus idea:** we might want to have a float-equality guideline with regards to ``NaN``, since ``NaN != NaN`` even when the encoding is the same. For answering the question of “is this value ``NaN``?”, we have the ```is_nan`` `__ method. * - `DCL39 `__ - Avoid information leakage when passing a structure across a trust boundary - - - It seems to be technically possible to achieve, using Unsafe. Zulip thread of this discussion: `How should padding bits be erased for sending? `__\ The important issue seems to be that of copying into the untrusted buffer without copying sensitive data that may lie in the uninitialized bits of the copied struct.For structs and enums, this seems to be solvable by making a type which copies everything except for the padding bits inside of it.For unions, one might want to be REALLY SURE, and hopefully prove, that you’re not copying your padding. Might be impossible to safely send unions.\ *One might want also to zero-out sensitive memory in their own processes, such that nothing sensitive is left behind after they end.* **That’s outside the scope of our work.** *Zulip thread on this:* `Are bits erased on drop? If not, how can I ensure they are? `__ * - `INT36 `__ - Converting a pointer to integer or integer to pointer - - - With modifications:- ptr2int: considered to be relatively unimportant- int2ptr: cautioned against\ **Pointer Provenance** plays a role in this.\ *Also, see:* `transmute: caution against int2ptr transmutation `__\ May deserve scrutiny for possible unsafe-heavy treatment * - `CON40 `__ - Do not refer to an atomic variable twice in an expression - - - * - `CON36 `__ - Wrap functions that can spuriously wake up in a loop - - - This directly maps to the usage of ```std::sync::Condvar`` `__, in particular while using its ```wait`` `__ and ```wait_timeout`` `__ methods.To correctly wrap these spurious wake-ups in a loop, the methods ```wait_while`` `__ and ```wait_timeout_while`` `__ are respectively provided, and should probably be recommended in their place. * - `EXP40 `__ - Do not modify constant objects - - - ``const`` items can’t be modified - they are actually inlined at every point of usage, so modifying them wouldn’t do a thing anyways. So this is not about ``const`` in the case of Rust.On the other hand, ``static`` items can be modified, but only in ``unsafe`` code. And this is by design - some things are meant to be “global items with special case mutability”A difference must be made, however, with regards to ``static`` and ``static mut`` variables, because as expressed `here `__, the latter is incredibly prone to UB. ``static`` variables can be used with a lot more ease (still with plenty of caution!), using `the interior mutability pattern `__, covering the vast majority of use-cases for global mutable state.\ *My current line of thought is that ``static mut`` should be forbidden as either a Mandatory rule (i.e. with no exceptions) or a Required rule with well-documented reasoning about its safety. Remember:* `usage of ``static mut`` very easily results in UB. `__\ \ *As for ``static``, I think I would like us to have an Advisory rule recommending against them. Hopefully, such a rule would show examples of how to use ``static`` safely.*\ **Paired with STR30** * - `STR30 `__ - Do not attempt to modify string literals - - - Treat as **merged with EXP40** for Rust mapping purposes * - `INT30 `__ - Ensure that integer operations do not wrap - - - Already implemented; still review mapping/category * - `INT33 `__ - Ensure that division and remainder operations do not result in divide-by-zero errors - - - Already implemented; still review mapping/category * - `ARR30 `__ - Do not form or use out-of-bounds pointers or array subscripts - - - In Safe Rust:- Direct addressing will panic if OOB- arr.get(index) will return None if OOBIn Unsafe Rust:- arr.get_unchecked(index) is UB if OOB.So, I’d say out-of-bound indexing should be either prevented or handled properly.If using Unsafe indexing, it should be formally validated. * - `FIO45 `__ - Avoid TOCTOU race conditions while accessing files - - - *Rationale:* ```std::fs`` `__ `explicitly talks about TOCTOU `__ *and how to avoid it.* * - `FLP30 `__ - Do not use floating-point variables as loop counters - - - * - `INT31 `__ - Ensure that integer conversions do not result in lost or misinterpreted data - - - Already being worked in #185; still review mapping/category * - `FLP32 `__ - Prevent or detect domain and range errors in math functions - - - * - `ENV33 `__ - Do not call system() - - - 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. * - `MSC41 `__ - Never hard code sensitive information - - - * - `MEM31 `__ - Free dynamically allocated memory when no longer needed - - - The 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. * - `INT32 `__ - Ensure that operations on signed integers do not result in overflow - - - Already implemented; still review mapping/category * - `INT34 `__ - Do not shift an expression by a negative number of bits or by greater than or equal to the number of bits that exist in the operand - - - Already implemented; still review mapping/category * - `CON33 `__ - Avoid race conditions when using library functions - - - * - `CON41 `__ - Wrap functions that can spuriously fail in a loop - - - * - `ARR37 `__ - Do not add or subtract an integer to a pointer to a non-array object - - - * - `FLP34 `__ - Ensure that floating-point conversions are within range of the new type - - - * - `FLP36 `__ - Preserve precision when converting integral values to floating-point type - - - * - `FIO42 `__ - Close files when they are no longer needed - - - This is a good precept for life, I guess.In Rust, handling of such resources is a lot easier since their Drop implementation should close them automatically.It’s still good to keep in mind, and not make a file e.g. have the ``'static`` lifetime if that’s not necessary. * - `CON38 `__ - Preserve thread safety and liveness when using condition variables - - - So far, the consensus is to make the following recommendations:- *Consider not using ``Condvar`` if at all possible.*\ - *If using ``Condvar`` and liveness is critical, consider using ``notify_all`` instead of ``notify_one``.*\ Zulip discussion: `Recommending ``Condvar::notify_all`` instead of ``notify_one``? `__\ Higher-policy discussion expected * - `MSC32 `__ - Properly seed pseudorandom number generators - - - * - `MEM34 `__ - Only free memory allocated dynamically - - - * - `CON35 `__ - Avoid deadlock by locking in a predefined order - - - Table 2 – Guidelines applicable to Rust in the presence of unsafe code ---------------------------------------------------------------------- .. list-table:: :widths: 14 14 14 14 14 :header-rows: 1 * - Guideline - Title - Category - Safety Critical rust Rule - Comment * - `EXP39 `__ - Do not access a variable through a pointer of an incompatible type - - - * - `CON32 `__ - Prevent data races when accessing bit-fields from multiple threads - - - * - `CON43 `__ - Do not allow data races in multithreaded code - - - Treat as **paired with CON32** in Rust, as their requirements are the same * - `ARR36 `__ - Do not subtract or compare two pointers that do not refer to the same array - - - * - `MEM30 `__ - Do not access freed memory - - - * - `EXP34 `__ - Do not dereference null pointers - - - * - `DCL30 `__ - Declare objects with appropriate storage durations - - - * - `EXP42 `__ - Do not compare padding data - - - * - `ENV31 `__ - Do not rely on an environment pointer following an operation that may invalidate it - - - Recently moved into the unsafe bucket This 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. * - `EXP33 `__ - Do not read uninitialized memory - - - *Rationale: it’s UB in Rust* * - `MEM36 `__ - Do not modify the alignment of objects by calling realloc() - - - * - `CON34 `__ - Declare objects shared between threads with appropriate storage durations - - - * - `EXP36 `__ - Do not cast pointers into more strictly aligned pointer types - - - * - `MEM35 `__ - Allocate sufficient memory for an object - - - Table 3 – Guideline rules that are not applicable to Rust --------------------------------------------------------- .. list-table:: :widths: 14 14 14 14 14 :header-rows: 1 * - Guideline - Title - Category - Safety Critical rust Rule - Comment * - `PRE31 `__ - Avoid side effects in arguments to unsafe macros - - - **Context**\ *In C, “unsafe macro” means a macro that evaluates one of its parameters more than once or not at all. Doing so with side effects then means that those side effects are triggered either more than once, or not at all.*\ C macros make using this kind of pattern safely very hard.In Rust, this is not the case, and there are multiple examples of macros that use this pattern on purpose and successfully.There are multiple different use cases for this, in fact, as explained in `this comment on Zulip `__. Furthermore, if no side effecting is required, then the writer of the macro can enforce this using ``const`` blocks, as is explained in the `comment right after `__.There is no magic feature in Rust to stop a macro from expanding a side-effecting expression multiple times. However, doing so requires to be a lot more explicit about it. Therefore, if such a macro invocation is encountered in the wild, then chances are that the user meant to do exactly that.\ *Zulip thread:* `Macros and insertion of side-effecting metavariables `__ Review current reasoning for macro applicability * - `EXP30 `__ - Do not depend on the order of evaluation for side effects - - - Unlike for C, the evaluation order is fully defined in Rust: `expressions -> expression precedence `__\ Thus, this rule isn’t really needed. At least, not with the same UB-stopping urgency that it is needed for in C.\ *Extra notes: there is a restriction lint that touches on this topic, as a precedent:* ```mixed_read_write_in_expression`` `__ * - `EXP32 `__ - Do not access a volatile object through a nonvolatile reference - - - Volatile is specific to C in this case.Furthermore, a mismatch like this would be bound by the rules of the type system, and thus be caught unless the user were to be using transmutation. Rules about transmutation, however, are not a map of this rule but they are rather their own thing. * - `ARR39 `__ - Do not add or subtract a scaled integer to a pointer - - - Pointer arithmetic is done through APIs in Rust, `all of which `__ mention up-front that their ``count: usize`` parameter is in units of the underlying type ``T``. Even the name strongly indicates that it’s a **count**, and not a specific length.If the ARR39 kind of pattern proves to be a problem, a rule can be made about it. As far as I can tell, however, it is not. * - `FIO32 `__ - Do not perform operations on devices that are only appropriate for files - - - **Context**\ *In C, those APIs might block (the current thread) if the files being open correspond to devices (files under ``/dev/``). This in turn can lead to a Denial of Service, by effectively blocking the system.* The APIs present in ```std::fs`` `__ are quite a bit different from the ones present in C.Some functions in this module may block:- Attempting to take a filesystem lock,- Calling ``Read::read`` (might block waiting for data), and - ``Write::write`` (might block waiting for data to be written).However, a rule that restricts the use of blocking actions over a filesystem is quite different from FIO32. Thus, I don’t believe this maps to Rust. Related filesystem guidance may instead belong near #392 * - `FIO46 `__ - Do not access a closed file - - - This is guaranteed in Rust already by the fact that closing a file consumes the variable, invalidating any future accesses to it.\ *Unsafe Rust, as always, could get away with doing something like this regardless, but that would be UB and* **should be covered by a different guideline** *(something along the lines of “don’t extend lifetimes beyond their valid range”* * - `ENV34 `__ - Do not store pointers returned by certain functions - - - Live References cannot be invalidated in Rust.\ *Implementors of such libraries in Unsafe Rust must take care to not invalidate the references they create. This would be UB. It would always violate the memory model. But the rule to enforce this lies outside of the context of ENV34. It’s a more general rule that must be followed.* * - `CON37 `__ - Do not call signal() in a multithreaded program - - - Rust doesn’t provide support for signal handling in ``std``. Details as to why can be seen `here `__.Since this feature is not supported in Rust, the rule doesn’t apply.\ *That being said, there are crates which provide signal handling utilities. Some are mentioned in the linked thread above. Dear reader, use those crates at your own discretion.* * - `MSC30 `__ - Do not use the rand() function for generating pseudorandom numbers - - - `The APIs for generating pseudorandom numbers in core and std `__ are currently nightly-only.\ *I don’t know if it was RNG, but IIRC something like it from the stdlib was discouraged in Rust as well, due to it not being collision resistant. I’m pretty sure it was a hash function or something.* * - `STR31 `__ - Guarantee that storage for strings has sufficient space for character data and the null terminator - - - Strings are not null-terminated in Rust and their storage space is guaranteed * - `DCL40 `__ - Do not create incompatible declarations of the same function or object - - - *Rationale: doing this is impossible in Rust.* * - `PRE30 `__ - Do not create a universal character name through concatenation - - - *Rationale: it’s just very specific to C* * - `DCL38 `__ - Use the correct syntax when declaring a flexible array member - - - The rule is about “using the standardized syntax for this feature, instead of relying on Undefined Behavior and a compiler-specific, non-standardized syntax”.Such a suggestion makes no sense in Rust, since there is only one compiler and its syntax is the only one available. Correct syntax can compile; incorrect syntax cannot. * - `EXP35 `__ - Do not modify objects with temporary lifetime - - - *Rationale: the borrow checker eliminates this problem* * - `EXP43 `__ - Avoid Undefined Behavior when using restrict-qualified pointers - - - The borrow checker gives us correct-by-construction restrict qualifications in codegen. Basically, “restrict” is part of the type system, and type checking (in particular borrow checking) enforces that its rules are always abided by. * - `ARR32 `__ - Ensure size arguments for variable length arrays are in a valid range - - - *Rationale: VLAs are not a thing in Rust* * - `ARR38 `__ - Guarantee that library functions do not form invalid pointers - - - The rule basically asks the user that, whenever they call a function that receives a pointer to an array and a length, that said length doesn’t go outside the bounds of the array (which would form an invalid pointer)In Safe Rust, this is handled by bounds checks, and in the mapping of ARR30 we’re already handling that.In Unsafe Rust, doing this is to break the Safety Contract of the API we’re calling, which `is getting its own rule. `__ and is outside the mapping of this ARR38 (this rule) Recently moved out of the applicable bucket * - `STR32 `__ - Do not pass a non-null-terminated character sequence to a library function that expects a string - - - *Rationale: strings are not null-terminated in Rust* * - `FIO34 `__ - Distinguish between characters read from a file and EOF or WEOF - - - See the `Read `__ trait. EOF / WEOF cannot be acquired from them.As long as file reading operations are done through the Read trait, this should not be a concern. * - `FIO37 `__ - Do not assume that fgets() or fgetws() returns a nonempty string when successful - - - This rule comes from the need to properly handle errors found during the execution of ``fgets()`` and ``fgetws()``. Errors in those functions are reported in a way whose proper handling cannot be enforced by the compiler.Fallible APIs in Rust return values of the enum ``Result``, whose error case must be properly handled, in order for the program to compile. This feature completely eliminates the need for this kind of rule in Rust. * - `FIO39 `__ - Do not alternately input and output from a stream without an intervening flush or positioning call - - - This is UB in C, due to implementation details of the stream handling APIs. The implementation of those APIs in Rust is different, so the guideline doesn’t really map to it. \ *For more information, see* `this comment `__ *and* `this issue `__\ *.* * - `FIO44 `__ - Only use values for fsetpos() that are returned from fgetpos() - - - The closest APIs in Rust’s ``std`` to C’s ``fsetpos`` and ``fgetpos`` are the ones provided by the ```std::io::Seek`` `__ trait. Their main differences can be summarized by two things:- The foundational method of the trait, ```Seek::seek`` `__, seeks by the number of bytes given to it. It doesn’t require the “multibyte parser state” that’s sometimes encoded in the ``fpos_t`` parameter for ``fsetpos``, since the trait has no notion of wide-oriented streams.- There is no Undefined Behavior in ``Seek``\ ’s APIs.Thus, there is no reason to restrict the provenance of the offsets used there. * - `ERR33 `__ - Detect and handle standard library errors - - - Functions in std that may fail, wrap their result in the ``Result`` type, which forces the caller to handle the error case whenever it happens. Thus, this rule is already enforced by the compiler. * - `MSC37 `__ - Ensure that control never reaches the end of a non-void function - - - *Rationale: this is already enforced by the type system* * - `PRE32 `__ - Do not use preprocessor directives in invocations of function-like macros - - - This rule is needed in C due to how its preprocessor works. It’s very C-preprocessor-specific, and doesn’t map to Rust * - `DCL31 `__ - Declare identifiers before using them - - - 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. * - `DCL37 `__ - Do not declare or define a reserved identifier - - - **Context** *In 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.*\ 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. * - `EXP37 `__ - Call functions with the correct number and type of arguments - - - This is enforced by the type system * - `EXP44 `__ - Do not rely on side effects in operands to sizeof, \_Alignof or \_Generic - - - This is C-specific * - `EXP47 `__ - Do not call va_arg with an argument of the incorrect type - - - 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.* * - `STR34 `__ - Cast characters to unsigned char before converting to larger integer sizes - - - Characters in Rust are not integers.They are `unicode scalar values `__. * - `FIO30 `__ - Exclude user input from format strings - - - Format strings are evaluated at compile time in Rust * - `FIO41 `__ - Do not call getc(), putc(), getwc() or putwc() with a stream argument that has side effects - - - This rule arises from how those APIs are implemented (as C macros), and not from a more general aspect of the situation. * - `ENV30 `__ - Do not modify the object referenced by the return value of certain functions - - - 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.* * - `ENV32 `__ - All exit handlers must return normally - - - Panicking doesn’t have UB. Panics inside of panics will eventually abort the program. * - `ERR34 `__ - Detect errors when converting a string to a number - - - Functions in std that may fail, wrap their result in the ``Result`` type, which forces the caller to handle the error case whenever it happens. Thus, this rule is already enforced by the compiler. * - `DCL36 `__ - Do not declare an identifier with conflicting linkage classifications - - - This is a very specific issue to C * - `DCL41 `__ - Do not declare variables inside a switch statement before the first case label - - - The semantics of C’s ``switch`` statements are (fortunately) not present in Rust * - `EXP45 `__ - Do not perform assignments in selection statements - - - Rust is expression-oriented. Assignments return ``()`` in Rust. Therefore the use-case for this is not really present in Rust. * - `EXP46 `__ - Do not use a bitwise operator with a Boolean-like operand - - - The type system makes usage of these operators a reasonable thing in Rust. They are well-defined and well-behaved. * - `FIO38 `__ - Do not copy a FILE object - - - This is related to how the ``FILE`` object has implementation-defined behavior. This is completely C-specific, in this case. * - `FIO40 `__ - Reset strings on fgets() or fgetws() failure - - - Unlike in the original ``fgets()`` and ``fgetws()`` implementation, the bytes of the buffer ``buf`` in the io-reading-APIs of Rust’s ``std`` have very well-defined values in all scenarios: they follow the rules of the ``Read`` trait and its ```read`` `__ function. From those building blocks is that functions such as ```Read::read_to_string`` `__ are constructed.As the root cause of this problem isn’t present in Rust, this rule is not needed. * - `SIG30 `__ - Call only asynchronous-safe functions within signal handlers - - - Rust doesn’t provide support for signal handling in ``std``. Details as to why can be seen `here `__.Since this feature is not supported in Rust, the rule doesn’t apply.\ *That being said, there are crates which provide signal handling utilities. Some are mentioned in the linked thread above. Dear reader, use those crates at your own discretion.* * - `SIG31 `__ - Do not access shared objects in signal handlers - - - *Same as SIG30* * - `ERR30 `__ - Take care when reading errno - - - Errno doesn’t exist in Rust.But furthermore, functions that may fail wrap their result in the ``Result`` type, which forces the caller to handle the error case if and only if it happened. * - `ERR32 `__ - Do not rely on indeterminate values of errno - - - *Rationale: see ERR30-C* * - `CON30 `__ - Clean up thread-specific storage - - - Thread-specific storage in Rust refers to values behind a ```LocalKey`` `__.There is no important difference between how this kind of storage is cleaned up and how other resources local to the thread (like its stack variables) are cleaned up. Thus, it does not merit its own rule. * - `CON39 `__ - Do not join or detach a thread that was previously joined or detached - - - This does not apply to Rust because:- ```std::thread::JoinHandle::join`` `__ consumes the thread, and- ```JoinHandle`` `__ doesn’t implement ``Clone``, so it’s impossible to join it twice.Unsafe code would be needed to invalidly copy it. But then again, “Obey ownership semantics” can just be one rule. * - `INT35 `__ - Use correct integer precisions - - - All primitive integer types guarantee their precision in Rust * - `STR37 `__ - Arguments to character-handling functions must be representable as an unsigned char - - - Characters in Rust are not integers * - `STR38 `__ - Do not confuse narrow and wide character strings and functions - - - There’s only one character type in Rust * - `MEM33 `__ - Allocate and copy structures containing a flexible array member dynamically - - - Flexible array members are not a thing in Rust * - `FIO47 `__ - Use valid format strings - - - Format strings are evaluated, and therefore, validated, at compile time, in Rust * - `SIG34 `__ - Do not call signal() from within interruptible signal handlers - - - Rust doesn’t provide support for signal handling in ``std``. Details as to why can be seen `here `__.Since this feature is not supported in Rust, the rule doesn’t apply.\ *That being said, there are crates which provide signal handling utilities. Some are mentioned in the linked thread above. Dear reader, use those crates at your own discretion.* * - `SIG35 `__ - Do not return from a computational exception signal handler - - - *Rationale: see SIG34* * - `CON31 `__ - Do not destroy a mutex while it is locked - - - This is impossible to do in Rust due to ownership semantics: it’s only possible to destroy things one has ``&mut`` access to.The user could use ``unsafe`` to invalidly create such a reference, but doing so would violate ownership semantics (and be immediate Undefined Behavior). * - `MSC33 `__ - Do not pass invalid data to the asctime() function - - - There is no equivalent time-displaying function in either ``core`` nor ``std``.\ *As of the time of writing (2026-03-03), this kind of functionality can be accessed through external libraries such as ``chrono``, ``hifitime``, ``icu``, ``jiff`` and ``time``.* * - `MSC38 `__ - Do not treat a predefined identifier as an object if it might only be implemented as a macro - - - There is no such thing as a macro pointer in Rust * - `MSC39 `__ - Do not call va_arg() on a va_list that has an indeterminate value - - - Variadic functions do not exist in Rust * - `MSC40 `__ - Do not violate constraints - - - *Context of MSC40: this rule is about not writing code that doesn’t comply with the C standard.*\ The Rust compiler rejects all such programs. If a program is not valid Rust code, then it does not compile.