Handling untrustworthy data in non-trivial ways is a major source of security bugs, and it‘s therefore against Chromium’s security policies to do it in the Browser or Gpu process unless you are working in a memory-safe language.
Rust provides a cross-platform memory-safe language so that all platforms can handle untrustworthy data directly from a privileged process, without the performance overheads and complexity of a utility process.
The Rust toolchain is enabled for and supports all platforms and development environments that are supported by the Chromium project. The first milestone to include full production-ready support was M119.
Rust can be used anywhere in the Chromium repository (not just //third_party
) subject to current interop capabilities, however it is currently subject to a internal approval and FYI process. Googlers can view go/chrome-rust for details. New usages of Rust are documented at [email protected]
.
For questions or help, reach out to [email protected]
or #rust
on the Chromium Slack.
If you use VSCode, we have additional advice below.
Third-party libraries are pulled from crates.io, but Chromium does not use Cargo as a build system.
All third-party crates need to go through third-party review. See //docs/adding_to_third_party.md for instructions on how to have a library reviewed.
The //third_party/rust/chromium_crates_io/Cargo.toml
file defines the set of crates depended on from first-party code. Any transitive dependencies will be found from those listed there. The file is a standard Cargo.toml
file, though the crate itself is never built, it is only used to collect dependencies through the [dependencies]
section.
To use a third-party crate “bar” version 3 from first party code:
src/
dir of Chromium.//third_party/rust/chromium_crates_io/Cargo.toml
:vpython3 ./tools/crates/run_gnrt.py add foo
to add the latest version of foo
.vpython3 ./tools/crates/run_gnrt.py add [email protected]
to add a specific version of foo
.cargo run --release --manifest-path tools/crates/gnrt/Cargo.toml --target-dir out/gnrt add foo
./tools/crates/run_gnrt.py vendor
to download the new crate.cargo run --release --manifest-path tools/crates/gnrt/Cargo.toml --target-dir out/gnrt vendor
//third_party/rust/chromium_crates_io/patches
for the crates. If a patch can not apply, the crate's download will be cancelled and an error will be printed. See //third_party/rust/chromium_crates_io/patches/README.md
for more details."test"
group in //third_party/rust/chromium_crates_io/gnrt_config.toml
:[crate.foo] group = "test"
BUILD.gn
file for the new crate:vpython3 ./tools/crates/run_gnrt.py gen
cargo run --release --manifest-path tools/crates/gnrt/Cargo.toml --target-dir out/gnrt gen
git add -f third_party/rust/chromium_crates_io/vendor
. (The -f
is important, as files may be skipped otherwise from a .gitignore
inside the crate.)git add third_party/rust
//third_party/rust/OWNERS
.To enable a feature “spaceships” in the crate, change the entry in //third_party/rust/chromium_crates_io/Cargo.toml
to include the feature:
[dependencies] bar = { version = "3", features = [ "spaceships" ] }
If a shipping library needs security review (has any unsafe
), and the review finds it‘s not satisfying the rule of 2, then move it to the "sandbox"
group in //third_party/rust/chromium_crates_io/gnrt_config.toml
to make it clear it can’t be used in a privileged process:
[crate.foo] group = "sandbox"
If a transitive dependency moves from "safe"
to "sandbox"
and causes a dependency chain across the groups, it will break the gnrt vendor
step. You will need to fix the new crate so that it's deemed safe in unsafe review, or move the other dependent crates out of "safe"
as well by setting their group in gnrt_config.toml
.
Third-party crates will get updated semi-automatically through the process described in ../tools/crates/create_update_cl.md
. If you nevertheless need to manually update a crate to its latest minor version, then follow the steps below:
src/
dir of Chromium.//third_party/rust/chromium_crates_io/Cargo.toml
.vpython3 ./tools/crates/run_gnrt.py update <crate name>
cargo run --release --manifest-path tools/crates/gnrt/Cargo.toml --target-dir out/gnrt update <crate name>
./tools/crates/run_gnrt.py vendor
vendor
, like: ./tools/crates/run_gnrt.py vendor <crate-name>
cargo run --release --manifest-path tools/crates/gnrt/Cargo.toml --target-dir out/gnrt vendor
git add -f third_party/rust/chromium_crates_io/vendor
-f
is important, as files may be skipped otherwise from a .gitignore
inside the crate.BUILD.gn
filesvpython3 ./tools/crates/run_gnrt.py gen
cargo run --release --manifest-path tools/crates/gnrt/Cargo.toml --target-dir out/gnrt gen
git add -f third_party/rust
The directory structure for a crate “foo” version 3.4.2 is:
//third_party/ rust/ foo/ (for the "foo" crate) v3/ (version 3.4.2 maps to the v3 epoch) BUILD.gn (generated by gnrt gen) README.chromium (generated by gnrt vendor) chromium_crates_io/ vendor/ foo-3.4.2 (crate sources downloaded from crates.io) patches/ foo/ (patches for the "foo" crate) 0001-Some-changes.diff 0002-Other-changes.diff Cargo.toml Cargo.lock gnrt_config.toml
Most Rust libraries will need a more C++-friendly API written on top of them in order to generate C++ bindings to them. The wrapper library can be placed in //third_party/rust/<cratename>/<epoch>/wrapper
or at another single place that all C++ goes through to access the library. The CXX is used to generate bindings between C++ and Rust.
See //third_party/rust/serde_json_lenient/v0_1/wrapper/
and //components/qr_code_generator
for examples.
Rust libraries should use the rust_static_library
GN template (not the built-in rust_library
) to integrate properly into the mixed-language Chromium build and get the correct compiler options applied to them.
See rust-ffi.md
for information on C++/Rust FFI.
Unstable features are unsupported by default in Chromium. Any use of an unstable language or library feature should be agreed upon by the Rust toolchain team before enabling it.
Since Chromium imports the Rust toolchain at its HEAD and builds it in a nightly-like configuration, it is technically possible to depend on unstable features. However, unstable features often change in a backwards incompatible way without a warning. If such incompatible changes are introduced, importing a new version of toolchain now requires the owner to fix forward, instead of being an automated process. This makes toolchain upgrades prohibitively difficult.
When an exception is required, consider:
A list of exceptions is maintained in ../tools/rust/unstable_rust_feature_usage.md
.
Use the log crate's macros in place of base LOG
macros from C++. They do the same things. The debug!
macro maps to DLOG(INFO)
, the info!
macro maps to LOG(INFO)
, and warn!
and error!
map to LOG(WARNING)
and LOG(ERROR)
respectively. The additional trace!
macro maps to DLOG(INFO)
(but there is WIP to map it to DVLOG(INFO)
).
Note that the standard library also includes a helpful dbg!
macro which writes everything about a variable to stderr
.
Logging may not yet work in component builds: crbug.com/374023535.
TODO: crbug.com/377915495.
Prefer to use BString
and BStr
to work with strings in first-party code instead of std::String
and str
. These types do not require the strings to be valid UTF-8, and avoid error handling or panic crashes when working with strings from C++ and/or from the web. Because the web is not UTF-8 encoded, many strings in Chromium are also not.
In cross-language bindings, &[u8]
can be used to represent a string until native support for BStr
is available in our interop tooling. A u8
slice can be converted to BStr
or treated as a string with ByteSlice
.
rust-analyzer
extension for VSCode, rather than earlier forms of Rust support.gn
with the --export-rust-project
flag, such as: gn gen out/Release --export-rust-project
.ln -s out/Release/rust-project.json rust-project.json
rust-project.json
and use this to give you rich browsing, autocompletion, type annotations etc. for all the Rust within the Chromium codebase..vscode/settings.json
in the Chromium checkout:{ // The rest of the settings... "rust-analyzer.cargo.extraEnv": { "PATH": "../../third_party/rust-toolchain/bin:$PATH", } }This assumes you are working with an output directory like
out/Debug
which has two levels; adjust the number of ..
in the path according to your own setup.If you are building a throwaway or experimental tool, you might like to use pure cargo
tooling rather than gn
and ninja
. Even then, you may choose to restrict yourself to the toolchain and crates that are already approved for use in Chromium.
Here's how.
export PATH_TO_CHROMIUM_SRC=~/chromium/src mkdir my-rust-tool cd my-rust-tool mkdir .cargo cat <<END > .cargo/config.toml [source.crates-io] replace-with = "vendored-sources" [source.vendored-sources] directory = "$PATH_TO_CHROMIUM_SRC/third_party/rust/chromium_crates_io/vendor" END $PATH_TO_CHROMIUM_SRC/third_party/rust-toolchain/bin/cargo init --offline $PATH_TO_CHROMIUM_SRC/third_party/rust-toolchain/bin/cargo run --offline
Most cargo
tooling works well with this setup; one exception is cargo add
, but you can still add dependencies manually to your Cargo.toml
:
[dependencies] log = "0.4"