LINUX.ORG.RU

Релиз Wasmer 1.0

 , wasmer, ,


1

1

Выпущен Wasmer 1.0 — среда выполнения WebAssembly (сокр. Wasm), написанная на Rust. Wasm автоматически помещает приложения в песочницу для безопасного выполнения, защищая хост от ошибок и уязвимостей в них. Wasm также предоставляет экономичную среду выполнения, позволяющую контейнерам Wasmer работать там, где контейнеры Docker слишком громоздки.

Особенности выпуска:

  • Параллельная компиляция в разы уменьшила время компиляции программ.
  • Компиляторы на выбор: Singlepass (упор на быстроту компиляции), Cranelift, LLVM (упор на оптимизацию кода).
  • Появление кросс-компиляции, возможность скомпилировать Wasm для aarch64 архитектуры с x86_64 машины и наоборот.
  • Поддержка Apple Silicon.

>>> Подробности

★★★

Проверено: Shaman007 ()

Ответ на: комментарий от alienclaster

Даст варнинг со ссылкой на документацию и rust best recipes? :)

#![warn(clippy::pedantic)]

use std::rc::Rc;

#[derive(Clone, Debug)]
struct X {
}

fn f(_: X) {
    
}

fn just_print(x: Rc<X>) {
    println!("{:?}", *x);
}

fn just_print_2(mut x: X) {
    println!("{:?}", x);
}

fn main() {
    let x = X{};
    f(x.clone());
    f(x.clone());
    
    let x2 = X{};
    let x2 = Rc::new(x2);
    just_print(x2);
    
    let x3 = X{};
    just_print_2(x3);
}
$ cargo clippy
warning: variable does not need to be mutable
  --> src/main.rs:17:17
   |
