💾 Archived View for gmi.noulin.net › 2021-02-20-trying-rust.gmi captured on 2023-06-14 at 14:20:05. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
date: 2022-08-29 07:40:23
categories: programming
firstPublishDate: 2021-02-20 15:36:20
Rust is not easy to learn for beginner programmers. I suggest beginner programers start learning python or javascript then C and then rust. Learning C helps understanding the kind of issues that are detected by the rust compiler. There are tools for C for detecting the memory issues but they run in the tests (CI) but they don't detect all issues. Rust shows the issues earlier at compile time when the program is under development.
I think getting issues at compile time saves development time.
I checked which SEI CERT C rules apply for Rust.
The following rules apply:
In debug mode, it panics. A fix for this is to use the SEI CERT C compliant solution. I found some discussion around this:
To explicitly handle the possibility of overflow, you can use these families of methods provided by the standard library for primitive numeric types:
When INT35 is violated, it panics.
When out-of-bounds accesses are done on static arrays or vectors, it panics.
In rust, system() is: std::process::Command, it is vulnerable when the path to the command is incorrectly specified.
The following rules don't apply:
The result is NaN.
Rust supports multiple program styles in a good way: imperative, object oriented, functional programming.
Rust is not stable and still evolving, for example last year printing variables in format strings was added `println!("{var}");` but printing a struct member is not supported and under discussion:
allow arbitrary expressions in format string
// Code: struct D<'a> { s: &'a str }$ let s = D { s : "ad"};$ println!("{}", s.s);$ . println!("{s.s}"); // Doesn't compile error: invalid format string: expected `'}'`, found `'.'` --> src/main.rs:11:17 | 11 | println!("{s.s}"); | - ^ expected `}` in format string | | | because of this opening brace | = note: if you intended to print `{`, you can escape it using `{{` error: could not compile `minigrep` due to previous error
Most changes are additions so current code is likely to compile with future compiler versions. There is a tool (cargo fix) to update code to newer version of rust.
Declarations can be put in any order (except macros, macros have to be written before first use), for example a struct can be used before it is declared in the same file.
When memory errors are detected, the program panics. The panics have to be handle gracefully and all unhandled panics have to be found with static analysis or dynamic testing (tests and fuzzing). The libraries have to also handle the panics gracefully.
In general, it is easier to collaborate with other developers in projects compare to C. With C, a set of rules (quite large) has to be decided: memory management, naming and style formating (clang-format), file and directory organization, testing, secure conding rules. The tooling has be chosen: build system, test library, sanitizers, static analyzers, fuzzers. With Rust, only testing rules have to be decided. Memory management is done automatically, the compiler suggest snake case and there is rust-fmt, file and directory organization is suggested by the compiler and cargo. Build system, test library, fuzzers are provided, the need for sanitizers and static analyzers is lower than for C.
In C, I use macros as closures, it is quite inconvenient to use because it is prone to mistake and can be debugged only with prints. Closures in rust are much better.
I think the Drop trait is better than having `__attribute__((cleanup(func)))` on variable declarations.
Rust warns about unused return values and unused parameters, with GNU C the attributes `__attribute__ ((warn_unused_result))` and `__attribute__ ((unused))` have to be added to each function.
Functions can return multiple values, so it is uniform and easy to separate return values from errors (with Result<> or Option<>).
There are namespaces and names can be changed locally where the object is used (use crate as myname;).
The compiler messages are helpful and directly gives solutions to compilation issues (sometime the messages are misguiding).
crates.io has only one namespace so there will be name squatters. There are crates not implemented as I want, so I create local crates and declare them with path in cargo.toml dependencies:
[dependencies] mycrate = { path = "../mycrate"}
The documentation is good but incomplete:
The toolchain is 1GB per version. The rust system takes a lot of disk space.
Lots rust programs claim to be blazing fast, it seems.
It did a benchmark on a program parsing a 91MB log file with about 1 million lines:
Rust Debug 25sec C Debug 3.8sec Rust -O 1.48sec (13 million allocations) C -O3 2.2sec (31 million allocations) C -O3 with less allocations 0.5sec (1 million allocations)
Rust debug is slow and the rust optimized version is fast without optimizing the code. It is possible to get the same performance as C by reducing the allocations.
Rustc issues a warning when names don't have the default case:
Coredump are not well supported. By default panics don't generate a coredump and panic = "abort" doesn't generate a coredump either. In Cargo.toml
[profile.release] panic = "abort"
To generate a coredump, register a panic handler and trigger sigabrt like this:
use libc::kill; use libc::SIGABRT; unsafe { kill(0, SIGABRT);}
Code coverage is available in nightly. To setup nightly in a project, do this:
export RUSTFLAGS="-Zprofile" export CARGO_INCREMENTAL=0
Then build normally with `cargo build` and for gcov coverage run:
llvm-cov-11 gcov ./target/debug/deps/nightly-6cea039c96dffc6e.gcda vi main.rs.gcov
For llvm code coverage, run:
llvm-profdata merge -sparse default.profraw -o default.profdata llvm-cov show -Xdemangler=rustfilt target/debug/nightly -instr-profile=default.profdata -show-line-counts-or-regions -show-instantiations
Llvm in debian bullseye doesn't support profraw format generated by rustc, so I compiled the latest llvm from source (it takes more than 10GB disk space).
Command Line Applications in Rust
A peer-reviewed collection of articles/talks/repos which teach concise, idiomatic Rust.
Rust has evolved a lot last few years, most of the code snippets I find either don't compile or are wrong.
The Rust toolchain has requirements on Linux and Glibc versions, this can force users to update systems or compile the Rust toolchain to the latest version compatible with the system.
Some packages might only work with edition 2021 which is not supported by older systems, forcing a system update. Also some packages might be abandoned and may not work with available rust toolchain forcing a package upgrade and a new security review.
I wonder if the rust toolchain glibc support is aligned with Red Hat support. Rust 1.64 depends on glibc 2.17 and it is the glibc in Red Hat 7 which will go out of support in 2024. So I suppose soon the oldest supported glibc will be the one in Red Hat 8.
A minimal rust install is about 500MB (without the documentation).
PATH has to be set like this:
export PATH=/home/$USER/.cargo/bin:$PATH
And these files are needed in home:
.cargo/bin/cargo .cargo/bin/rustfilt .cargo/bin/rustup .cargo/bin/rustc .cargo/bin/rust-gdb .cargo/bin/rust-gdbgui .rustup/tmp .rustup/update-hashes .rustup/update-hashes/stable-x86_64-unknown-linux-gnu .rustup/settings.toml .rustup/downloads .rustup/toolchains .rustup/toolchains/stable-x86_64-unknown-linux-gnu .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/zsh .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/zsh/site-functions .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/zsh/site-functions/_cargo .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-run.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-report.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-metadata.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-help.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-locate-project.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-tree.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-doc.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-check.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-version.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-uninstall.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-build.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/rustc.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-install.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-package.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-vendor.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/rustdoc.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-verify-project.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-init.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-login.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-fix.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-bench.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-rustdoc.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-pkgid.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-rustc.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-owner.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-update.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-publish.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-test.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-fetch.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-add.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-new.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-clean.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-yank.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-search.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/share/man/man1/cargo-generate-lockfile.1 .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/librustc_driver-d680884a73809b24.so .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/libtest-50b9616eedb811b7.so .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/libstd-8f1929c73c3f8167.so .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/libLLVM-14-rust-1.63.0-stable.so .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/components .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/rust-installer-version .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/multirust-channel-manifest.toml .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/manifest-rustfmt-preview-x86_64-unknown-linux-gnu .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/manifest-cargo-x86_64-unknown-linux-gnu .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/etc .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/etc/gdb_load_rust_pretty_printers.py .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/etc/gdb_providers.py .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/etc/lldb_providers.py .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/etc/__pycache__ .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/etc/__pycache__/gdb_providers.cpython-39.pyc .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/etc/__pycache__/rust_types.cpython-39.pyc .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/etc/__pycache__/gdb_lookup.cpython-39.pyc .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/etc/rust_types.py .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/etc/lldb_commands .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/etc/lldb_lookup.py .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/etc/gdb_lookup.py .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libproc_macro-f46062bad18d692a.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-19c77e4dc3dcb87e.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc-stable_rt.tsan.a .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-63f8356c87a0d0e8.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcfg_if-fb44a42088c9369a.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libhashbrown-65c63cf3af0af657.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libprofiler_builtins-02287944b380ef08.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libgimli-682a81c4b2133b72.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libminiz_oxide-4a53f0a2785abc6a.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libmemchr-9d7c322d48daa475.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-e359d865975ccf21.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libgetopts-754da76e30d40e26.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_core-a506e577d917828c.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd_detect-7b5ec4c918d9f957.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libadler-868e2d515c28d027.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc-stable_rt.msan.a .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-8f1929c73c3f8167.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libtest-50b9616eedb811b7.so .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-8f1929c73c3f8167.so .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-fc1fb63210fdafad.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_alloc-394ad2d73aede76a.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libaddr2line-08ae1606a951cabe.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-c21be34a5cae8449.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_abort-2ef255b89354cca0.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libobject-b886fd10c5a7c7c0.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_demangle-a73b3512c88de071.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libtest-50b9616eedb811b7.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc-stable_rt.lsan.a .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunicode_width-abff7c50c58df25c.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_std-89f1a8c8e39f4a91.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc-stable_rt.asan.a .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-61a7402e61a5b0e0.rlib .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin/rust-lld .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin/gcc-ld .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin/gcc-ld/ld .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/multirust-config.toml .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/manifest-clippy-preview-x86_64-unknown-linux-gnu .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/manifest-rust-docs-x86_64-unknown-linux-gnu .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/manifest-rustc-x86_64-unknown-linux-gnu .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/manifest-rust-std-x86_64-unknown-linux-gnu .rustup/toolchains/stable-x86_64-unknown-linux-gnu/etc .rustup/toolchains/stable-x86_64-unknown-linux-gnu/etc/bash_completion.d .rustup/toolchains/stable-x86_64-unknown-linux-gnu/etc/bash_completion.d/cargo .rustup/toolchains/stable-x86_64-unknown-linux-gnu/libexec .rustup/toolchains/stable-x86_64-unknown-linux-gnu/libexec/cargo-credential-1password .rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin .rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/cargo .rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/rustc .rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/rust-gdb .rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/rust-gdbgui
2021-02-20 15:36:20 Versions: rustc 1.50 and rustc 1.52(nightly)
I followed the instructions on the
and ran rustup like this:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
It downloaded a dozen of archives (megabytes) and installed rust in home under `~/.cargo/bin`.
I used a Dell XPS 13 9350 and I compiled rust version 1.52, latest in the git repo with these commands:
./x.py build ./x.py install
`x.py build` took 1 hour and `/x.py install` took 1.5 hour to finish.
I decided to try code coverage, it is an unstable feature:
The compile error I get is:
error[E0463]: can't find crate for `profiler_builtins` | = note: the compiler may have been built without the profiler runtime error: aborting due to previous error For more information about this error, try `rustc --explain E0463`.
To fix this error, read the instructions in the
nightly unstable documentation
.
I compiled my code with `rustc -Cdebuginfo=2` to emit the full debug information.
I have gdb 10.0 installed on my machine and when I run `rust-gdb` it starts gdb 10.0.
To debug, I use the command (my program is called `h`):
rust-gdb -tui h
In Rust by example, I read:
Since Rust 1.45, the `as` keyword performs a *saturating cast* when casting from float to int.
Reading the release notes, I notice there are many features that are unstable, deprecated or changing.
It means my source code needs to be tested for each new release of rust and then time needs to be spent to fix the issues.
If one decides to not fix the issues, the specific rust version for the source code has to be keep available and multiple version of rust might be needed.
As of today, the cost of using rust is far too high compare to the benifits it gives. The system is too unstable and the tools are not mature.
hashtags: #rust