- [ ] Умеет писать unsafe код и безопасные обёртки для него. - [ ] Понимает причины UB и знает, как его не допустить. (откуда взялось, что значит и как может нанести вред работе программы) - [ ] для автора - проверка ОРа квизами, включая примеры кода. - [ ] Умеет проектировать безопасный интерфейс для unsafe кода. - [ ] Знает best practice для написания unsafe кода. - [ ] Можно использовать примеры из third party крейтов. - [ ] Начать с проблемы, когда компилятор не может гарантировать безопасность по памяти (но без этого невозможно написать программу), возможно из ub - [ ] Рассказать про причины ub - [ ] Рассказать, чем является unsafe, ответственность на программисте, про ub (НЕ является избавлением от borrow checker) - [ ] Рассказать про применение unsafe (взаимодействие с С, оптимизация (вспомнить небезопасную либу для бэкенда: rocket или actix), написание основы/базы языка) - [ ] Определении функции unsafe если соблюдение инвариантов висит на пользователе (при написании такой функции смотреть - является ли сам интерфейс функции safe) - [ ] примеры из third party - [ ] Рассказать про бест практис при написании unsafe: - [ ] Лучший unsafe - отсутствующий unsafe - [ ] Уменьшение зоны unsafe (легче найти баг + проще просчитать ub) - [ ] Safety - [ ] SAFETY - [ ] assert_unsafe_precondition! - [ ] ... - [ ] Практика - [ ] Лайфтаймы как помошники при взаимодействии с c abi - [ ] Drop Почему unsafe внутри unsafe fn: фн показывает, что инварианты должен соблюдать пользователь функции ансейф блок же показывает скоуп, где нужно искать баги (где они и будут тк анйсейф операция) подводный камень: при ансейф баг может возникать в любом из блоков анйсефа, даже если он возникает в другом месте ub: из-за различий архитектру цп и ос и для оптимизаций еслм возникает баг, значит неправильно реализованы инварианты в одном из unsafe блоков с которым взаимодействовали (даже в совершенно другом месте) Возможно рассказать еще про это все? - pointers - nonnull - phantomdata (инвариантность/ковариантность и тд) - unsafecell - send/sync + unsafe trait markers (мб практический пример: написание собстенного mutex) - unsafe traits - При описании бест практис про Safety, привести пример, почему нужно (а еще потому, что при изменении логики функции самим тоже нужно следить, какие инварианты висят за пользователем) Практика: подумайте над тем, какие инварианты тут должны быть соблюдены и какие из них не соблюдены. или пропробовать найти несоблюденный инвариант и "взломать" программу?) допустим, нам нужно дя создания сокета узнать, можем ли мы использовать tcp/udp/icmp/etc, для этого используем сискол WSAEnumProtocolsA # Start В прошлом уроке мы научились использовать C функции в своем rust коде. Давайте же расширим свои знания, и научимся взаимодействовать с таким кодом. В прошлом уроке в практическом задании вам встречался такой код: ```rust include!(concat!(env!("OUT_DIR"), "/bindgen.rs")); use std::ffi::{CStr, CString}; const TEST_JSON: &CStr = c"{ \"meaning_of_life\": 42 }"; fn main() { let json: *mut cJSON = unsafe { cJSON_Parse(TEST_JSON.as_ptr()) }; let json_str = unsafe { cJSON_PrintUnformatted(json) }; let json_str = unsafe { CString::from_raw(json_str) }; let json_str = json_str.to_str().unwrap(); assert_eq!(json_str, r#"{"meaning_of_life":42}"#); let meaning_of_life = unsafe { cJSON_GetObjectItem(json, c"meaning_of_life".as_ptr()) }; let meaning_of_life = unsafe { cJSON_GetNumberValue(meaning_of_life) }; println!("Meaning of life: {}", meaning_of_life); assert_eq!(meaning_of_life, 42f64); } ``` У json обозначен не встречавшийся до этого тип `*mut _` ## Сырые указатели Вы уже неоднократно пользовались референсами в своем коде. В этих типах компилятор следит за временем жизни, чтобы не обратится к памяти после освобождения, а так же за валидностью памяти. Но, когда дело доходит до вызова внешней функции компилятор уже будет не способен отследить время жизни и валидность памяти. Поэтому в rust есть аналогичный тип - сырые указатели. Он унаследован по синтаксису и смыслу от своих предшественников (в частности от С), поэтому его описание выглядит так: `*const T` - для неизменяемого указателя на тип T `*mut T` - для изменяемого указателя на тип T Внутри себя он, точно так же, как и референс, содержит адрес на память и опционально метадату, но сырой указатель не дает абсолютно никаких гарантий по памяти. Это нетипично для rust, но так необходимо при взаимодействии с внешними функциями, так для них компилятор никак не может гарантировать безопасность. ## Взаимодействие с сырым указателем Если же сырой указатель не дает **Начать с проблемы, когда компилятор не может гарантировать безопасность по памяти (но без этого невозможно написать программу), возможно из ub** Допустим, на вход вашей функции **Рассказать про причины ub** - как в математике есть неопределенности (к примеру, для деления на ноль), так и в языках программирования тоже есть свои неопределенности. Именно для этого и было создана такая вещь, как неопределённое поведение. Неопределено, значит никогда не случается. Значит компилятор может оптимизировать код только соблюдая верность тех случаев, что не являются ub. (пример с nullptr дереф) **Рассказать, чем является unsafe, ответственность на программисте, про ub (НЕ является избавлением от borrow checker)** **Как про отдельную вещь рассказать про вызов unsafe функции** **Рассказать про применение unsafe (взаимодействие с С, оптимизация (вспомнить небезопасную либу для бэкенда: rocket или actix), написание основы/базы языка)** **Практика по пути** **Мб рассказать про кейс с лайфтаймами** - [ ] Определении функции unsafe если соблюдение инвариантов висит на пользователе (при написании такой функции смотреть - является ли сам интерфейс функции safe) - [ ] примеры из third party - [ ] Рассказать про бест практис при написании unsafe: - [ ] Лучший unsafe - отсутствующий unsafe - [ ] Уменьшение зоны unsafe (легче найти баг + проще просчитать ub) - [ ] Safety - [ ] SAFETY - [ ] assert_unsafe_precondition! - [ ] ... - [ ] Практика - [ ] Лайфтаймы как помошники при взаимодействии с c abi - [ ] Drop