Автор Гілка: TRACTOR — переписування всього коду з Сі/Сі++ на Rust  (Прочитано 3511 раз)

Відсутній Володимир Лісівка

  • Адміністратор ЩОДО
  • Видавець
  • *****
  • дописів: 3800
  • Карма: +9/-0
  • Програміст
Втомившись від постійного пошуку вразливостей у коді написаному на Сі/Сі++, американська агенція DARPA розпочинає проєкт TrACtoR — Translate All Code To Rust (Переклад Всього Коду на Раст), з метою підвищення його безпечності. Це можна вважати початком кінця епохи Сі.

Оголошення: https://www.darpa.mil/program/translating-all-c-to-rust
[Fedora Linux]

Відсутній Володимир Лісівка

  • Адміністратор ЩОДО
  • Видавець
  • *****
  • дописів: 3800
  • Карма: +9/-0
  • Програміст
Оголошення:

Цитата
TRACTOR BACKGROUND AND OBJECTIVES

Buffer overflow vulnerabilities and other related “memory safety” software flaws allow an attacker to
inject messages that hijack control of a computer. These vulnerabilities are only possible because
programs written in C and C++ don’t force their developers to check conditions, such as array bounds or
pointer arithmetic, for correctness. Google and Microsoft have estimated that 70% of their security
vulnerabilities stem from these and other related memory safety issues. While there are a variety of
approaches to mitigate these risks, newer languages, like Rust, can completely eliminate them while
preserving efficiency. Unfortunately, significant and expensive manual effort is required to rewrite legacy
code into idiomatic Rust.

After at least two decades of experience applying sophisticated tools towards mitigating memory safety
issues in C and C++, the software engineering community has largely concluded that bug finding tools
DARPA-SN-24-89
are not sufficient. Rather, the consensus is that it is preferable to use “safe” programming languages that
reject unsafe programs at compile time.

The TRACTOR program aims to achieve a high degree of automation towards translating legacy C to
Rust, with the same quality and style that a skilled Rust developer would employ, thereby permanently
eliminating the entire class of memory safety security vulnerabilities present in C programs. Performers
might employ novel combinations of software analysis (e.g., static analysis and dynamic analysis), and
machine learning techniques (e.g., large language models).

A draft solicitation for TRACTOR will be posted at sam.gov after release of this special notice and will
be linked from https://www.darpa.mil/program/translating-all-c-to-rust.

Переклад (перекладав з допомогою ШІ codestral):
Цитата
ТРАКТОР: ФОН І ЦІЛІ

Вразливості переповнення буфера та інші пов'язані з "безпекою пам'яті" програмні помилки дозволяють атакувачу впроваджувати повідомлення, які захоплюють контроль над комп'ютером. Ці вразливості можливі тільки тому, що програми, написані на C та C++, не змушують своїх розробників перевіряти умови, такі як межі масиву або арифметичні операції над вказівниками, на коректність. Google і Microsoft оцінили, що 70% їхніх проблем з безпекою походять від цих і інших пов'язаних з безпекою пам'яті питань. Хоча існують різноманітні підходи для мінімізації цих ризиків, нові мови програмування, такі як Rust, можуть повністю виключити їх, зберігаючи ефективність. На жаль, для переписання легасі-коду в ідіоматичний Rust необхідно значні і дорогі ручні втручання.

Після принаймні двох десятиліть досвіду застосування складних інструментів для мінімізації проблем з безпекою пам'яті в C та C++, спільнота інженерів програмного забезпечення в цілому прийшла до висновку, що інструменти знаходження помилок недостатні. Натомість консенсус полягає в тому, що краще використовувати "безпечні" мови програмування, які відхиляють небезпечні програми під час компіляції.

Програма TRACTOR має на меті досягти високого ступеня автоматизації перекладу легасі-коду C на Rust з такою ж якістю та стилем, що і досвідчений розробник Rust, таким чином назавжди виключивши всі класи безпеки програмних вразливостей, присутніх у програмах C. Виконавці можуть застосовувати нові комбінації аналізу програмного забезпечення (наприклад, статичний та динамічний аналіз) і технік машинного навчання (наприклад, великих мовних моделей).

Чернетка звернення для TRACTOR буде опублікована на сайті sam.gov після виходу цього спеціального повідомлення і буде посилатися на https://www.darpa.mil/program/translating-all-c-to-rust.


« Змінено: 2024-07-31 08:06:52 від Володимир Лісівка »
[Fedora Linux]

Відсутній yvs115

  • Новачок
  • *
  • дописів: 30
  • Карма: +0/-0
Цитата
don’t force their developers to check conditions, such as array bounds or pointer arithmetic, for correctness.

