Skip to content

A note that a macro in a #![forbid(unsafe_code)] library can emit unsafe code #506

@peter-lyons-kehl

Description

@peter-lyons-kehl

Thank you for the Nomicon.

https://doc.rust-lang.org/nomicon/safe-unsafe-meaning.html reads " you can even toss #![forbid(unsafe_code)] into your code base to statically guarantee that you're only writing Safe". While that is technically correct, it may lead people to unintentionally introduce unsafe. Steps:

  1. "Let me check a such-and-such library"
  • "Let me check a such-and-such 3rd party library." or
  • "Let me review our such-and-such internal library.", or even
  • "Let me check my own (private/internal) library that I wrote X years ago and mostly forgot about."
  1. "That library's lib.rs has #![forbid(unsafe_code)]."
  2. "Great. So that library can't introduce any unsafe to my library/crate." (This is the core of the mistake.)
  3. "Let me use that library's macro(s)." (Or, even worse: "Let me copy-and-paste that library's tutorial/doctest/unit test...".)
    But, macros from such libraries can still generate unsafe code.

Of course, the consumer can have #![forbid(unsafe_code)] in her crate - but only if her crate doesn't use any unsafe on its own.

If the library uses macro_rules, any unsafe can be grepped for. If it's a procedural macro, unsafe could come from a concatenated (or otherwise generated) string, so not searchable. (Obviously, that would be either stupid or malicious, but malicious crates did exist.)

So, suggest a note like:

However, if you are using any macros, those may generate unsafe even if their library has #![forbid(unsafe_code)]. You can:

  • check the macro implementation (but that won't cover future versions). Or,
  • have #![forbid(unsafe_code)] in your crate. Or,
  • if your crate uses unsafe (which is likely, since you are reading this):
    • use such macro(s) in a playground library with #![forbid(unsafe_code)], or
    • move your code that uses such macro(s) in a separate module and have #![forbid(unsafe_code)] in that module, or
    • move your code that uses such macro(s) in a separate block and forbid unsafe for that block #[forbid(unsafe_code)] {...}.

If this sounds acceptable, I'm open to providing a pull request.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions