Naar de Nederlandstalige versie

TETRA RustIEC

RustIEC is a VLAIO TETRA project (grant HBC.2021.0066) with the goal of teaching Flanders' companies proficiency in the Rust programming language. The project has a specific focus on secure IoT systems, secure edge computing, and secure cloud computing.

The RustIEC project is run by the Smartnets lab of the Vrije Universiteit Brussel, and the DistriNet lab of the KU Leuven. Meet the team!

Project goal

Problems with memory, such as memory leaks, buffer overflows, and memory dumps, are well-known issues with software that could be exploited by attackers. The amount of cyber attacks increases year after year. Not only large companies, but also smaller companies are more often the target of attacks, and could face severe consequences.

With most programming languages like C and C++, these issues with memory management are noticed late, usually during runtime. They might not appear during compilation or debugging. When these problems only become apparent in production, they can lead to great damage. The search to their root cause can also be time consuming.

The Rust programming language provides an adequate answer. The compiler will not allow the developer to write unsafe code. Inherently by its design, the amount of mistakes in written Rust code is lower. As a consequence, mistakes are more often avoided by their conception, which makes maintenance of software easier. Rust allows, at the same time, to write performant code. This programming language is well-documented, and many libraries are available for embedded systems as well as for regular platforms.

The most important goal of this project is to acquiant companies with the advantages that Rust could provide them, such that they can make the trade-off of using Rust for future projects for themselves.

We envision these results:

  • Two complete case-studies, for which the code will be shared openly.
  • Benchmarks made for comparing the performance of Rust and more mainsteram programming languages such as C, C++ and Python, for some frequent and representative algorithms in the IoT and security domains.
  • Research to interoperability of Rust with other programming languages and the portability to other platforms.
  • Research of the efficiency of conversion tools surch as C2Rust and CRUST.
  • Organisation of one introductory and one more advanced hands-on workshop about learning Rust, and publishing the workshop material.
  • Integrating the gained knowledge in at least three courses for both research institutions.

Project participants

Ausy Digazu LSEC OTN Systems Sky Hero Barco Gemone Lumency Quicksand Verhaert Digital COMmeto MatchID Shayp

Vrije Universiteit Brussel Vlaio KU Leuven

Naar de Nederlandstalige versie

The team

The RustIEC project is run by the INDI/ETRO Smartnets lab of the Vrije Universiteit Brussel, and the DistriNet lab of the KU Leuven.

Project supervisors

Kris Steenhaut An Braeken Jorn Lapon Stijn Volckaert

Kris Steenhaut (Vrije Universiteit Brussel) has been guiding the ETRO/IRIS/Smartnets group since 2005. Her research activities focus on the design, implementation and experimental evaluation of Wireless Sensor Networks and their integration in the Internet and the Word Wide Web. Topics of particular attention are interoperability, security and privacy as well as the interworking with fog and cloud. Kris Steenhaut has guided several ITEA and SBO projects and several EU projects on Internet of Things, smart grid, smart lighting and environmental monitoring. She plays an active role in development cooperation with Cuba and Vietnam.

An Braeken (Vrije Universiteit Brussel) became professor in 2007 at the Erasmushogeschool Brussel (currently since 2013, Vrije Universiteit Brussel) in the Industrial Sciences Department. Her current interests include security and privacy protocols for IoT, cloud and fog, blockchain and 5G security. She has cooperated and coordinated more than 12 national and international projects.

Jorn Lapon (KU Leuven) is a Research Manager in Secure Software of the DistriNet Research Group of KU Leuven located in Gent. He has been active in both industry and academics and obtained his PhD on Anonymous Credential Systems back in 2012. Topics of particular interest are IoT security, with a focus on secure development and security testing. His close collaboration with industry has proven to be valuable for both the companies and academic research.

Stijn Volckaert (KU Leuven) is een assistant professor bij imec-DistriNet, KU Leuven - Technology Campus Ghent. Zijn onderzoek focust op exploit mitigation, software diversity, multi-variant execution en geautomatiseerd overzetten van legacy code naar veilige programmeertalen.

Project collaborators

Ruben De Smet Diana Deac Roald Van Glabbeek Andreas Declerck

Ruben De Smet (Vrije Universiteit Brussel) has been actively developing in Rust since 2016, and has contributed to multiple Rust "crates", among which in the asynchronous ecosystem, the cryptographic ecosystem, and the "qmetaobject" library. He co-maintains a set of Signal libraries and develops a Signal client in Rust. For his PhD research, he works on a peer-to-peer application. Ruben joined the Belgium Rust User Group in 2017, and has been organiser of this group since 2020.

