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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions