#article
Статья (перевод) от основателя Signal с впечатлениями от так называемого web3.
TL;DR: реалии этих проектов противоречат декларируемым ценностям (главным образом децентрализации) и вообще катастрофически сломаны.
Статья (перевод) от основателя Signal с впечатлениями от так называемого web3.
TL;DR: реалии этих проектов противоречат декларируемым ценностям (главным образом децентрализации) и вообще катастрофически сломаны.
Moxie Marlinspike
My first impressions of web3
Despite considering myself a cryptographer, I have not found myself particularly drawn to “crypto.” I don’t think I’ve ever actually said the words “get off my lawn,” but I’m much more likely to click on Pepperidge Farm Remembers flavored memes about how…
запуск завтра
Извините, что ночью, но исследователи утверждают, что Pegasus стабильно взламывает самую последнюю версию айфона (14.6). Без всяких кликов по ссылкам, просто посылают жертве «заряженную смску» (сообщение в iMessage) и всё, атакующий владеет телефоном. Речь…
#itsec #article
A deep dive into an NSO zero-click iMessage exploit: Remote Code Execution
Подробная техническая статья о том, как именно работает 0-click exploit, позволяющий скомпрометировать устройство без каких-либо действий со стороны пользователя. Опять комбинация out of bounds {write, read} и парсера изображений вкупе с Тьюринговой трясиной одного экзотического формата изображений.
A deep dive into an NSO zero-click iMessage exploit: Remote Code Execution
Подробная техническая статья о том, как именно работает 0-click exploit, позволяющий скомпрометировать устройство без каких-либо действий со стороны пользователя. Опять комбинация out of bounds {write, read} и парсера изображений вкупе с Тьюринговой трясиной одного экзотического формата изображений.
Blogspot
A deep dive into an NSO zero-click iMessage exploit: Remote Code Execution
Posted by Ian Beer & Samuel Groß of Google Project Zero We want to thank Citizen Lab for sharing a sample of the FORCEDENTRY exploit w...
Forwarded from мне не нравится реальность
В свежем Rust 1.58.0 наконец-то можно использовать переменные напрямую при форматировании строк:
let person = get_person();Пока что это работает только с именами, а не произвольными выражениями, но всё равно приятно. Прощайте
// ...
println!("Hello, {person}!"); // captures the local `person`
format!("{name}", name = name);
!Forwarded from мне не нравится реальность
Ещё из плющек:
— теперь
— Теперь правила ансайзинга для дженерик структур немного проще[1]
— В
— реализация
—
[1]: Новые правила позволяют такое:
А полные новые правила такие:
— the tail field depends on at least one type or const parameter not used in any other field
— the target struct can be created from the source by replacing only the parameters only found in the last struct field
— the tail field implements
[2]: Ранее они были отключены из-за того, что их нельзя выполнить в
— теперь
*const T
указатели можно дерефать в константных контекстах— Теперь правила ансайзинга для дженерик структур немного проще[1]
— В
copy{,_nonoverlapping}
опять включили debug_assert
'ы[2]— реализация
Clone
для RSplit<T, P>
больше не требует T: Clone
— Трейт Termiation
теперь реализов для Result<Infallible, E>
, позволяя писать fn main() -> Result<Infallible, ErrorType>
, для програм которые не заканчиваются успешно через выход из main
— Стабилизировали File::options
, замену FileOptions::new
— Стабилизировали {Option,Result}::unwrap_unchecked
— Стабилизировали многие методы Duration
и MaybeUninit
как const fn
— Компилятор теперь будет пытаться применять стабильные методы прежде, чем не стабильные. Это позволит избежать поломок при добавлении в std
методов, пересикающихся по именам с методами из сторонних трейтов.—
rustdoc
теперь показывает методы из всех Deref
реализаций, рекурсивно (а не только из первой)[1]: Новые правила позволяют такое:
struct A<T, U: ?Sized + 'static>(T, B<T, U>);
struct B<T, U: ?Sized>(T, U);
fn main() {
let x: A<[u32; 1], [u32; 1]> = A([0; 1], B([0; 1], [0; 1]));
// This previously did not work as the last field of `A` also mentions `T`,
// as only `U` changes this is now allowed thanks to this feature.
let _y: &A<[u32; 1], [u32]> = &x;
}
TL;DR: если последнее поле это структура, которая ансайзиться, то теперь и наружняя структура тоже ансайзиться.А полные новые правила такие:
— the tail field depends on at least one type or const parameter not used in any other field
— the target struct can be created from the source by replacing only the parameters only found in the last struct field
— the tail field implements
Unsize
from source to target[2]: Ранее они были отключены из-за того, что их нельзя выполнить в
const fn
Полный список изменений: RELEASES.md#version-1580-2022-01-13#prog #rust
Хозяйке на заметку
Как известно, если у типа в Rust есть несколько методов от разных трейтов с одними и теми же именами, то попытка вызвать один из них при помощи синтаксиса метода будет прервана компилятором с жалобой на неоднозначность имён, вынуждая прибегнуть к развёрнутому синтаксису вызова (
Хозяйке на заметку
Как известно, если у типа в Rust есть несколько методов от разных трейтов с одними и теми же именами, то попытка вызвать один из них при помощи синтаксиса метода будет прервана компилятором с жалобой на неоднозначность имён, вынуждая прибегнуть к развёрнутому синтаксису вызова (
Trait::method(&value, arg1, arg2)
). Менее известен тот факт, что методы самого типа (inherent methods) перекрывают одноимённые методы трейтов, так что если одному имени отвечают метод типа и сколько угодно методов трейтов, то предпочтение всегда отдаётся методу самого типа и не вызывает неоднозначностей. Этим можно воспользоваться, чтобы иметь возможность в необобщённом контексте вызывать методы трейта, не импортируя сам трейт:trait Trait {
fn method(&mut self, arg: Arg);
}
struct Type {
...
}
impl Trait for Type {
fn method(&mut self, arg: Arg) {
...
}
}
impl Type {
fn method(&mut self, arg: Arg) {
Trait::method(self, arg)
}
}
// где-то в другом месте, где в текущем пространстве имён
// есть Type, но нету Trait:
let mut value = Type::make(...);
value.method(arg);
🔥1
#prog #rust #моё
Допустим, нам нужно сделать на Rust бинарное дерево. Казалось бы, плёвое дело:
Но для начала немного о том, как мы будем задавать высоту. Так как решение на const generics потребует специализации и более продвинутой их обработки и потому абсолютно не реализуемо на стабильной версии, воспользуемся для задания высоты числами Пеано (да, я об этом уже писал):
Кажется, что это изложение довольно легко перекладывается на код: определяем трейт с ассоциированным типом, который уменьшает число на единицу, реализуем его дляnever
С другой стороны, так уж сильно нам его менять не придётся: вместо того, чтобы отображать каждое число на число на единицу меньше, вы воспользуемся структурной индукцией и будем отображать число непосредственно на тип узла:
Как всегда, весь код в гисте. И на этот раз даже больше, чем в посте: добавлены методы для поиска по дереву (с допущением, что дерево является двоичным деревом поиска) и немного более приятная печать.
Оставайтесь на связи. 🤙
Допустим, нам нужно сделать на Rust бинарное дерево. Казалось бы, плёвое дело:
struct TreeNode<T> {
value: T,
left: Option<Box<Self>>,
right: Option<Box<Self>>,
}
struct Tree<T> {
root: Option<TreeNode<T>>,
}
Однако тут у нас по аллокации на каждый узел, от чего у нас страдает локальность данных и, как следствие, эффективность кеша (не говоря уже о стоимости аллокаций в рантайме). С другой стороны, у нас есть возможность делать дерево произвольной (насколько хватит оперативки, конечно же) высоты. А можем ли мы, отказавшись от произвольной высоты и задавая её предел наперёд, хранить вложенные узлы напрямую, а не через указатель? Как оказалось, да!Но для начала немного о том, как мы будем задавать высоту. Так как решение на const generics потребует специализации и более продвинутой их обработки и потому абсолютно не реализуемо на стабильной версии, воспользуемся для задания высоты числами Пеано (да, я об этом уже писал):
struct Z;
struct S<T>(T);
Теперь немного подумаем о том, как это отобразить на древовидную структуру. Каждый узел дерева высотой N + 1 включает в себя узлы высотой N. Узел же дерева с высотой 0 не должен включать в себя данные вообще. Этого можно добиться, сопоставив Z тип с полями ненаселённого типа.Кажется, что это изложение довольно легко перекладывается на код: определяем трейт с ассоциированным типом, который уменьшает число на единицу, реализуем его для
S<T>
с типом T
, а для Z
с типом Infallible
, параметризуем узел высотой Height
и параметризуем вложенные узлы <Height as Decrement>::Output
... К сожалению, это не работает: если определить узел таки образом, rustc не понимает, что рекурсия рано или поздно кончается, и жалуется на бесконечную вложенность типа без индирекции. Кажется, нам нужен другой подход.С другой стороны, так уж сильно нам его менять не придётся: вместо того, чтобы отображать каждое число на число на единицу меньше, вы воспользуемся структурной индукцией и будем отображать число непосредственно на тип узла:
struct Node<T, Next> {
value: T,
left: Next,
right: Next,
}
Тут важно, что поля left
и right
имеют тип Next
, а не Option<Next>
, иначе мы не сможем сделать узел нулевой высоты ненаселённым типом. Собственно, вот как отображение выглядит для Z
:use std::convert::Infallible as Never;
trait Project<T> {
type Projected;
}
impl<T> Project<T> for Z {
type Projected = Node<T, Never>;
}
Итого узел нулевой высоты нельзя сконструировать, как мы и хотели. Лишь немногим сложнее выглядит отображение для S<N>
:impl<T, N> Project<T> for S<N>
where
N: Project<T>,
{
type Projected = Node<T, Option<N::Projected>>;
}
Так как мы не хотим оперировать узлами напрямую (хотя бы потому, что через них затруднительно наложить ограничение на высоту), сделаем обёртку — собственно параметризованное высотой дерево:struct Tree<T, Height: Project<T>> {
repr: Height::Projected,
}
Теперь реализуем парочку вспомогательных методов и попробуем сделать дерево высоты 2 (=S<S<Z>>
):let tree: Tree<i32, S<S<Z>>> = Node {
value: 42,
left: None,
right: Some(Node {
value: 42,
left: None,
right: None
}),
}.into();
Что ж... Оно работает. И даже нормально печатается поле repr
, если добавить #[derive(Debug)]
на Node
. Попробуем теперь поменять тип дерева на дерево с единичной высотой:let tree: Tree<i32, S<Z>> = Node {
...
Компилятор ожидаемо жалуется:error[E0271]: type mismatch resolving <Z as Project<i32>>::Projected == Node<{integer}, Option<_>>Не слишком внятно, но цели статически ограничить высоту дерева мы успешно достигли.
--> src/main.rs:181:7
|
181 | }.into();
| ^^^^ expected enum Option, found enum Infallible
|
= note: expected struct Node<{integer}, Option<_>>
found struct Node<i32, Infallible>
Как всегда, весь код в гисте. И на этот раз даже больше, чем в посте: добавлены методы для поиска по дереву (с допущением, что дерево является двоичным деревом поиска) и немного более приятная печать.
Оставайтесь на связи. 🤙
Telegram
Блог*
#prog #rust #моё #article
Здрасьте. Сегодня поста не будет — но только потому, что я решил написать статью для Хабра. Собственно, вот она.
И напоминаю: если вам это понравилось — поддержите копеечкой автора, я вам благодарен буду: 4274 3200 5402 8520.
Здрасьте. Сегодня поста не будет — но только потому, что я решил написать статью для Хабра. Собственно, вот она.
И напоминаю: если вам это понравилось — поддержите копеечкой автора, я вам благодарен буду: 4274 3200 5402 8520.
Блог*
#prog #rust #моё Допустим, нам нужно сделать на Rust бинарное дерево. Казалось бы, плёвое дело: struct TreeNode<T> { value: T, left: Option<Box<Self>>, right: Option<Box<Self>>, } struct Tree<T> { root: Option<TreeNode<T>>, } Однако тут…
> Антон делает то, что я люблю в программировании больше всего — совершенно беcсмысленный, возведённый в абсолют бред, на который потрачено больше времени, чем стоило бы<...>
Ах, Вафель, ты был абсолютно прав.
Кстати, к него на канале уже 400 человечков! 👀🎉
Ах, Вафель, ты был абсолютно прав.
Кстати, к него на канале уже 400 человечков! 👀🎉
Telegram
Мне не нравится реальность
Антон делает то, что я люблю в программировании больше всего — совершенно беcсмысленный, возведённый в абсолют бред, на который потрачено больше времени, чем стоило бы, но зато... зато красиво!
dereference_pointer_there/1210
dereference_pointer_there/1210
#prog #rust #article
Why is my Rust build so slow? — офигенная статья от Амоса про ускорение компиляции большого проекта на Rust
Why is my Rust build so slow? — офигенная статья от Амоса про ускорение компиляции большого проекта на Rust
fasterthanli.me
Why is my Rust build so slow?
I’ve recently come back to an older project of mine (that powers this website), and as I did some maintenance work: upgrade to newer crates, upgrade to a newer rustc, I noticed that my build was ta...
#prog #performancetrap #rust #article
How a Single Line of Code Made a 24-core Server Slower Than a Laptop
TL;DR:Arc::clone на машине с кучей ядер
How a Single Line of Code Made a 24-core Server Slower Than a Laptop
TL;DR:
pkolaczk.github.io
How a Single Line of Code Made a 24-core Server Slower Than a Laptop | Piotr Kołaczkowski
Imagine you wrote a program for a pleasingly parallel problem, where each thread does its own independent piece of work, and the threads don’t need to coordi...
#prog #rust #article
Writing Non-Trivial Macros in Rust — полезная статья о том, как поэтапно писать на Rust (относительно) сложные декларативные макросы. Ссылается на The Little Book of Rust Macros, которая сама по себе достойна прочтения.
Writing Non-Trivial Macros in Rust — полезная статья о том, как поэтапно писать на Rust (относительно) сложные декларативные макросы. Ссылается на The Little Book of Rust Macros, которая сама по себе достойна прочтения.
Michael-F-Bryan
Writing Non-Trivial Macros in Rust
Macros in Rust tend to have a reputation for being complex and magical, the likes which only seasoned wizards like @dtolnay can hope to understand, let alone master.
Rust’s declarative macros provide a mechanism for pattern matching on arbitrary syntax to…
Rust’s declarative macros provide a mechanism for pattern matching on arbitrary syntax to…
#prog #rust #моё
В крейте pulldown-cmark есть структура
Я решил провести эксперимент: поменять определение
Я запустил бенчмарки (кстати, разрабы молодцы, они используют criterion), ожидая увидеть увеличение ПЕРФОРМАНСА. И я действительно его увидел... На бенчмарках, число которых можно было пересчитать по пальцам одной руки. Во всех остальных бенмарках производительность либо не поменялась, либо — что было куда чаще — статистически значимо ухудшилась. 😒
То ли я неверно бенчмаркаю (что вполне может быть, ибо на фоне у меня таки висел VS Code), то ли я чего-то не знаю об оптимизирующих компиляторах. Короче, я разочарован, опечален и сконфужен.
В крейте pulldown-cmark есть структура
Options
, в которой хранятся опции для конфигурирования поведения парсера. Эта структура перемещается внутрь парсера при создании и в процессе парсинга флаги оттуда только считываются, но никогда не меняется. Звучит, как идеальный кандидат для вынесения на уровень типов.Я решил провести эксперимент: поменять определение
Options
с этого:bitflags::bitflags! {
pub struct Options: u32 {
const ENABLE_TABLES = 1 << 1;
const ENABLE_FOOTNOTES = 1 << 2;
const ENABLE_STRIKETHROUGH = 1 << 3;
const ENABLE_TASKLISTS = 1 << 4;
const ENABLE_SMART_PUNCTUATION = 1 << 5;
const ENABLE_HEADING_ATTRIBUTES = 1 << 6;
}
}
на это:pub struct Options<
const ENABLE_TABLES: bool,
const ENABLE_FOOTNOTES: bool,
const ENABLE_STRIKETHROUGH: bool,
const ENABLE_TASKLISTS: bool,
const ENABLE_SMART_PUNCTUATION: bool,
const ENABLE_HEADING_ATTRIBUTES: bool,
>(());
Там, где в коде был вызов, скажем, options.contains(Options::ENABLE_TABLES)
, в моём варианте стал вызов options.enable_tables()
— метод, который просто возвращает значение параметра ENABLE_TABLES
. Имея на руках доказуемо константные значения, компилятор может убрать из кода if-ы и вместе с ними лишний код, что должно снизить объём генерируемого кода для каждого варианта парсинга и повысить производительность за счёт отсутствия ветвлений.Я запустил бенчмарки (кстати, разрабы молодцы, они используют criterion), ожидая увидеть увеличение ПЕРФОРМАНСА. И я действительно его увидел... На бенчмарках, число которых можно было пересчитать по пальцам одной руки. Во всех остальных бенмарках производительность либо не поменялась, либо — что было куда чаще — статистически значимо ухудшилась. 😒
То ли я неверно бенчмаркаю (что вполне может быть, ибо на фоне у меня таки висел VS Code), то ли я чего-то не знаю об оптимизирующих компиляторах. Короче, я разочарован, опечален и сконфужен.
GitHub
GitHub - bheisler/criterion.rs: Statistics-driven benchmarking library for Rust
Statistics-driven benchmarking library for Rust. Contribute to bheisler/criterion.rs development by creating an account on GitHub.
Блог*
#prog #rust #моё #article Здрасьте. Сегодня поста не будет — но только потому, что я решил написать статью для Хабра. Собственно, вот она. И напоминаю: если вам это понравилось — поддержите копеечкой автора, я вам благодарен буду: 4274 3200 5402 8520.
Антон:
— Rust — простой язык, чего вы?
Тоже Антон:
— Rust — простой язык, чего вы?
Тоже Антон:
<List as AsStrList<{ n_digits(<N as NumericValue>::VALUE) }>>::LIST