Diana Deac (Vrije Universiteit Brussel) recently started developing in Rust after working with Contiki-NG which is written in the C programming language. She designed an adaptive scheduler for Time Slotted Channel Hopping (TSCH) for Contiki-NG. She is currently working on implementing the RPL protocol in Rust. The focus of her PhD research is enhancing protocols for wireless sensor networks with security in mind.

Roald Van Glabbeek (Vrije Universiteit Brussel) contributes through his expertise on embedded platforms and design and implementation of MAC, RDC and routing protocols.

Andreas Declerck (Vrije Universiteit Brussel) has been working with Rust since 2017 and occasionally contributes to the Rust-written X11 window manager LeftWM. For his master's thesis, he is exploring the potential of using Rust to implement multicast in the RPL network protocol and CSMA on embedded devices. He is active in the art world, assisting artists with the technical aspects of their art installations. In his spare time, he is an active volunteer at CoderDojo Belgium, where he teaches children aged 7 to 18 how to program.

Project contributors

Thibaut Vandervelden Robrecht Blancquaert Alicia Andries

Thibaut Vandervelden (Vrije Universiteit Brussel) is a Rust crate contributor since 2019. His main focus is writing software for embedded devices that use low power wireless communication protocols, such as IEEE802.15.4. He has contributed to the smoltcp crate, where he implemented the 6LoWPAN protocol and is currently working on a RPL protocol implementation. The performance of the Rust programming language on embedded devices is the focus of his PhD research.

Robrecht Blancquaert (Vrije Universiteit Brussel) focusses on fast, safe implementations of elliptic curves for low-power embedded devices, with automatic specialisation for different CPU architectures.

Alicia Andries (KU Leuven) is a PhD researcher at the imec-DistriNet research group of KU Leuven under supervision of Stijn Volckaert. She werks on semi-automatic migration of code in unsafe programming languages to safer alternatives, such as Rust. For example, she works on translating drivers to Rust, researching the current limitations of automatic migration tools, and she researches Rust for Linux.

Naar de Nederlandstalige versie

Workshops

Part of the RustIEC project goal is the organisation of at least one introductory and two advanced hands-on workshops about learning Rust.

RustIEC 101

RustIEC 101 is our introductory Rust course, based on the A-modules of the "101-rs" course by Tweede Golf. The materials are available at https://101.rustiec.be/, and the source code is available at https://gitlab.com/etrovub/smartnets/rustiec-101/.

Part 1

This course will be taught in the form of two workshops on:

  • March 14, 2023 on the VUB campus;
  • March 27, 2023 on the VUB campus;
  • March 28, 2023 on the VUB campus;

with a total expected participant count of 35.

Part 2

The second part of the RustIEC 101 course teaches more advanced features of the Rust language.

  • September 13, 2023 on the VUB campus;
  • October 19, 2023 on the Barco campus;

RustIEC 201: Embedded programming

The "RustIEC 201: Embedded programming" workshop aims to provide you with an insight into the world of embedded Rust. The contents of the workshop are hosted on our website https://201.rustiec.be/.

This course was thought on March 25, 2023.

RustIEC 202: C2Rust

The "Advanced: C2Rust" workshop is designed for members looking to deepen their understanding of Rust through practical applications. This workshop extends the foundational knowledge from RustIEC 101, offering participants hands-on experience with the C2Rust tool, which helps in the migration of C codebases to Rust.

The course material can be found on https://github.com/AliciaAndries/rustiec_workshop_steps.

This course was thought on December 12, 2023, right after the User Committee meeting.

Naar de Nederlandstalige versie

Contact

For questions that are directly related to the study area of one of the collaborators or contributors, feel free to directly contact the relevant team members.

General questions or joining the project

An Braeken Kris Steenhaut

Would you have interest in joining the project with your company, you can contact An Braeken and Kris Steenhaut.

Technical questions and suggestions

For questions pertaining to the content of the project, you can directly contact the collaborators and contributors.

Web, cloud and async

Ruben De Smet

For questions regarding cloud or web technology, or for asynchronous programming, you may contact Ruben De Smet.

Embedded programming

Thibaut Vandervelden Diana Deac

For questions regarding embedded programming, you can contact Thibaut Vandervelden and Diana Deac

Automatic translation and Linux kernel drivers

Stijn Volckaert Alicia Andries

For questions pertaining to automatic translation or Linux kernel development, you can contact Stijn Volckaert en Alicia Andries.