17 | fn just_print_2(mut x: X) {
   |                 ----^
   |                 |
   |                 help: remove this `mut`
   |
   = note: `#[warn(unused_mut)]` on by default

warning: this argument is passed by value, but not consumed in the function body
  --> src/main.rs:13:18
   |
13 | fn just_print(x: Rc<X>) {
   |                  ^^^^^ help: consider taking a reference instead: `&Rc<X>`
   |
note: the lint level is defined here
  --> src/main.rs:1:9
   |
1  | #![warn(clippy::pedantic)]
   |         ^^^^^^^^^^^^^^^^
   = note: `#[warn(clippy::needless_pass_by_value)]` implied by `#[warn(clippy::pedantic)]`
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value

warning: redundant clone
  --> src/main.rs:24:8
   |
24 |     f(x.clone());
   |        ^^^^^^^^ help: remove this
   |
   = note: `#[warn(clippy::redundant_clone)]` on by default
note: this value is dropped without further use
  --> src/main.rs:24:7
   |
24 |     f(x.clone());
   |       ^
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone

warning: 3 warnings emitted
  • Зачем тебе mut, ты же не мутируешь ничего

  • Ладно, пускай ты пользуешься счетчиком ссылок, мало ли почему. Может тебе нужен такой тип для еще чего-то. Но в функции just_print ты точно не получаешь никакой пользы от увеличения счетчика и сразу уменьшения. Более того, это приватная функция, потому я знаю что ты это делаешь даже не для публичного стабильного интерфейса «на будущее». Просто одолжи, убережешься от пары тактов.

  • Не нужно клонировать два раза, тогда по настоящему у тебя получается три копии, но третью ты сразу выкидываешь. Просто перемещай вторую

vertexua ★★★★★
()
Ответ на: комментарий от anonymous

shared_ptr всегда можно заменить на альтернативные способы (например арены памяти).

Не могу оценить это утверждение, никогда не работал с регионами в С++ - но на сколько я понял, если регионов много, то там тоже будут свои «нюансы».

alienclaster ★★★
()
Ответ на: комментарий от alienclaster

Арены кстати интересно реализуются в Rust. Внутри будет unsafe, но снаружи lifetimes будут следить чтобы указатели никогда не жили дольше арены

vertexua ★★★★★
()
Ответ на: комментарий от Legioner

Линуксовый. cgroups и технологии, основанный на нём (docker и тд).

Смешались в кучу люди, котлеты. Cgroups, namespaces, seccomp, lsm – это не контейнеры, а api предоставляемые ядром для огораживания процессов. С ними в плане безопасности всё относительно хорошо.

Докер – контейнерная виртуализация, работающая на базе предыдущих. Его аффтары [s]ложили на[/s] не ставили перед собой безопасность как цель, поэтому он особо безопасным ими самими не считается.

И тд надо смотреть отдельно.

Можно поспорить на счёт минимальной TCB в процесс-ядро проитв вм-гипервизор, но это всё теория.

anonymous
()
Ответ на: комментарий от Oxd34d10cc

std::mem::take

Которая требует T: Default. Очень полезная альтернатива.

Можно, если опираться на готовые примитивы

Они, конечно, написаны на unsafe

Вы противоречите сами себе.

но кого это волнует?

Любого здравомыслящего человека?

Siborgium ★★★★★
()
Ответ на: комментарий от anonymous

там для 99% проблем есть готовое решение.

Посмотрите в потроха этой библиотеки.

Но да объем того что нужно изучить очень приличный

Нет, никакого объема там нет.

Siborgium ★★★★★
()
Ответ на: комментарий от Siborgium

Которая требует T: Default

А тебе хотелось объект в unspecified состоянии оставить? В Rust так не принято.

Вы противоречите сами себе.

Нет тут противоречия. В коде реализации самого Rc никакого unsafe не будет, потому что можно просто взять и переиспользовать безопасную абстракцию. То, что эта абстракция сама написана с помощью unsafe уже детали реализации. Никто не мешает сделать std::cell::Cell встроенной конструкцией языка, а не библиотечной структурой, только кому от этого лучше станет?

Любого здравомыслящего человека?

Любой здравомыслящий человек должен понимать, что в любой программе как ни крути где-то там внизу по коллстеку полюбому будет unsafe и от этого никуда не убежать. Суть Rust не в том, чтобы «писать без unsafe», а чтобы этот unsafe максимально изолировать.

Oxd34d10cc
()
Ответ на: комментарий от Oxd34d10cc

В Rust так не принято.

Какая мне разница, что там принято? Я говорю – нет способа, вы мне – так не принято. Способа нет не потому, что так не принято, а потому что базовая модель не позволяет.

В коде реализации самого Rc никакого unsafe не будет

Нет, будет. От заворачивания в слои абстракции unsafe никуда не денется. Я бы понял, если бы вы говорили про unsafe для взаимодействия с платформозависимыми API – но речь об unsafe для реализации inner mutability, которая никак базовой моделью не предусматривается.

Суть Rust не в том, чтобы «писать без unsafe», а чтобы этот unsafe максимально изолировать.

Снова чушь. Вы можете изолировать unsafe только когда вы заворачиваете готовые интерфейсы, либо когда заворачиваете ради заворачивания. Попробуйте писать на Rust низкоуровневый код. Я пробовал – едет unsafe через unsafe. Заворачивать его бессмысленно, либо будет протекающая абстракция без реальных гарантий, либо ассерты на каждый вызов. У вас в невинном коде вида

fn do_something() -> Result<(), ()> {
    if unsafe { !call_c_fn() } {
        Ok(())
    } else {
        Err(())
    }
}

fn main() {
    if let Ok(_) = do_something() {
        // ...
    }
}

семантически вместо одного ветвления будет минимум два – внутри do_something и для того, чтобы сделать матч по результату. Ошибку принято пробрасывать вверх, поэтому там будет на каждом уровне еще по матчу. Что поделать – писать panic! с хэндлерами вместо исключений раст-библия не позволяет.

Это если отвечать на ваш аргумент, принимая, что вы почитали контекст и понимаете, на что отвечаете. Вы не понимаете.

Изначально я говорил о том, что базовая модель скудна, и никакой семантики счетчика ссылок (для компилятора) у Rc нет, ее никак нельзя выразить. Более того, чтобы вообще написать Rc, нужно показать компилятору, что вы умнее его и сами предоставите гарантии корректной работы Rc, написав unsafe (неважно, на каком уровне). Ваши слова только подтверждают мой тезис.

Siborgium ★★★★★
()
Последнее исправление: Siborgium (всего исправлений: 1)
Ответ на: комментарий от Siborgium

Я говорю – нет способа, вы мне – так не принято

Способ я тебе показал. Чем он тебя не устраивает ты так и не объяснил.

Вы можете изолировать unsafe только когда вы заворачиваете готовые интерфейсы, либо когда заворачиваете ради заворачивания. Попробуйте писать на Rust низкоуровневый код. Я пробовал – едет unsafe через unsafe. Заворачивать его бессмысленно, либо будет протекающая абстракция без реальных гарантий, либо ассерты на каждый вызов

Читаю как «я не осилил, значит и у вас (и никого другого) тоже не получится». Какие фундаментальные проблемы подхода изолирования unsafe? Почему не получится? Ты свой субъективный опыт считаешь за объективную истину?

У вас в невинном коде вида

Это то тут вообще к чему?

Oxd34d10cc
()
Ответ на: комментарий от Siborgium

Посмотрите в потроха этой библиотеки.

Там будет unsafe это сразу подразумевалось, unsafe и предназначен для того чтобы делать то что модель раста не допускает напрямую или допускает, но с жертвами производительности.

Нет, никакого объема там нет.

Там нет никакого объема если сравнить с объемом знаний (часто весьма неявных) чтобы хорошо писать на C++, но вполне приличный по сравнению с другими языками.

anonymous
()
Ответ на: комментарий от Oxd34d10cc

Способ я тебе показал. Чем он тебя не устраивает ты так и не объяснил.

Меня способ не устраивает:

  1. Наличием T: Default. Как минимум, это вынуждает писать реализации трейтов непонятно для чего.

  2. (Самое главное) – отсутствие ссылочного полиморфизма и необходимость вызывать какие-то функции. Впрочем, иначе быть и не могло – нет конструкторов, которых в свою очередь нет из-за проблем базовой модели.

Какие фундаментальные проблемы подхода изолирования unsafe

Фундаментальная проблема – либо ты покрываешь unsafe проверками, которые понятия не имеют о контексте и убивают производительность, либо проверки убираешь вообще, и прописываешь их руками где ноебходимо, но тогда «safe» интерфейс ничем от unsafe не отличается.

Ты свой субъективный опыт считаешь за объективную истину

Я могу выбрать любой крейт с unsafe и он будет подпадать под одну из этих категорий. Обычно под первую.

Это то тут вообще к чему?

Это пример того, почему заворачивание unsafe в проверки влечет за собой деградацию производительности.

Собственно, мне вообще без разницы, как там можно изолировать, или не изолировать, или что-то третье. Я говорю: модель убога. Лучше, чем си с классами, но все еще убога. Никаких счетчиков ссылок нет, компилятор ничего не понимает и выдает гигантское число ложных срабатываний. Сверху утверждают противоположное.

Siborgium ★★★★★
()
Ответ на: комментарий от anonymous

модель раста не допускает напрямую или допускает, но с жертвами производительности.

Ну то есть приходим к подтверждению моего тезиса? С чем спорит персонаж выше в таком случае?

Siborgium ★★★★★
()
Ответ на: комментарий от Siborgium

Ну то есть приходим к подтверждению моего тезиса? С чем спорит персонаж выше в таком случае?

Да скорее согласен с тем что модель раста во многом убога, но думаю ей есть куда совершенствоваться, и она вполе развивается, года три еще назад borrow checker не пропускал гораздо больше вполне корректного кода. По unsafe, это очень хорошая вещь и позволяет писать большую часть кода в безопасном подмножестве языка. Идея изоляции мне очень понравилась, неплохо бы и в C++ перенять. Сейчас в D это пытаются до ума довести, может и в C++ потом перекочует. По unsafe оберткам не вижу ничего плохого в паре лишних проверок, во первых на фоне вызова самой фунции это почти всегда незаметно, во вторых я например и в C++ всегда стараюсь оборачивать сишные апи, и обычно не использую на таком низком уровне исключения.

anonymous
()
Ответ на: комментарий от Siborgium

либо ты покрываешь unsafe проверками, которые понятия не имеют о контексте и убивают производительность,

Насчет «убивают производительность» очень спорно, это нужно с профайлером смотреть, думаю разницы на практике не будет.

либо проверки убираешь вообще, и прописываешь их руками где ноебходимо, но тогда «safe» интерфейс ничем от unsafe не отличается.

Это не вариант, ты должен гарантировать что все что выходит из unsafe безопасно.
Ну и я не понимаю, весь этот плач, и думаю что для системного и около софта даже если четверть будет сидеть в unsafe это лучше чем 100% unsafe в других языках.

anonymous
()
Ответ на: комментарий от Siborgium

В расте move осуществляется всегда. Я не могу написать код вида … потому что владение v безусловно передается в insert.

match map.entry(&k) {
    Entry::Occupied(_) => foo(v),
    Entry::Vacant(e) => { e.insert(v); }
}

Разве это не «conditional move», которого ты хочешь?

DarkEld3r ★★★★★
()
Ответ на: комментарий от alienclaster

Не могу оценить это утверждение, никогда не работал с регионами в С++ - но на сколько я понял, если регионов много, то там тоже будут свои «нюансы».

В C++ с чем бы ты не работал, всегда будут нюансы, даже в банальных вещах типа векторов.

anonymous
()
Ответ на: комментарий от Siborgium

Нет, здесь нет conditional move, здесь есть безусловный move в каждом из двух бранчей.

Можешь объяснить в чем разница, ведь результат получается идентичный?

anonymous
()
Ответ на: комментарий от anonymous

Результат идентичен только на этом синтетическом примере, который я писал конкретно к insert if not exists.

Ключевое различие в том, что в расте я могу только передать владение куда-то. Это убирает веер проблем, но и вместе с веером возможностей. В С++ соответствующий тип ссылки сигнализирует о возможности взять владение. В зависимости от условия я могу как воспользоваться этой возможностью, так и проигнорировать ее – в этом случае перемещаемый объект останется нетронутым.

Siborgium ★★★★★
()

Она уже научилась не падать от любого неудобного поворота?

anonymous
()
Ответ на: комментарий от anonymous

Но ведь это достаточно большой класс задач.

Я бы не сказал. И даже в этом классе, при необходимости (например тормозах) shared_ptr всегда можно заменить на альтернативные способы (например арены памяти).

На счет нетормозящих арен памяти, счетчика ссылок, rust и C++:

«We evaluated Go and Java for their concurrent, parallel GCs, and C++ for its reference counting. Interestingly, reference counting is often described as more efficient than GC, but in our case that’s not true: Because there is a huge object graph at some stage that needs to be deallocated, reference counting incurs more or less the same pause that a non-concurrent GC does. That’s why we don’t expect Rust to fare better here either.»

-- Pascal Costanza, разработчик elPrep : a high-performance tool for analyzing sequence alignment/map files in sequencing pipelines.
Разрабатывают прототип на CL и переписывают на -> Go, потому как в открытых реализациях CL нет современных параллельных сборщиков мусора.

(c) https://lisp-journey.gitlab.io/blog/pro-mailing-list-on-common-lisp-and-paral...

alienclaster ★★★
()
Ответ на: комментарий от alienclaster

Разрабатывают прототип на CL и переписывают на -> Go, потому как в открытых реализациях CL нет современных параллельных сборщиков мусора.

Хорошо, в следующей итерации перепишут на C++ или rust :)

anonymous
()
Ответ на: комментарий от Siborgium

В зависимости от условия я могу как воспользоваться этой возможностью, так и проигнорировать ее – в этом случае перемещаемый объект останется нетронутым.

Допустим, но по самому объекту ведь это всё равно понять нельзя? Тебе придётся возвращать из функции, например, bool, который скажет был объект перемещён или нет. В расте можно сделать похожим образом, правда возвращать не флажок, а сам объект: fn insert_if_not_exist(T) -> Option<T>. Вполне себе «conditional move».

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

Так указанная мной проблема и решается на данный момент. Нет, это не conditional move и это перемещает исходный объект в худшем случае дважды – если все copy elision отработают должным образом. В противном случае худший случай будет еще хуже.

Siborgium ★★★★★
()
Последнее исправление: Siborgium (всего исправлений: 1)
Ответ на: комментарий от alienclaster

Там написано, почему нет.

Там написано что они не осилили нормально работу с памятью в языках без GC :) Для лисперов это вполне простительно.