цікаво чи вдасться прикласти той TRACTOR до базового unsafe Rust коду, покаже час

Відсутній xuser13

  • Графоман
  • ****
  • дописів: 486
  • Карма: +0/-0
А якщо Rust, то вразливеостей не стане?
чи планетяне щче не подали блакитне свитло?

Відсутній yvs115

  • Новачок
  • *
  • дописів: 30
  • Карма: +0/-0
А якщо Rust, то вразливеостей не стане?
враховуючи що мова йде тільки про один тип безпеки - memory safety (про інші типи там нічого нема) і тільки про safe rust (а суттєва частина кодується з unsafe rust заради достатнього рівня швидкодії), то це про зменшення їх кількості, а не про "не стане"

Відсутній Володимир Лісівка

  • Адміністратор ЩОДО
  • Видавець
  • *****
  • дописів: 3800
  • Карма: +9/-0
  • Програміст
> а суттєва частина кодується з unsafe rust заради достатнього рівня швидкодії

Unsafe rust зменшує швидкість коду до швидкості Сі, через те що компілятор не може застосувати частину оптимізацій, а не збільшує. Небезпечний код використовують тоді, коли можливості мови не дозволяють реалізувати задумане безпечними методами. Типовий приклад, це коли потрібно редагувати різні частини однієї структури в різних методах.

Раст вимагає що всі редагування відбувалися через одного «власника даних», для уникнення колізій, але якщо програміст впевнений що колізій не буде, тому що різні частини коду будуть редагувати різні дані, то він може використати unsafe для того щоб отримати кілька посилань на дані, з можливістю редагування, і роздати їх різним функціям.

Також unsafe часто потрібен при роботі з бібліотеками на Сі/Сі++, ядром, апаратурою, пам'яттю,  чи додатковими можливостями процесора, про які компілятор нічого не знає і не може допомогти переконатися у їхній коректності. Це малий відсоток від всього коду на Rust. За статистикою, 80% бібліотек взагалі не мають небезпечного коду.
[Fedora Linux]

Відсутній yvs115

  • Новачок
  • *
  • дописів: 30
  • Карма: +0/-0
> а суттєва частина кодується з unsafe rust заради достатнього рівня швидкодії

Unsafe rust зменшує швидкість коду до швидкості Сі, через те що компілятор не може застосувати частину оптимізацій, а не збільшує.
не зовсім точно, або зовсім не точно: unsafe rust більш швидкий відносно safe rust переважно за рахунок відсутності runtime checks (ще трохи швидкості додає додаткова можлива оптимізація відповідного коду компілятором, але це тільки додатковий бонус). З unsafe rust код може досягати швидкодії C кода.

Цитата
Небезпечний код використовують тоді, коли можливості мови не дозволяють реалізувати задумане безпечними методами.
теж ні - переважно для швидкодії (приклад - більшість з тих що часто юзаються rust crates, і спроби використання rust коду в модулях ядрах які виливаються в дискусії щодо необхідності стандарту на unsafe rust). Використання же unsafe в юзер код більш різноманітні.

Цитата
Також unsafe часто потрібен при роботі з бібліотеками на Сі/Сі++, ядром, апаратурою, пам'яттю,  чи додатковими можливостями процесора, про які компілятор нічого не знає і не може допомогти переконатися у їхній коректності. Це малий відсоток від всього коду на Rust. За статистикою, 80% бібліотек взагалі не мають небезпечного коду.
тут багато недомовок:
- "Це малий відсоток від всього коду на Rust. За статистикою, 80% бібліотек взагалі не мають небезпечного коду".
-- За сухою стат. самої Rust foundation щодо crates - там близько 20/40% процентів unsafe (40 через кросзалежності). Якщо взяти те що використовується часто і те що ні (cтд 20/80) - то процент буде значно біільш ніж 40%. Потім - якщо враховувати що зазвичай використовуються більш ніж один crate, то вірогідність що rust софт unsafe (transitive safety) ще значно більша навіть якщо там немає жодної unsafe конструкції.
- "% бібліотек взагалі не мають небезпечного коду"
-- і це тільки один з аспектів безпечного коду - memory safety, тут значно більше пунктів ніж memory (про які забувають говорячи про код в rust)
« Змінено: 2024-08-05 13:26:07 від yvs115 »

Відсутній Володимир Лісівка

  • Адміністратор ЩОДО
  • Видавець
  • *****
  • дописів: 3800
  • Карма: +9/-0
  • Програміст