Naar de Nederlandstalige versie

Kick-off meeting November 24 2022

Ruben De Smet: RustIEC kick-off

Kick-off Introduction slides

Download slides "kick-off introduction"

Ruben De Smet

Stijn Volckaert: Safe Systems Programming in Rust

Kick-off Introduction slides

Download slides "Safe Systems Programming in Rust"

Stijn Volckaert

Ruben De Smet & Thibaut Vandervelden: the Rust ecosystem

The Rust ecosystem

Download slides "Rust Ecosystem"

Ruben De Smet Thibaut Vandervelden

Naar de Nederlandstalige versie

User committee meeting March 27 2023

Ruben De Smet: committee meeting overview

Committee slides

Download committee slides

Ruben De Smet

Alicia Andries: C to Rust and making unsafe code safe

"C to Rust" slides

Download "C to Rust" slides

Alicia Andries

Thibaut Vandervelden: smoltcp

"smoltcp" slides

Download "smoltcp" slides

Thibaut Vandervelden

Naar de Nederlandstalige versie

User committee meeting December 12 2023

Jorn Lapon: Welcome with coffee

Ruben De Smet: Vulnerabilities in Rust programs

Vulnerabilities slides

Download Vulnerabilities slides

Ruben De Smet

Alicia Andries: Incremental Migration of C-code to Rust

Incremental Migration slides

Download Incremental Migration slides

Alicia Andries

Naar de Nederlandstalige versie

User Committee meeting June 5 2024

Alicia Andries: overview user committee meeting

User committee meeting slides

Alicia Andries

Alicia Andries: Evolution of Rust for Linux and Lessons Learned

rust4linux slides

Download rust4linux slides

Alicia Andries

Thibaut Vandervelden: Rust Operating Systems and Frameworks for Embedded Devices

Embedded OS slides

Download Embedded OS slides

Thibaut Vandervelden

Michael Allwright: WebAssembly and Rust

Wasm slides

Download WASM slides

Jeroen Gardeyn: How Rust boosts confidence and productivity

my experiences as an algorithm researcher

Jeroen's slides

Download Jeroen's slides

Naar de Nederlandstalige versie

Embedded demo at Wireless Community Meeting - October 9, 2024

Based on our embedded workshop, we produced a small demo for the Wireless Community (WiCo) meeting on secure IoT on October 9, 2024. The demo extends the workshop with wireless control over a IEEE 802.15.4 TCP/IP network.

Group picture at WiCo meeting

Naar de Nederlandstalige versie

RustIEC newsletter (June 2023)

Welcome to the first newsletter for the RustIEC project. First, we would like to thank the participants of the first Rust Hands-On workshop, for which we received very good and insightful feedback. In September, the second session of this Rust Hands-On workshop will take place. Based on the results of the questionnaire, we decided that a specialized workshop at a later date will be focussed on embedded programming using Rust.

In this newsletter, we provide you with updates on the progress made by the RustIEC teams.

RPL implementation by Vrije Universiteit Brussel

The VUB team is currently finishing the implementation and evaluation of the Routing Protocol for Low-power and lossy networks called RPL. The implementation is written in Rust and added to the smoltcp TCP/IP library, a lightweight TCP/IP protocol stack. As an embedded operating system, we used the Embassy framework. Both are written in the Rust programming language.

Network Stack Figure 1: Protocol and application stack of Embassy with smoltcp and Contiki-NG.

We used a simulator to evaluate the correctness of the RPL implementation, as a first step. Afterwards, real devices were employed, specifically the nRF52840 development kit. The network under evaluation consisted of devices running the smoltcp RPL implementation with the Embassy framework and devices running the well-established Contiki-NG RPL implementation, written in C, which is part of the Contiki-NG operating system. Figure 1 illustrates the protocol stacks for both smoltcp and Contiki-NG.

The testbed comprised of three nodes, as depicted in Figure 2. One of the nodes served as the root, another acted as a router, and the third operated as a leaf node. Multiple setups were evaluated, combining the Contiki-NG implementation with the smoltcp implementation. This approach aimed to test the compatibility of the Rust RPL implementation against an existing RPL implementation written in C.

Testbed Figure 2: Testbed of nRF52840-DK's running smoltcp and Contiki-NG.

The Rust-based RPL with smoltcp is robust, but requires 145.5 KB of flash memory, whereas RPL with Contiki-NG in C requires 47.7 KB. The firmware without RPL requires 117.3 KB for smoltcp and 38.1 KB for Contiki-NG. However, it is important to note that this Rust implementation is a first iteration, leaving ample room for optimization and further refinement.

The VUB team worked, in collaboration with a master student, on the implementation of the Generic Header Compression (GHC) protocol. This protocol serves as an extension of the 6LoWPAN adaptation layer for IPv6. The implementation was also added to the Rust smoltcp library. After the evaluation, they concluded that GHC demonstrates its utility primarily in specific scenarios. IPv6 addresses are part of the dictionary used in the compression algorithm, resulting in only being efficient when the payload to be compressed contains IPv6 addresses.

The VUB team is now focussing on researching how to implement the Data Link layer in Rust for embedded devices, more specifically, Medium Access Protocols (MAC) such as Carrier Sense Multiple Access (CSMA) and Time Slotted Channel Hopping (TSCH). When these protocols are implemented in Rust, a full stack in a safe programming language is available for devices using the IEEE 802.15.4 standard.

Progress on C to Rust transpilers by KU Leuven

The KU Leuven team finished their case study of the Rust for Linux kernel. They successfully made a prototype of a parallel port driver in Rust and have learned some important lessons on the interoperability of C and Rust. For example, you should consider the kind of security features you added to the C code, and whether they ought to be added to the Rust code. Domen Puncen Kugler has uncovered some interesting examples of this. Also, if you translate a part of your C code base to Rust you will have to use a lot of unsafe calls to be able to interact with the C code from the new Rust code. It is important to wrap such unsafe functions in safe ones that can do memory safety checks before simply letting Rust code use a pointer that was provided by C code. While the KU Leuven team may have set aside their study of the Rust for Linux kernel for the time being, they are keeping an eye on significant developments. For example, the further Rust integrations into the mainline Linux kernel with the release of kernel version 6.2. The Rust integrations for this version are mostly low-level support code. It will still be quite a long time before any substantial Rust driver will be supported by the mainline kernel.

The KU Leuven team is currently evaluating the state-of-the-art on automatically translating C into safe Rust. The three publications of particular interest are Mehmet Emre et al.’s OOPSLA 2021 paper "Translating C to Safer Rust", Bryan Tan Yao Hong’s MSc thesis entitled "From C Towards Idiomatic & Safer Rust Through Constraints-Guided Refactoring", and Hanliang Zhang et al.'s VAC 2023 paper "Ownership guided C to Rust translation" They discussed the two first papers at the previous user group meeting. All three publications have very distinct techniques for transforming C to safe Rust, but they all use C2Rust by Immunant as a stepping stone as it can generate non-idiomatic unsafe Rust from C code. C2Rust does not aid in making a program safer or proving a program was safe in the first place. All it was built to do is make a syntactical translation. However, this syntactical translation does already remove a first hurdle for anyone trying to generate idiomatic Rust code from C code.

Because all three publications do use C2Rust, the start of their workflow is very similar. They all follow the workflow shown in Figure 3. They first use C2Rust to generate unsafe Rust, then they add their own contribution in the Refactoring block. While the papers share a similar workflow for transpiling, they have different ways of evaluating the effectiveness of their tools which makes comparing their different architectures arduous.

C2Rust Overview Figure 3: overview of the workings of C2Rust.

Mehmet Emre et al.'s architecture is the most straightforward. They simply transform every pointer of a specific type they come across to a Rust reference. If the transformations do not compile, they automatically look at the compiler errors and the proposed fixes and apply those. This is a very aggressive technique. The architecture proposed by Bryan Tan Yao Hong on the contrary, is very precise. They prepare transformations for some very specific cases like transforming array pointers into Rust types. Lastly, Hanliang Zhang et al.'s proposed architecture is based on finding pointers that fit into Rust's ownership model. The basics of the idea are very much like those of Immunant's Ownership Analysis.

After extensive experimentation, the KU Leuven team found that all the designs show promise, but the implementations of these architectures have several fundamental design flaws and shortcomings. The KU Leuven team is currently summarizing the strengths and weaknesses of the designs and will then formulate guidelines and recommendations that should serve as a starting point for a new and improved design.

Naar de Nederlandstalige versie

RustIEC newsletter (September 2024)

Welcome to the second newsletter for the RustIEC project. In this newsletter, we provide you with updates on the progress made by the RustIEC teams.

RustIEC demo at IMEC's Wireless Community event

Wednesday October 9, 2024, at IMEC - Leuven (12h - 19h) we will showcase RustIEC's results on secure embedded programming in Rust. We will demonstrate a wireless version of the pong game which we presented during our embedded workshop. The main topic of IMEC's Wireless Community even of October 9th is Secure over-the-air firmware updates of IoT devices, but the scope is broader.