anonymous
()
Ответ на: комментарий от anonymous

Там написано что они не осилили нормально работу с памятью в языках без GC :)

Они отказались от С++ хотя и рассматривали его и по ссылке написано почему. Коммерческие варианты лиспа я хз почему им не подошли, подозреваю, Allegro очень дорогой был со стремной лицензией, а в LW, наверное, сборщик мусора неплохой, но не параллельный, для их задачи этот момент, видимо, был принципиальным, раз они отказались от обычного лиспа и JVM (хотя в последнейтоже появились уже сборщики современные).

Для лисперов это вполне простительно.

Наивно было ожидать адекватную реакцию с вашей стороны :) Но я попробовал.

alienclaster ★★★
()
Ответ на: комментарий от alienclaster

Они отказались от С++ хотя и рассматривали его и по ссылке написано почему.

По ссылке у них огромный граф объектов который освобождается как одно целое, и упоминается только подсчет ссылок и ни слова о других методах управления памятью возможных в С++, хотя их ситуация похоже вполне хорошо ложится на арены обсужденные чуть выше.

Наивно было ожидать адекватную реакцию с вашей стороны :) Но я попробовал.

Вполне адекватно все, вместо лисперов можно подставить любых пользователей языков с GC. Все-таки управлять памятью вручную или полуавтоматически как в С++ или расте отдельный навык и его нужно иметь чтобы даже хотя бы адекватно оценить ту же применимость С++ к задаче.