не зовсім точно, або зовсім не точно: unsafe rust більш швидкий відносно safe rust переважно за рахунок відсутності runtime checks (ще трохи швидкості додає додаткова можлива оптимізація відповідного коду компілятором, але це тільки додатковий бонус). З unsafe rust код може досягати швидкодії C кода.

Сі:
Код: C
  1. #include "stdint.h"
  2. #include "stdlib.h"
  3. #include "stdio.h"
  4.  
  5. uint64_t* fibonacci(int length) {
  6.     uint64_t* fib = (uint64_t*)malloc(sizeof(uint64_t)*length);
  7.  
  8.     if (length > 1) {
  9.         fib[1] = 1;
  10.     }
  11.  
  12.     if (length > 2) {
  13.         for(int i=2; i<length; i++) {
  14.             fib[i] = fib[i-1] + fib[i-2];
  15.         }
  16.     }
  17.  
  18.     return fib;
  19. }
  20.  
  21. int main(int argc, char** argv) {
  22.     int length=atoi(argv[1]); // TODO: error handling
  23.     uint64_t* fib = fibonacci(length);
  24.     printf("%lu", fib[length-1]);
  25.  
  26.     return 0;
  27. }
  28.  

Наївний переклад з Сі на Раст:
Код: C
  1. fn fibonacci_vec(length: usize) -> Vec<u64> {
  2.     let mut fib = vec![0; length];
  3.  
  4.     if length > 1 {
  5.         fib[1] = 1;
  6.     }
  7.  
  8.     if length > 2 {
  9.         for i in 2..length {
  10.             fib[i] = fib[i-1] + fib[i-2];
  11.         }
  12.     }
  13.  
  14.     fib
  15. }
  16.  
  17. pub fn main() {
  18.     let arg = std::env::args().nth(1).expect("Please specify length");
  19.     let length: usize = arg.parse().expect("That's not a number!");
  20.     let fibonacci = fibonacci_vec(length);
  21.     println!("{:?}", fibonacci.last());
  22. }
  23.  

Ідіоматичний Rust:
Код: C
  1. use std::cell::Cell;
  2.  
  3. pub fn fibonacci_vec(length: usize) -> Vec<u64> {
  4.     let mut fib = vec![0; length];
  5.  
  6.     if fib.len() > 1 {
  7.         fib[1] = 1;
  8.     }
  9.  
  10.     if fib.len() > 2 {
  11.         for window in Cell::from_mut(&mut fib[..]).as_slice_of_cells().windows(3) {
  12.             window[2].set(window[1].get() + window[0].get());
  13.         }
  14.     }
  15.  
  16.     fib
  17. }
  18.  
  19. pub fn main() {
  20.     let arg = std::env::args().nth(1).expect("Please specify length");
  21.     let length: usize = arg.parse().expect("That's not a number!");
  22.     let fibonacci = fibonacci_vec(length);
  23.     println!("{:?}", fibonacci.last());
  24. }
  25.  
  26.  

Компілював з -O3.

$ hyperfine './fib_gcc 100000000' './fibclang 100000000' 'target/release/fibvec_iterator_cell 100000000' 'target/release/fibvec_naive_indexing 100000000'
Benchmark 1: ./fib_gcc 100000000
  Time (mean ± σ):     278.3 ms ±   3.2 ms    [User: 49.4 ms, System: 227.9 ms]
  Range (min … max):   273.5 ms … 283.7 ms    10 runs
 
Benchmark 2: ./fibclang 100000000
  Time (mean ± σ):     307.3 ms ±   4.1 ms    [User: 78.6 ms, System: 227.5 ms]
  Range (min … max):   301.8 ms … 314.3 ms    10 runs
 
Benchmark 3: target/release/fibvec_iterator_cell 100000000
  Time (mean ± σ):     278.1 ms ±   5.4 ms    [User: 46.2 ms, System: 230.7 ms]
  Range (min … max):   274.0 ms … 289.4 ms    10 runs
 
Benchmark 4: target/release/fibvec_naive_indexing 100000000
  Time (mean ± σ):     307.7 ms ±   2.3 ms    [User: 78.0 ms, System: 228.4 ms]
  Range (min … max):   304.2 ms … 312.0 ms    10 runs
 
Summary
  target/release/fibvec_iterator_cell 100000000 ran
    1.00 ± 0.02 times faster than ./fib_gcc 100000000
    1.11 ± 0.03 times faster than ./fibclang 100000000
    1.11 ± 0.02 times faster than target/release/fibvec_naive_indexing 100000000

Висновок: ідіоматичний і безпечний Rust (llvm) на 11% швидший ніж ідіоматичний Сі (clang), і має таку ж швидкість як Сі (gcc). Наївний але безпечний Rust (llvm) має таку ж швидкість як Сі (clang).

Цитата
Цитата
Небезпечний код використовують тоді, коли можливості мови не дозволяють реалізувати задумане безпечними методами.
теж ні - переважно для швидкодії

Результати тестів покажете чи повірити вам на слово?


Цитата
(приклад - більшість з тих що часто юзаються rust crates, і спроби використання rust коду в модулях ядрах які виливаються в дискусії щодо необхідності стандарту на unsafe rust). Використання же unsafe в юзер код більш різноманітні.
Раст в ядрі хочуть використовувати якраз тому, що він дає додаткові гарантії безпеки.

Цитата
- "Це малий відсоток від всього коду на Rust. За статистикою, 80% бібліотек взагалі не мають небезпечного коду".
-- За сухою стат. самої Rust foundation щодо crates - там близько 20%... процентів unsafe (40 через кросзалежності).

20% бібліотек мають unsafe, 100%-20% = 80% не мають.

Цитата
Якщо взяти те що використовується часто і те що ні (cтд 20/80) - то процент буде значно біільш ніж 40%.
Потім - якщо враховувати що зазвичай використовуються більш ніж один crate, то вірогідність що rust софт unsafe (transitive safety) ще значно більша навіть якщо там немає жодної unsafe конструкції.
Ви про те, що якщо взяти будь яку програму на Раст, то там є небезпечний код в скомпільованому файлі? Це 100%.

Цитата
-- і це тільки один з аспектів безпечного коду - memory safety, тут значно більше пунктів ніж memory (про які забувають говорячи про код в rust)
Помилки при роботі з пам'яттю зараз складають приблизно 60% усіх вразливостей. Rust дозволяє позбутися від значної кількості цих помилок, тобто скоротити кількість всіх вразливостей на половину.

Ніхто не забуває про логічні помилки, арифметичні переповнення, або некоректне використання коду. В Rust це називається unsoundness (слабкість?).
[Fedora Linux]

Відсутній yvs115

  • Новачок
  • *
  • дописів: 30
  • Карма: +0/-0
перфомансами займатись то таке,
але okay - там є інші питання зав'язані на код

не зовсім точно, або зовсім не точно: unsafe rust більш швидкий відносно safe rust переважно за рахунок відсутності runtime checks (ще трохи швидкості додає додаткова можлива оптимізація відповідного коду компілятором, але це тільки додатковий бонус). З unsafe rust код може досягати швидкодії C кода.

Сі:
iuint64_t* fib = (uint64_t*)malloc(sizeof(uint64_t)*length);
...
for(int i=2; i<length; i++) {
     fib[i] = fib[i-1] + fib[i-2];
}
Наївний переклад з Сі на Раст:
let mut fib = vec![0; length];
...
for i in 2..length {
     fib[i] = fib[i-1] + fib[i-2];
}
Ідіоматичний Rust:
let mut fib = vec![0; length];
...
for window in Cell::from_mut(&mut fib[..]).as_slice_of_cells().windows(3) {
      window[2].set(window[1].get() + window[0].get());
}

Компілював з -O3.
$ hyperfine './fib_gcc 100000000' './fibclang 100000000' 'target/release/fibvec_iterator_cell 100000000' 'target/release/fibvec_naive_indexing 100000000'
Benchmark 1: ./fib_gcc 100000000
  Time (mean ± σ):     278.3 ms ±   3.2 ms    [User: 49.4 ms, System: 227.9 ms]
  Range (min … max):   273.5 ms … 283.7 ms    10 runs
 
Benchmark 2: ./fibclang 100000000
  Time (mean ± σ):     307.3 ms ±   4.1 ms    [User: 78.6 ms, System: 227.5 ms]
  Range (min … max):   301.8 ms … 314.3 ms    10 runs
 
Benchmark 3: target/release/fibvec_iterator_cell 100000000
  Time (mean ± σ):     278.1 ms ±   5.4 ms    [User: 46.2 ms, System: 230.7 ms]
  Range (min … max):   274.0 ms … 289.4 ms    10 runs
 
Benchmark 4: target/release/fibvec_naive_indexing 100000000
  Time (mean ± σ):     307.7 ms ±   2.3 ms    [User: 78.0 ms, System: 228.4 ms]
  Range (min … max):   304.2 ms … 312.0 ms    10 runs
 
Summary
  target/release/fibvec_iterator_cell 100000000 ran
    1.00 ± 0.02 times faster than ./fib_gcc 100000000
    1.11 ± 0.03 times faster than ./fibclang 100000000
    1.11 ± 0.02 times faster than target/release/fibvec_naive_indexing 100000000