Subscriptions via Wireless Community Workshop.

Rust Embedded Operating Systems and Frameworks

The VUB team submitted Overview of Rust Embedded Operating Systems and Frameworks to the MDPI Sensors journal, which was accepted for publication. The paper focuses on several Rust-based OSes and frameworks, including Tock, Hubris, RTIC and Embassy, It shows the potential of Rust offering a high-level language, without sacrificing low-level control or memory safety, making embedded systems more reliable and secure. Each OS brings something unique, from real-time capabilities to hardware abstraction, tailored to meet the challenges of modern embedded devices.

The first part of the paper covers the basics of the embedded Rust landscape, explaining how Rust can be used to write firmware for microcontrollers. It also explains the benefits of using asynchronous Rust for embedded systems, providing a more efficient and structured way to interact with peripherals. The most important parts of an embedded OS are also discussed, such as how tasks are scheduled, how processes communicate, how to interact with hardware, and finally how these OSes and frameworks handle networking.

The final part of the paper provides an evaluation of the interrupt and scheduling latency for each of the different OSes and frameworks. The results show that Rust-based OSes and frameworks can achieve low latencies, making them suitable for real-time applications. The memory requirements of each OS are also compared.

Crabstick: a chess engine in Rust

Thibaut and Ruben of the VUB team built a chess engine in Rust called Crabstick. This Friday-night hobby project is a work in progress, but it already plays a decent game of chess. You can play against Crabstick on Lichess.

The Lichess-integration is an interesting case study of how to integrate Rust with a web service: Crabstick is deployed as a Kubernetes service, and it can scale up to handle multiple games at once. Every game is handled by a separate worker deployment, which communicates with the main manager via a REST API. The worker deployment is implemented as an Actix actor, and exposes the games to Prometheus.

Crabstick on Prometheus Figure 1: Crabstick statistics in Prometheus, showing the number of games played over time.

You can already have a look around the Crabstick source code. At a later time, we plan to make a comprehensive report on user space Rust tools and techniques.

Onwards Into the Breach

Over the duration of the RustIEC project Rust has been gaining more traction than ever. It is no longer only big companies like Google, Android, and Mozilla that are sharing their positive experiences with using Rust, governments are also getting involved. The White House now advises that new code ought not to be written in memory unsafe languages like C and C++, but instead should be developed in memory safe languages like Rust.

Translating C to Rust

Both academia and industry are making great strides in reducing the challenges of adopting Rust in systems level software. One domain that we have spent quite some time on during RustIEC, which is especially gaining interest, is automatic translation from C to Rust. The Translating All C to Rust(TRACTOR) program introduced by the Defense Advanced Research projects Agency (DARPA) is one indication of the growing interest. Hanliang Zhang et al., Jaemin Hong, Jaemin Hong et al., and Mehmet Emre et al. propose solutions based on program analysis while Momoko Shiraishi, Hasan Ferit Eniser, and Yoshiki Takashima propose solutions based on machine learning. Both angles have their pros and cons. While program analysis techniques aim to translate very specific code patterns, the code before and after transformation is very unlikely to have changed semantically. On the other hand, machine learning approaches are more holistic, and can cover whole code bases. However, they do come with a cost, and that is semantic equivalence. There is a significant probability that the code after the transformation will no longer compile, or the new program may exhibit completely different behavior. The future, therefore, will likely be a marriage between the two angles along with some extensive verification of the resulting program.

While TRACTOR is aiming for fully automated translations, either with program analysis or AI, or a combination of both, we have been looking into what tools we can provide until a reliable and usable fully automated translator is available. While we do believe that a fully automated translator is the future, there is no telling how long it will take before such a program can be trusted to operate on real infrastructure. In the meantime we propose a semi-automated tool that provides suggested translations in order of criticality to a developer who then decides whether those changes would be semantics preserving. While this means there is more manual labor necessary, this proposal also comes with more semantics preserving guarantees.

C and Rust Interoperability

While it remains impossible to translate whole codebases completely from C to memory safe Rust, using C and Rust together is a must. Thankfully Rust was designed with C interoperability in mind, so it is a mostly solved problem. The how of the matter is answered, however, whether we should do it in the first place wasn't asked during RustIEC. This question has popped up in recent literature. The concern explored by Michalis Papaevripides et al. and Samuel Mergendahl et al. is that unexploitable memory errors in hardened C code, that are passed to Rust code, could be used to exploit the memory safe Rust code. Since this attack was formulated Inyoung Bang et al., Peiming Liu et al., Hussain Almohri, Paul Kirth, and Elijah Rivera have proposed memory separation techniques such that the possibly corrupted C data can never corrupt Rust data. These protections still have some drawbacks, confused deputy attacks are not covered and, most importantly, the current tools are prototypes, so not industry ready.