anonymous
()
Ответ на: комментарий от anonymous

У меня просто нет особого повода сомневаться в компетентности этих челиков, система все же не наколенная. Наверняка, под «подсчетом ссылок» они имел ввиду, что другие варианты тоже попробовали и они не подошли - остался подсчет ссылок, который тормозит. Но это не точно :)

alienclaster ★★★
()
Ответ на: комментарий от Siborgium

Нет, это не conditional move и это перемещает исходный объект в худшем случае дважды – если все copy elision отработают должным образом.

Согласен, тут ты прав. Можно поспорить насчёт того насколько этот «оверхед» заметен, но не буду.

Но всё-таки не уверен, что понимаю суть претензий. Ведь при желании можно предоставить интерфейс аналогичный entry у хеш мапы и дать пользователю гибкость и отсутствие лишних перемещений ценой чуть большей многословности. Если не хочется заморачиваться, то можно перемещать назад неиспользуемый объект - экономим строки, получаем «лишние мувы». В С++ в данном случае будет чуть проще/гибче, но апи никак не страхует от случайного использования перемещённого объекта. В общем-то в этом обычно и проявляется разница в подходе у этих двух языков.

Или в чём проблема?

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

Ведь при желании можно предоставить интерфейс аналогичный entry у хеш мапы и дать пользователю гибкость и отсутствие лишних перемещений ценой чуть большей многословности.