Висновок: ідіоматичний і безпечний Rust (llvm) на 11% швидший ніж ідіоматичний Сі (clang), і має таку ж швидкість як Сі (gcc). Наївний але безпечний Rust (llvm) має таку ж швидкість як Сі (clang).

вже бачу що заюзан unsafe cell для швидкодії щоб зрівнятись з cі -
ви ж розумієте що "Cell has the same memory layout and caveats as UnsafeCell"?

відносно clang що юзали - не знаю яка зборка то, які runtime checks заюзані по дефолту (якщо там повключені для safety: stack-protector boundary-checks etc. - то результат відповідно буде повільніший, тобто може бути tradeoff між safety і perfomance).
Або ж просто той hiperpuper щось своє тредове наміряв.

Потім - бачу помилку в c коді. Щоб зрозуміти до чого вона може призводить:
(junk filling: в bsd це j option зазвичай, в glibc - PERTURB)
% ./fib_gcc 10
34

% MALLOC_PERTURB_=13 ./fib_gcc 10
17144620962624171516

- якщо rust використовує таксамо системний аллокатор - буде те само що в cі
- якщо в rust стекова алокація (стекова память суттєво швидша) - використовуйте таку і в сі (a не heap malloc)
- якщо якась своя rust оптимізація - будуть помилки іншого типу, нп такого типу можуть бути
% ./fib_gcc $((1000 * 1000 * 1000))
13425198974673467106

% ./fib_rs_naive $((1000 * 1000 * 1000))
Some(13425198974673467106)

% ./fib_gcc $((1000 * 1000 * 1000 * 10))
6733232933538918685

% ./fib_rs_naive $((1000 * 1000 * 1000 * 10))
memory allocation of 80000000000 bytes failed
IOT instruction (core dumped)  ./fib_rs_naive $((1000 * 1000 * 1000 * 10))
oops,
safe rust у цьому випадку падає доволі впевнено (safely?)