Translation and Interoperability in the Real World

We used the Rust for Linux kernel as a case study to see how the introduction of Rust into a C code base is done in the real world. On the front of translating C to Rust, the maintainers of the Rust for Linux kernel chose to redesign when translating, instead of creating a one to one translation. More impactful than that were the large API and design changes throughout the duration of the RustIEC project, which we covered in the user group meeting on the 5th of June. However, the Rust for Linux kernel seems to be stabilizing and new Rust features are slowly but steadily being added to the mainline Linux kernel. One point of contention that seems to remain is how the Rust and C code should interface as there are few semantic definitions available for the C API. Therefore, on the front of C and Rust interoperability the main issue seems to be communication between the rather disjoint C and Rust maintainers and, at least for the time being, not security issues.

Questions or Suggestions?

If you have any questions or suggestions, feel free to reach out to us:

(L1.1) Rust: pros and cons

Rust is a compiled systems programming language, like C and C++. Each language has its own strengths and weaknesses. The following are the advantages (non-exhaustive) of Rust compared to C and C++.

  1. Memory safety: Rust has a strong ownership system and borrow checker that enforces strict rules at compile time, preventing common memory-related errors such as null pointer dereferencing, dangling pointers, and buffer overflows. This can lead to more reliable and secure code.

  2. Zero-cost abstraction: Rust provides high-level abstractions without sacrificing performance. The ownership system allows for fine-grained control over memory allocation and deallocation, and the language includes features like pattern matching, algebraic data types, and type inference that enable expressive code without runtime overhead.

  3. Community and ecosystem: Rust has a growing and active community that values safety, performance, and modern software engineering practices. The Rust ecosystem includes a package manager (Cargo) that simplifies dependency management and makes it easy to integrate third-party libraries.

  4. C compatibility: Rust can be easily integrated with C and C++ code. It provides foreign function interface (FFI) capabilities that allow Rust code to call C functions and vice versa. This makes it feasible to gradually introduce Rust into existing C or C++ projects.

  5. Built-in Testing: Rust has a built-in testing framework that makes it easy to write and run tests. Testing is considered an integral part of Rust development, and the language encourages developers to write tests for their code, promoting a culture of code quality and reliability.

However, Rust also has its own disadvantages (non-exhaustive):

  1. Steep learning curve: Rust has a steeper learning curve compared to C and C++. The ownership system and borrow checker introduce new concepts that may be unfamiliar to developers, especially those who are new to systems programming.

  2. Maturity of the Ecosystem: While Rust's ecosystem is growing rapidly, it may not be as mature as C++'s, which has been around for much longer. C and C++ have well-established libraries and frameworks for various domains, and Rust may still be catching up in certain areas.

  3. Limited Legacy Code Support: C and C++ have a large codebase in existing projects, and Rust's integration with legacy C or C++ code might not be as seamless as using these languages together. There may be additional effort required to interface with existing codebases.

  4. Limited support for some architectures: While Rust supports many architectures, it might have limited support for very niche or specialized platforms compared to C and C++, which have been used in a wide range of environments for a longer period.

It's important to note that while these considerations highlight potential disadvantages of Rust compared to C, Rust brings significant advantages in terms of memory safety, concurrency, and modern language features.

More information about the pros and cons of Rust can be found in Stijn Volckaert's presentation.

(L1.2) Rust: tools and interoperability