Можно, конечно, но этот интерфейс придется писать каждый раз с нуля. Набросанный мной try_emplace_noalloc без изменений подойдет для любого контейнера с emplace_back.

не страхует от случайного использования перемещённого объекта

Потому что это полностью корректно, хотя результаты будут варьироваться в зависимости от конкретного типа и конкретного использования. Это логическая ошибка наподобие вычитания вместо сложения или «и» вместо «или».

Или в чём проблема?

Нет никакой проблемы, я защищаю свой исходный тезис и отвечаю на вопросы/замечания.

Siborgium ★★★★★
()
Последнее исправление: Siborgium (всего исправлений: 1)
Ответ на: комментарий от Siborgium

Нет никакой проблемы, я защищаю свой исходный тезис и отвечаю на вопросы/замечания.

Ну исходный тезис всё-таки был, что «сделать нельзя», вернее:

Ключевое различие в том, что в расте я могу только передать владение куда-то. Это убирает веер проблем, но и вместе с веером возможностей.

Я же считаю, что возможности никуда не деваются, пусть и реализуются немного иначе и более многословно.

Это логическая ошибка наподобие вычитания вместо сложения или «и» вместо «или».

Да, согласен.

Хотя можно пойти глубже и сказать, что требование «valid but unspecified state» остаётся на совести автора кода и язык никак это не проверяет.

DarkEld3r ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.