Издаване на Rust 1.96. Оценка на пригодността на Rust за създаване на фърмуер за микроконтролери

Обявен е релийз на програмния език Rust 1.96, който е основан от проекта Mozilla, но в момента се развива под покровителството на независимата неправителствена организация Rust Foundation. Язикът е фокусиран върху безопасната работа с паметта и предоставя средства за постигане на висока степен на паралелизъм при изпълнение на задачи, като същевременно не използва сборщик на боклук и runtime (runtime се свежда до основна инициализация и поддръжка на стандартната библиотека).

Методите за работа с паметта в Rust са насочени към предотвратяване на грешки при манипулиране на указатели и защита от проблеми, произтичащи от нискоуровнева работа с паметта, като достъп до освобождавано пространство, разименоване на нулеви указатели, излизане извън границите на буфера и др. За разпространение на библиотеки, осигуряване на построяване и управление на зависимости, проектът развива пакетния мениджър Cargo. Поддържа се хранилище за библиотеки на crates.io.

Безопасната работа с паметта в Rust се осигурява по време на компилацията чрез проверка на референтите, проследяване на притежанието на обекти, вземане под внимание на времето на живот на обектите (област на видимост) и оценка на коректността на достъпа до паметта по време на изпълнението на кода. Rust също така предоставя средства за защита срещу препълване на цели числа, изисква задължителна инициализация на стойностите на променливите преди тяхната употреба, по-добре обработва грешките в стандартната библиотека, прилага концепцията за неизменяемост (immutable) на референтите и променливите по подразбиране и предлага силна статична типизация за минимизиране на логическите грешки.

Основни нововъведения:

  • Добавен е модул range с реализирани нови типове, които заместват остарелите типове Range, RangeInclusive, RangeToInclusive и RangeFrom, и позволяват съхраняването на диапазони в структури с Copy. Типът Range определя диапазони, ограничени с минималното и максимално допустимо значение (но не включително), типът RangeFrom определя числа, започващи от указаната стойност, а типът RangeInclusive — стойности в указан диапазон, включително и двете му граници. В бъдещи издания ще бъдат добавени типове RangeFull и RangeTo, а старата реализация ще бъде преместена в core::range::legacy::*, а синтаксисът „N..M“ ще бъде преведен на новия вариант на типовете.

    Новите типове се различават по това, че вместо типажа Iterator реализират типажа IntoIterator, т.е. вместо вграден итератор определят как да преобразуват типа в итератор. Такъв подход позволява използването на операцията копиране с новите типове (типаж Copy, показващ, че стойностите на типа могат да бъдат дублирани чрез просто копиране), която преди това беше недостъпна поради несъвместимост с типовете с вградени итератори.
    Например, новите типове позволяват запазването на границите на среза в структура, която се копира напълно без отделно запазване на началната и крайната стойност:

    use core::range::Range;

    #[derive(Clone, Copy)]
    pub struct Span(Range);

    impl Span {
    pub fn of(self, s: &str) -> &str {
    &s[self.0]
    }
    }

  • Добавени са макросите «assert_matches!» и «debug_assert_matches!», които проверяват съответствието на стойността с указан шаблон и аварийно спират изпълнението при несъответствие. Новите макроси се различават от изразите «assert!(matches!(..))» и «debug_assert!(matches!(..))» с това, че извеждат отладъчна информация за стойностите, предизвикали грешка. За да се избегнат конфликти с външни макроси, предоставяни с аналогични имена, новите макроси изискват явен импорт на библиотеката «core::assert_matches».

    use core::assert_matches;

    fn get_random_number() -> u32 {
    4
    }

    fn main() {
    assert_matches!(get_random_number(), 1..=6);
    }

  • При сборка за целевата платформа WebAssembly е прекратена предаването на опцията «—allow-undefined» на свързвача, която разрешаваше свързване при наличие на неопределени символи, които се преобразуваха в импорт от модула «env». При сборка за WebAssembly всички свързани символи с компоновката сега трябва задължително да бъдат определени по подразбиране. За възстановяване на старото поведение може да се използва променлива на средата «RUSTFLAGS=-Clink-arg=—allow-undefined» или изразът ‘#[link(wasm_import_module = «env»)]’ в кода.
  • Нов набор от API е преведен в категорията стабилни, включително стабилизирани методи и реализации на типажи:
    • assert_matches!
    • debug_assert_matches!
    • From за AssertUnwindSafe
    • From за LazyCell
    • From за LazyLock
    • core::range::RangeToInclusive
    • core::range::RangeToInclusiveIter
    • core::range::RangeFrom
    • core::range::RangeFromIter
    • core::range::Range
    • core::range::RangeIter
  • В пакетния мениджър Cargo е отстранена уязвимостта CVE-2026-5223, която може да се използва за презапис на изходния код на друг crate-пакет в локалния кеш на пакети от същия репозиторий чрез манипулации с символични връзки вътре в crate-а на пакетите. Уязвимостта се проявява само при работа с външни репозитории на пакети и не засяга потребителите на репозитория crates.io, тъй като в crates.io е забранено качването на пакети със символични връзки.

Допълнително може да се отбележи публикацията (PDF) на резултатите от анализа относно пригодността на езика Rust за разработка на фърмуер за микроконтролери и вградени системи с ограничени ресурси.
Изследването е проведено от компанията STMicroelectronics с участието на няколко европейски университета. Две изолирани екипа разработчици получили задача да реализират един и същи фърмуер за микроконтролерите STM32U585AI с ядро Arm Cortex-M33. Първият екип създава фърмуер на C, а вторият на Rust.

Тестването на завършената работа не показа значителни предимства при използването на езика C вместо Rust за разработване на фърмуер за микроконтролери, когато се сравнява консумацията на памет и производителност. Още повече, внедряването на системния runtime, написан на Rust, от открития проект Ariel OS позволи да се постигне консумация на памет в проекта на Rust, която е по-ниска, отколкото в реализацията на езика C, използваща традиционния стек за разработка на фърмуер на базата на библиотека newlib.

Размерът на резултатния фърмуер е 84100 байта в проекта на Rust и 76744 байта в проекта на C (с 10% по-малко), но консумацията на оперативна памет в фърмуера на Rust се оказа значително по-ниска — 24640 байта срещу 42608 байта. Що се отнася до производителността, при тестването на начален прототип, разработен за 6 седмици, реализацията на Rust беше два пъти по-бърза от реализацията на C, но и двете реализации значително изоставяха от изчислената максимална производителност. След 4 седмици, отделени за оптимизация, и двете реализации достигнаха приблизително еднакъв резултат, близък до изчисления максимум.



Източник: opennet.ru
Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster