💾 Archived View for gmi.noulin.net › 2021-02-20-trying-rust.gmi captured on 2023-01-29 at 03:02:45. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2022-03-01)

🚧 View Differences

-=-=-=-=-=-=-

Trying rust

Feed

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.

SEI CERT C rules

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:

RFC discussion

PR

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 Rust Reference

The Rustonomicon

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.

Case

Rustc issues a warning when names don't have the default case:

Coredump

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

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).

Documentation

Get started

lean

The Rust Programming Language

The Rust Reference

Command Line Applications in Rust

Rust By Example

The Rustonomicon

The Rust Unstable Book

Rust Cookbook

The Rust Standard Library

The Cargo Book

Rust Design Patterns

A peer-reviewed collection of articles/talks/repos which teach concise, idiomatic Rust.

algorithms

Articles about Rust

Rust from the ground up book

Rust feature compare to C

Good ideas in rust ecosystem

FFI

Stability

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.

Minimal rust install

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

Post version 1

2021-02-20 15:36:20 Versions: rustc 1.50 and rustc 1.52(nightly)

Installing rust

I followed the instructions on the

install page of rust-land

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`.

Compiling rust from source

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.

Code coverage

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

.

Debugging

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

Stability

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.

Conclusion

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

Feed