Trying rust
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:
- INT30-C. Ensure that unsigned integer operations do not wrap
- INT32-C. Ensure that operations on signed integers do not result in overflow
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:
Wrap in all modes with the wrapping_* methods, such as wrapping_add
Return the None value if there is overflow with the checked_* methods
Return the value and a boolean indicating whether there was overflow with the overflowing_* methods
Saturate at the value’s minimum or maximum values with saturating_* methods
INT33-C. Ensure that division and remainder operations do not result in divide-by-zero errors
INT35-C. Do not shift an expression by a negative number of bits or by greater than or equal to the number of bits that exist in the operand
When INT35 is violated, it panics.
- ARR30-C. Do not form or use out-of-bounds pointers or array subscripts
- ARR32-C. Ensure size arguments for variable length arrays are in a valid range
When out-of-bounds accesses are done on static arrays or vectors, it panics.
- FIO32-C. Do not perform operations on devices that are only appropriate for files
- FIO39-C. Do not alternately input and output from a stream without an intervening flush or positioning call
- FIO45-C. Avoid TOCTOU race conditions while accessing files
- ENV33-C. Do not call system()
In rust, system() is: std::process::Command, it is vulnerable when the path to the command is incorrectly specified.
- SIG* -- not checked
- MSC32-C. Properly seed pseudorandom number generators
- MSC41-C. Never hard code sensitive information
- POS35-C. Avoid race conditions while checking for the existence of a symbolic link (TOCTOU)
- POS36-C. Observe correct revocation order while relinquishing privileges
- POS37-C. Ensure that privilege relinquishment is successful
- POS38-C. Beware of race conditions when using fork and file descriptors
- POS39-C. Use the correct byte ordering when transferring data between systems
The following rules don't apply:
- PRE* - there is no string based preprocessor
- DCL*
- DCL30-C. Declare objects with appropriate storage durations
- DCL31-C. Declare identifiers before using them
- DCL36-C. Do not declare an identifier with conflicting linkage classifications
- DCL37-C. Do not declare or define a reserved identifier
- DCL38-C. Use the correct syntax when declaring a flexible array member
- DCL39-C. Avoid information leakage when passing a structure across a trust boundary
- DCL40-C. Do not create incompatible declarations of the same function or object
- DCL41-C. Do not declare variables inside a switch statement before the first case label
- EXP*
- EXP30-C. Do not depend on the order of evaluation for side effects
- EXP32-C. Do not access a volatile object through a nonvolatile reference
- EXP33-C. Do not read uninitialized memory
- EXP34-C. Do not dereference null pointers
- EXP35-C. Do not modify objects with temporary lifetime
- EXP36-C. Do not cast pointers into more strictly aligned pointer types
- EXP37-C. Call functions with the correct number and type of arguments
- EXP39-C. Do not access a variable through a pointer of an incompatible type
- EXP40-C. Do not modify constant objects
- EXP42-C. Do not compare padding data
- EXP43-C. Avoid undefined behavior when using restrict-qualified pointers
- EXP44-C. Do not rely on side effects in operands to sizeof, _Alignof, or _Generic
- EXP45-C. Do not perform assignments in selection statements
- EXP46-C. Do not use a bitwise operator with a Boolean-like operand
- EXP47-C. Do not call va_arg with an argument of the incorrect type
- INT31-C. Ensure that integer conversions do not result in lost or misinterpreted data
- INT35-C. Use correct integer precisions
- INT36-C. Converting a pointer to integer or integer to pointer
- FLP30-C. Do not use floating-point variables as loop counters
- FLP32-C. Prevent or detect domain and range errors in math functions
The result is NaN.
- FLP34-C. Ensure that floating-point conversions are within range of the new type
- FLP36-C. Preserve precision when converting integral values to floating-point type
- FLP37-C. Do not use object representations to compare floating-point values
- ARR36-C. Do not subtract or compare two pointers that do not refer to the same array
- ARR37-C. Do not add or subtract an integer to a pointer to a non-array object
- ARR38-C. Guarantee that library functions do not form invalid pointers
- ARR39-C. Do not add or subtract a scaled integer to a pointer
- STR30-C. Do not attempt to modify string literals
- STR31-C. Guarantee that storage for strings has sufficient space for character data and the null terminator
- STR32-C. Do not pass a non-null-terminated character sequence to a library function that expects a string
- STR34-C. Cast characters to unsigned char before converting to larger integer sizes
- STR37-C. Arguments to character-handling functions must be representable as an unsigned char
- STR38-C. Do not confuse narrow and wide character strings and functions
- MEM-*
- MEM30-C. Do not access freed memory
- MEM31-C. Free dynamically allocated memory when no longer needed
- MEM33-C. Allocate and copy structures containing a flexible array member dynamically
- MEM34-C. Only free memory allocated dynamically
- MEM35-C. Allocate sufficient memory for an object
- MEM36-C. Do not modify the alignment of objects by calling realloc()
- FIO30-C. Exclude user input from format strings
- FIO34-C. Distinguish between characters read from a file and EOF or WEOF
- FIO37-C. Do not assume that fgets() or fgetws() returns a nonempty string when successful
- FIO38-C. Do not copy a FILE object
- FIO40-C. Reset strings on fgets() or fgetws() failure
- FIO41-C. Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects
- FIO42-C. Close files when they are no longer needed
- FIO44-C. Only use values for fsetpos() that are returned from fgetpos()
- FIO46-C. Do not access a closed file
- FIO47-C. Use valid format strings
- ENV30-C. Do not modify the object referenced by the return value of certain functions
- ENV31-C. Do not rely on an environment pointer following an operation that may invalidate it
- ENV32-C. All exit handlers must return normally
- ENV34-C. Do not store pointers returned by certain functions
- ERR*
- ERR30-C. Take care when reading errno
- ERR32-C. Do not rely on indeterminate values of errno
- ERR33-C. Detect and handle standard library errors
- ERR34-C. Detect errors when converting a string to a number
- CON* -- not checked
- MSC30-C. Do not use the rand() function for generating pseudorandom numbers
- MSC33-C. Do not pass invalid data to the asctime() function
- MSC37-C. Ensure that control never reaches the end of a non-void function
- MSC38-C. Do not treat a predefined identifier as an object if it might only be implemented as a macro
- MSC39-C. Do not call va_arg() on a va_list that has an indeterminate value
- MSC40-C. Do not violate constraints
- POS30-C. Use the readlink() function properly
- POS34-C. Do not call putenv() with a pointer to an automatic variable as the argument
- POS44-C. Do not use signals to terminate threads
- POS47-C. Do not use threads that can be canceled asynchronously
- POS48-C. Do not unlock or destroy another POSIX thread's mutex
- POS49-C. When data must be accessed by multiple threads, provide a mutex and guarantee no adjacent data is also accessed
- POS50-C. Declare objects shared between POSIX threads with appropriate storage durations
- POS51-C. Avoid deadlock with POSIX threads by locking in predefined order
- POS52-C. Do not perform operations that can block while holding a POSIX lock
- POS53-C. Do not use more than one mutex for concurrent waiting operations on a condition variable
- POS54-C. Detect and handle POSIX library errors
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:
- snake_case for (
an_example): crate names, function names - upper camel case for (
AnExample): struct, enum, members UpperCamel - const and static variables are in capital letters (
AN_EXAMPLE)
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:
- create a new project
- install the nightly toolchain
rustup toolchain install nightly - run
rustup override set nightly - setup environment:
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
Command Line Applications in Rust
A peer-reviewed collection of articles/talks/repos which teach concise, idiomatic Rust.
Rust feature compare to C
- variables are immutable by default
- let can redeclare variables with identical names
- variables can't be assigned in if,while,for statements. if (a = f(3))
- all {} blocks are mandatory if (b) return true; is not allowed if b {true}
- return can be omitted, the last statement without ; is the return value
- enum are more like structs
- only bool can be without compare in conditionals let b = true; if b {println!("yes");} let b = 1; if b {println!("yes");} // compile error if b = 1 {println!("yes");} // compile error
- return errors are separated from return values
- reference &var (pointer) and dereference *var are similar.
- there are no ++ or -- operators
- function definitions can be written in any order
- macros have to be written before the first use
- functions have fixed number of parameters
- the use statements can be written anywhere in the code
- modules can be renamed when they are included: use std::process as p; it is easier to avoid namespace collisions
__FUNC__is missing
Good ideas in rust ecosystem
- documentation as comments
- documentation server and generator in cargo
- code styling in cargo and rustc
- test runner in cargo
- variable and reference to variable are identical when calling functions or accessing struct members
- registry index is a git repo
- when running a program for first time,
cargo rundownloads and installs the missing crates
FFI
- wrapper functions in rust code are needed
- types need to be converted. There is an easier solution for extern types under development.
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:
- unstable compiler options are not available in the release version of rust (1.50)
- when I compile with the options
-Zprofile=yor-Zinstrument-coverage=y, it fails to compile
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
- when I put a breakpoint on main, it stops in
library/std/src/rt.rsand the function islang_start, it doesn't work as expected - when I put a breakpoint on a statement in main and run, it stops on the correct line
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