тест з тим кодом на мому компі (варіант коли malloc віддає заповнену нулями памя'ть)
% gcc -O3 -o fib_gcc fib_c.c
% clang -O3 -o fib_clang fib_c.c
% rustc -C opt-level=3 -o fib_rs_naive fib_rs_naive.rs
% rustc -C opt-level=3 -o fib_rs_index fib_rs_index.rs

% ls -l
.rw-rw-r-- 530 yvs  6 сер 07:51 fib_c.c
.rwxrwxr-x 16k yvs  6 сер 08:08 fib_clang
.rwxrwxr-x 16k yvs  6 сер 08:08 fib_gcc
.rwxrwxr-x 13M yvs  6 сер 08:09 fib_rs_index
.rw-rw-r-- 602 yvs  6 сер 07:52 fib_rs_index.rs
.rwxrwxr-x 13M yvs  6 сер 08:09 fib_rs_naive
.rw-rw-r-- 492 yvs  6 сер 07:52 fib_rs_naive.rs

% N=$((10 * 1000 * 1000))
% multitime -n 10 ./fib_gcc $N >/dev/null
===> multitime results
1: ./fib_gcc 10000000
            Mean        Std.Dev.    Min         Median      Max
real        0.047       0.002       0.043       0.047       0.050       
user        0.008       0.002       0.003       0.008       0.012       
sys         0.039       0.003       0.034       0.039       0.043       

% multitime -n 10 ./fib_clang $N >/dev/null
===> multitime results
1: ./fib_clang 10000000
            Mean        Std.Dev.    Min         Median      Max
real        0.053       0.003       0.047       0.053       0.057       
user        0.012       0.003       0.008       0.012       0.018       
sys         0.041       0.004       0.034       0.041       0.045       

% multitime -n 10 ./fib_rs_naive $N >/dev/null
===> multitime results
1: ./fib_rs_naive 10000000
            Mean        Std.Dev.    Min         Median      Max
real        0.052       0.002       0.048       0.052       0.054       
user        0.014       0.003       0.007       0.014       0.018       
sys         0.038       0.003       0.035       0.036       0.043       

% multitime -n 10 ./fib_rs_index $N >/dev/null
===> multitime results
1: ./fib_rs_index 10000000
            Mean        Std.Dev.    Min         Median      Max
real        0.048       0.001       0.046       0.048       0.050       
user        0.009       0.003       0.005       0.009       0.013       
sys         0.039       0.003       0.033       0.038       0.043       
на відносно крупних виборках приблизно те що і очікувалось

на дрібних виборках дають себе знати ліві мегабайти супутнього rust коду:
% multitime -n 100 ./fib_rs_index 1000 >/dev/null
===> multitime results
1: ./fib_rs_index 1000
            Mean        Std.Dev.    Min         Median      Max
real        0.002       0.000       0.001       0.002       0.002       
user        0.000       0.001       0.000       0.000       0.002       
sys         0.001       0.001       0.000       0.001       0.002       

% multitime -n 100 ./fib_gcc 1000 >/dev/null
===> multitime results
1: ./fib_gcc 1000
            Mean        Std.Dev.    Min         Median      Max
real        0.001       0.000       0.001       0.001       0.002       
user        0.000       0.000       0.000       0.000       0.001       
sys         0.001       0.000       0.000       0.001       0.002       

Цитата
Цитата
Цитата
Небезпечний код використовують тоді, коли можливості мови не дозволяють реалізувати задумане безпечними методами.
теж ні - переважно для швидкодії
Результати тестів покажете чи повірити вам на слово?
дивіться вище тест по наведеному коду

не бачу чим той тест змінює наступне (скоріш підтверджує якщо допустити що використовується алокація пам'яті одного типу - в тому не впевнений):
- runtime checks уповільнюють код (але більш safe в аспекті memory safety) [і неважливо з якої мови він отримувався прі інших рівних параметрах - алгоритм, оптимізація, і т.п.];
- rust unsafe код швидче за rust safe;
- rust unsafe код приблизно дає більш-меньш таку саму швидкодію що і c unsafe;

Цитата
Цитата
(приклад - більшість з тих що часто юзаються rust crates, і спроби використання rust коду в модулях ядрах які виливаються в дискусії щодо необхідності стандарту на unsafe rust). Використання же unsafe в юзер код більш різноманітні.
Раст в ядрі хочуть використовувати якраз тому, що він дає додаткові гарантії безпеки.
бачивши дискусії щодо требаб стандартизацію unsafe rust для linux ядра - є дуже великі сумніви до того що саме тим движе і що раст фани декларують

Цитата
Цитата
- "Це малий відсоток від всього коду на Rust. За статистикою, 80% бібліотек взагалі не мають небезпечного коду".
-- За сухою стат. самої Rust foundation щодо crates - там близько 20%... процентів unsafe (40 через кросзалежності).

20% бібліотек мають unsafe, 100%-20% = 80% не мають.
а чого зупинились після однієї аріфм.дії, дуже мало залишиться далі?
Rust foundation не дає цифри щодо transitive memory unsafety, але ж можно приблизно порядки плюс-мінус уявити:
кросзалежності тут це "make a direct function call into another crate that uses the unsafe keyword" -
вірогідність 100-~40 = ~60 якщо використовувати один crate вибраний по рандомайзу,
потім зі 100% крейтів заберіть ті які не викорстовуються часто (щоб бути ближче до практики) -
скільки залишиться 30%? 50%? а якщо врахувати що використовувати більш ніж один crate?

Цитата
Цитата
Якщо взяти те що використовується часто і те що ні (cтд 20/80) - то процент буде значно біільш ніж 40%.
Потім - якщо враховувати що зазвичай використовуються більш ніж один crate, то вірогідність що rust софт unsafe (transitive safety) ще значно більша навіть якщо там немає жодної unsafe конструкції.
Ви про те, що якщо взяти будь яку програму на Раст, то там є небезпечний код в скомпільованому файлі? Це 100%.
на 100% це щодо тесту з UnsafeCell? - не знаю.
А мова була про те що: якщо ви юзаєте unsafe crates - то важко стверджувати щось про safety в цілому.

Цитата
Цитата
-- і це тільки один з аспектів безпечного коду - memory safety, тут значно більше пунктів ніж memory (про які забувають говорячи про код в rust)
Помилки при роботі з пам'яттю зараз складають приблизно 60% усіх вразливостей. Rust дозволяє позбутися від значної кількості цих помилок, тобто скоротити кількість всіх вразливостей на половину.
те що скоротиться кількість вразливостей використовуючи safe rust - це точно, і це добре. (якщо не робити з того хайп, який вже схоже почав сходити)
про що і написав з самого початку.
Додам що це win-win ситуація по відношенню до інших мов програмування.

Цитата
Ніхто не забуває про логічні помилки, арифметичні переповнення, або некоректне використання коду. В Rust це називається unsoundness (слабкість?).
unsoundness - нестійкість (якщо буквально йти від "safe and sound" - у безпеці й непошкоджений)

краще скажіть за рахунок чого думаєте rust може бути швидче? (при умові використання однакових алгоритмів, однакової оптимізації, однакового типу пам'яті). я можу щось не знати відносно rust бо мало з ним стикаюсь.

скажу за рахунок чого може бути повільніше - за рахунок runtime checks (нп bounds checking). Навіть ще добавлю в порівняння нп openbsd: код системи думаю що там safe у набагато більш аспектах ніж memsafety у rust, але ж жах як там все повільно робить...

Відсутній Володимир Лісівка

  • Адміністратор ЩОДО
  • Видавець
  • *****
  • дописів: 3800
  • Карма: +9/-0
  • Програміст
Я не полінувався і поставив нічну збірку Rust, де є методи для доступу до елементів масиву без перевірок.

Код: C
  1.         for i in 2..length {
  2.             unsafe { *fib.get_unchecked_mut(i) = fib.get_unchecked(i-1) + fib.get_unchecked(i-2); }
  3.         }
  4.  

$ hyperfine './fib_gcc 100000000'  'target/release/fibvec_naive_indexing 100000000' 'target/release/fibvec_unsafe_indexing 100000000'
Benchmark 1: ./fib_gcc 100000000
  Time (mean ± σ):     284.7 ms ±   3.7 ms    [User: 47.8 ms, System: 235.9 ms]
  Range (min … max):   279.6 ms … 290.8 ms    10 runs
 
Benchmark 2: target/release/fibvec_naive_indexing 100000000
  Time (mean ± σ):     284.5 ms ±   2.6 ms    [User: 47.4 ms, System: 236.1 ms]
  Range (min … max):   279.2 ms … 287.9 ms    10 runs
 
Benchmark 3: target/release/fibvec_unsafe_indexing 100000000
  Time (mean ± σ):     313.2 ms ±   2.8 ms    [User: 76.2 ms, System: 235.9 ms]
  Range (min … max):   308.9 ms … 317.4 ms    10 runs
 
Summary
  target/release/fibvec_naive_indexing 100000000 ran
    1.00 ± 0.02 times faster than ./fib_gcc 100000000
    1.10 ± 0.01 times faster than target/release/fibvec_unsafe_indexing 100000000

Тести показують, що, в майбутніх версіях компілятора Rust, швидкодія коду, подібного на Сі, майже зрівняється зі швидкістю коду на Сі, а небезпечний код без перевірок є повільнішим на 10%, а не швидшим. В інтернеті є тести інших програмістів, з такими ж результатами.

Сучасні процесор вже давно не виконують інструкції послідовно і можуть пропускати деякі інструкції або забігати наперед (спекулятивне виконання коду), тому наші уявлення про код треба перевіряти реальними тестами.

Також нагадую, що 100% коду на Расті непрямо використовують unsafe, а також що компілятор, на жаль, пропускає деякі перевірки, коли компілює release, наприклад при приведенні типів.

«Soundness» — це будівельний термін що означає «надійність», буквально «дзвінкість» або «гучність» по нашому. Коли стукають по міцному дереву, металу, бетону — воно гучно дзвенить (sound), а коли втратили міцність — звук глухий (unsound). У філософії, аргументи називають sound (надійні), якщо вони базуються на припущеннях, які також sound; і unsound — якщо хоча б одне припущення unsound.

Ціллю системних програмістів на Расті є зробити безпечний (safe) код надійним (sound) при допомозі обгортання небезпечного (unsafe) і ненадійного (unsound) коду у надійні обгортки.

Як побічний ефект, такий код також досить часто виходить швидшим напевно через те, що компілятор і процесор бачать що код надійний, і тому більше оптимізують виконання під прямий шлях де все пучком. Я не спеціаліст по сучасним компіляторам і процесорам, тому мені ліньки розбиратися як вони цього досягають, але тести показують що ефект присутній.
[Fedora Linux]

Відсутній Володимир Лісівка

  • Адміністратор ЩОДО
  • Видавець
  • *****
  • дописів: 3800
  • Карма: +9/-0
  • Програміст
Код: C
  1. for window in Cell::from_mut(&mut fib[..]).as_slice_of_cells().windows(3) {
  2.       window[2].set(window[1].get() + window[0].get());
  3. }
  4.  

Цитата
вже бачу що заюзан unsafe cell для швидкодії щоб зрівнятись з cі -
ви ж розумієте що "Cell has the same memory layout and caveats as UnsafeCell"?

Я чітко вказую компілятору, що я збираюся міняти значення елементів масиву незалежно один від одного, і він підтверджує що у даному випадку це безпечно. Cell ніяк не впливає на перевірки доступу до елементів масиву — я всеодно отримую зріз масиву і ітерую по ньому. Компілятор прибирає перевірки через те, що використовується ітератор, щодо якого компілятор впевнений що він не вийде за межі масиву, вікно на 3 елементи, і статичні індекси у вікні, які перевіряються статично на етапі компіляції.
[Fedora Linux]

Відсутній yvs115

  • Новачок
  • *
  • дописів: 30
  • Карма: +0/-0
Цитата
вже бачу що заюзан unsafe cell для швидкодії щоб зрівнятись з cі -
ви ж розумієте що "Cell has the same memory layout and caveats as UnsafeCell"?

Я чітко вказую компілятору, що я збираюся міняти значення елементів масиву незалежно один від одного, і він підтверджує що у даному випадку це безпечно. Cell ніяк не впливає на перевірки доступу до елементів масиву — я всеодно отримую зріз масиву і ітерую по ньому. Компілятор прибирає перевірки через те, що використовується ітератор, щодо якого компілятор впевнений що він не вийде за межі масиву, вікно на 3 елементи, і статичні індекси у вікні, які перевіряються статично на етапі компіляції.
- для чого використано unsafe в назві й відключаються деякі перевірки? (роблячи то потенціально unsafe як і зазначено в його назві - якщо розуміти unsafe як unsafe, а safe як safe)
- "Я чітко вказую" це несерйозно якщо ви працюєте з потенційно unsafe конструкціями
- відносно алокатора і функцій з ним роботи: де подивитись відносно алокатора в Rust, коли це heap allocation, stack allocation, initialiaziation? (нп щоб розуміти де яка швидкодія буде)

p.s.
Цитата
for window in Cell::from_mut(&mut fib[..]).as_slice_of_cells().windows(3) { window[2].set(window[1].get() + window[0].get()); }
круто a+b виглядає з масивами, навіть не хочу уявляти як то буде виглядати якщо більш складна аріфметика буде необхідна

Відсутній Володимир Лісівка

  • Адміністратор ЩОДО
  • Видавець
  • *****
  • дописів: 3800
  • Карма: +9/-0
  • Програміст
Цитата
для чого використано unsafe в назві й відключаються деякі перевірки? (роблячи то потенціально unsafe як і зазначено в його назві - якщо розуміти unsafe як unsafe, а safe як safe)

Ви напевно сплутали Cell (клітина) і UnsafeCell. Обидва типи — це просто обгортки (вони зникають на етапі компіляції), які дозволяють програмісту редагувати вміст незалежно від інших даних, але Cell не дає редагувати дані з кількох різних місць, тому конфлікти не можливі, тоді як UnsafeCell не має ніяких обмежень — всі перевірки лягають на програміста. Я не використовував UnsafeCell.

Я раджу запитатися у ШІ (напр. Gemini), якщо щось не зрозуміло. Він досить добре розжовує.

Цитата
відносно алокатора і функцій з ним роботи: де подивитись відносно алокатора в Rust, коли це heap allocation, stack allocation, initialiaziation? (нп щоб розуміти де яка швидкодія буде)

Раст виділяє пам'ять в стеку. В купі пам'ять виділяється лише тоді, коли використовуються типи, які використовують купу. Типовими прикладами є масив — в стеку, Vec - в купі, &str - в стеку, String -  в купі. Якщо якісь дані потрібно помістити в купу, використовується Box. Є ще купа інших бібліотек, які використовують різні методи зберігання даних, напр. арени чи змішані стратегії стек/купа.

Знову ж таки, ШІ зараз чудово все пояснює українською мовою.

Цитата
круто a+b виглядає з масивами, навіть не хочу уявляти як то буде виглядати якщо більш складна аріфметика буде необхідна

Значно компактніше та зрозуміліше, чим безпечний код на Сі. Я нагадаю, що 60% всіх вразливостей у коді на Сі — це переповнення буфера, тобто хтось десь пропустив перевірку меж масиву. Якщо ви маєте рішення, яке дозволить писати код на Сі без цих вразливостей і без втрати продуктивності, то негайно повідомте Міністерство Оборони США, або хоча б нас. Це грубі гроші.
[Fedora Linux]

Відсутній yvs115

  • Новачок
  • *
  • дописів: 30
  • Карма: +0/-0
Я раджу запитатися у ШІ (напр. Gemini), якщо щось не зрозуміло. Він досить добре розжовує.
ясно... відносно помилки в тому коді вище
« Змінено: 2024-08-07 02:03:55 від yvs115 »

Відсутній xuser13

  • Графоман
  • ****
  • дописів: 486
  • Карма: +0/-0
Про памʼять і безпеку я вже таке читав про .NET і Java. Виходять торомозні програми та ще й зі своїм особливим управлінням памʼяттю бо існує garbage collector який може такого науправляти що часом хочеться щоб його не було. Вся ця движуха з Rust про це ж саме?
чи планетяне щче не подали блакитне свитло?