The Rust ecosystem is rather young, but grows quickly and contains quite many high-quality tools and libraries ("crates"). We presented an overview of the Rust ecosystem in November 2022, which is hereby summarized.

  1. Cargo, Crates.io, Docs.rs, Lib.rs, Rust Analyzer: Central to the Rust development environment are tools designed to streamline development of Rust code. Cargo is the de facto package manager, automating tasks such as building, testing, and project management. Crates.io functions as the primary repository for Rust packages, facilitating seamless sharing and discovery of libraries. Docs.rs automates documentation generation for crates, while Lib.rs serves as a community-driven catalog for alternative crate exploration. Rust Analyzer offers a sophisticated language server for enhanced IDE features, and ties into several different IDEs.

  2. FFI: c2rust, cbindgen: In the domain of interoperability between Rust and C, c2rust and cbindgen are notable projects. c2rust is a tool expressly designed for the migration from C to Rust, facilitating the conversion of C code to Rust. cbindgen automatically generates C bindings for Rust code, offering communication between Rust and C components.

  3. Rayon, Crossbeam: Parallelism is a cornerstone of Rust's design philosophy, and two libraries, Rayon and Crossbeam, contribute significantly to this paradigm. Rayon simplifies data parallelism, providing an accessible means to craft parallel code. Crossbeam, meanwhile, offers essential low-level building blocks for concurrent programming, addressing synchronization and parallelism requirements.

  4. env_logger, log: In the domain of logging, Rust offers tools such as env_logger and log. The env_logger crate, configurable through environment variables, and log, a flexible logging facade, collectively empower developers to adopt logging practices tailored to specific project requirements. Many other logging backends exist for log, and log is the de-facto standard libraries.

  5. thiserror, anyhow: Rust's capabilities in error handling are extended through the thiserror and anyhow crates. The thiserror crate provides a straightforward mechanism for defining custom error types, while anyhow offers a versatile framework for handling any error types, simplifying error management within Rust applications.

  6. Serde: Serialization and deserialization are fundamental tasks in software development, and serde stands as Rust's premier library for these operations. Supporting a diverse array of data formats, Serde ensures seamless data exchange within Rust applications through subcrates such as serde_json.

  7. AreWeAsyncYet.rs, AreWeGameYet.rs, AreWeWebYet.org, AreWeLearningYet.com, ...: Community-driven initiatives, encapsulated in websites like AreWeAsyncYet.rs, AreWeGameYet.rs, AreWeWebYet.org, AreWeLearningYet.com, serve as comprehensive resources tracking Rust's progress across diverse domains. These platforms offer valuable insights into Rust's evolution in areas such as asynchronous programming, game development, web development, learning resources, and community well-being.

  8. Async-Await: Rust introduces language-level features in the form of async-await syntax to facilitate the development of asynchronous code. This syntax enhances code readability and maintains a commitment to the principles of safety and concurrency. A whole ecosystem is being very actively developed around this asynchronous programming paradigm; see below.

  9. Tokio, Mio, Async-std: Asynchronous programming is pivotal in modern software development, and Rust provides robust solutions through Tokio, Mio, and async-std. Mio provides a zero-cost asynchronous I/O library, and serves as the I/O framework for most asynchronous executors. It abstracts away from operating system specific asynchronous APIs, but does not provide async-await integration. Tokio functions as a runtime for asynchronous applications, and provides a whole framework to work with asynchronous I/O with async-await syntax. Async-std offers utilities for asynchronous programming, and serves as an alternative to the now more popular Tokio. Collectively, these crates empower developers to build efficient and scalable systems

  10. Hyper, Actix-Web: For web development in Rust, libraries such as Hyper and frameworks like Actix-Web play essential roles. Hyper offers a fast and low-level HTTP implementation both at client and server side. Actix-Web is a powerful and ergonomic web framework. Both projects are built on top of the asynchronous Tokio framework.

  11. Wasm-Pack, Yew: In the context of WebAssembly (WASM) and web development, Rust is one of the major go-to languages. Rust offers tools such as wasm-pack. This utility streamlines the building and integration of WebAssembly projects. Yew, a Rust framework tailored for client-side web applications, leverages the power of Rust and WebAssembly to deliver a seamless and performant web development experience.

In summary, the Rust ecosystem boasts a collection of sophisticated tools and libraries that collectively enhance the development experience, addressing a wide spectrum of programming needs. These tools and libraries were presented during our kick-off meeting, during the "ecosystem" presentation, which was presented by Ruben and Thibaut.

(L1.3) Benchmarking Rust against C and C++

Rust and C are compiled languages that use the LLVM code generation tool, implying comparable runtime speed and memory usage. However, due to differences in programming styles, it's challenging to make assertions about their performance. Various Rust language-specific overheads contribute to this complexity:

  • In Rust, slices and str are represented by a pointer and the element count. When passed to a function, both the pointer and element count are transmitted. In contrast, C might only require a pointer, assuming the size is known or inferred from context.
  • Bound checks are inserted by the compiler when indexing an array. In most cases, these bound checks can be optimized out by the compiler. This can prohibit the compiler to do autovectorization of some operations.
  • In some cases, the Rust borrow checker is too strict, simply because that edge case is not implemented by the compiler. For these cases, adding copies or use reference counting is the solution. Lukely, there are very few edge cases where this is necassery.
  • Using generics in Rust can potentially increase the executable size, as the compiler generates optimized functions for each type used with a generic function, leading to multiple instances in the binary.

Rust also has places where it ends up being more efficient and faster than C:

  • Struct fields are reordered to minimize padding, enhancing memory utilization.
  • Rust is good in inlining functions, even those from dependencies.
  • Rust makes optimized versions of generic implementations, like C++ templates. This is not possible with C, where macros need to be used or less efficient implementations with void*.
  • Rust enforces thread-safety, even for dependencies.

Examing benchmarks, such as c-vs-rust benchmarks, shows that Rust outperforms C in 7 out of 10 benchmarks. In the c-vs-rust from the Benchmark games, Rust is fastest in 5 out of 10 benchmarks.

We also ran our own benchmarks, benchmarking 3 sorting algorithms written in Rust and in C. These algorithms were implemented in a straightforward manner, without any specific focus on code optimization. Utilizing Criterion, a benchmarking tool in Rust, we performed multiple runs of sorting arrays with random data across various sizes. The benchmarks ran on an HP EliteBook 745 G6 running Fedora 39. The following graphs depict the performance of each sorting algorithm's Rust implementation, its C counterpart, and the built-in standard library sorting function.

Bubble sort

For Bubble sort, the compiler is unable to optimize all bound checks for indexing arrays. Note that we consider this as an optimization that is missed by the compiler. The Rust compiler still has places where optimizations are lacking.

Bubble Sort Graph

Quick sort

Performance of Quick sort is around equal for the Rust and C implementations.

Quick Sort Graph

Heap sort

For the Heap sort implementation, the Rust version is faster than the C implementation.

Heap Sort Graph

Conclusion

Comparing the performance of Rust and C can be challenging since both are compiled languages sharing the same compiler backend (LLVM). While a comparison using the GCC compiler for C is possible, it introduces a comparison between GCC and LLVM rather than a comparison between the languages themselves.

Note that Rust has a rich standard library. Sorting anything that is sortable can be achieved by just calling the .sort() method. This feature contributes to Rust's rich and user-friendly programming environment.

(L2.1) Automatic conversion and interfaces

While Rust may be rapidly gaining popularity, many code bases are still primarily written in C. It is therefore important to make sure Rust is as painless as possible to introduce into an existing C code base. The foreign function interface options provided by Rust make communicating between C and Rust easier. If you want to translate C code to Rust, you can use C2Rust to speed this process along.

Automatic Conversions

Automatic conversion from C to Rust is possible, if not yet perfected. The current state-of-the art tool is C2Rust. More Information about the automatic conversion from C to Rust can be found in the presentation on Migrating From Unsafe Languages to Rust.

Interfaces

To call Rust from C or C from Rust, all you need are the correct bindings of the desired functions. Such bindings are simply the function headers expressed in the language you want to call them from. When a Rust binding of a C function is desired, one must create a Rust binding from a C header. For example, the C function header below:

void function(int i);

The following binding is needed to call the function from Rust:

#![allow(unused)]
fn main() {
extern "C" {
    pub fn function(i: ::std::os::raw::c_int);
}
}

Rust provides types that are identical to C types in the standard library to make interoperability between C and Rust easier. To create a Rust binding that represents a C function, it is necessary to add extern "C" to let the Rust compiler know you will be linking to external code. Bindings can not only be made for functions but also for structs. In the case of structs, it is important to add #[repr(C)] as it makes sure the alignment, size, and order of fields are the same as in C.

When creating a C binding from Rust code, you need to add some information to the Rust function. The compiler needs to be told not to mangle the function name, so the attribute #[no_mangle] must be added. The keyword extern "C" must be added to the function header to make sure that this function can be correctly used by a C program.

#![allow(unused)]
fn main() {
#[no_mangle]
pub extern "C" fn function(i: i32);
}

The following binding is needed to call the function from C:

void function(int i);

Creating bindings for your interfaces so C and Rust can talk to each other is banal work and can be done in an automated fashion. Bindgen was introduced to create Rust bindings from your C code. All you have to do to create such a binding is provide a C header file that contains all that should be callable from Rust code. Creating C bindings from Rust can also be automated with the tool cbindgen. Cbindgen needs some more help than bindgen, some configuration information must be provided. This can either be achieved by adding a cbindgen.toml file, or by adding a build.rs file (which is a Rust build script) with a cbingen builder. The documentation offers examples of configuration options.

(L2.3) Overview of research problems

(L2.2) Best practices regarding Rust and security