2014-10-02 17 views
9

Я понимаю, что следующий код имеет неопределенное поведение в C++ из-за чего-то, называемого «строгим правилом псевдонимов».Строгое сглаживание в ржавчине?

#include <cstdint> 

enum Foo : int16_t {}; 

void test(Foo& foo) { 
    reinterpret_cast<int16_t&>(foo) = 42; 
} 

В частности, компилятор С ++ может опустить назначение вообще, поскольку это позволило предположить, что int16_t& возвращаемое reinterpret_cast не указывает на ту же память, как foo (типа Foo&), потому что их типы другой.

Вопрос в том, имеет ли Rust что-то похожее на «строгое правило псевдонимов C++»? Другими словами, имеет ли неопределенный код следующий эквивалентный код Rust?

#[repr(i16)] 
enum Foo { Dummy } 

unsafe fn test(foo: &mut Foo) { 
    *std::mem::transmute::<&mut Foo, &mut i16>(foo) = 42; 
} 

EDIT:
Там же несвязанный вопрос с приведенной выше примером Rust кодой в этом test создает несуществующий вариант перечисления. Итак, вот тот же самый код с быстро исправить:

#[repr(i16)] 
enum Foo { Dummy, Yummy = 42 } 

unsafe fn test(foo: &mut Foo) { 
    *std::mem::transmute::<&mut Foo, &mut i16>(foo) = 42; 
} 
+0

Насколько я понимаю, C/C++, по сути, говорит: «Запись памяти как одного типа и чтение ее как другого типа никогда не бывает хорошо, за исключением случаев, когда вы используете« union »или читаете как« char » , У ржавчины нет такого правила одеяла, и законность зависит от конкретной пары рассматриваемых типов. – glaebhoerl

ответ

6

Я понимаю, что общий код Rust (как проверяется компилятором), конечно, не содержит неопределенное поведения (запрещающие ошибки компилятора), и что Rust-в- Язык не определяет какое-либо неопределенное поведение, в отличие от C.

Естественно, что единственное место неопределенного поведения могло произошло в пределах unsafe блоков или функций. unsafe предназначены для инкапсуляции любого потенциально опасного поведения как being safe as a whole. A post from July 2014 упоминает, что компилятор Rust требует, чтобы выполнялись определенные инварианты, и что это вообще dangerous to break those invariants, even in unsafe blocks (на самом деле, это возможно только в unsafe блоках).

Одним из таких опасных видов поведения является pointer aliasing (что, как представляется, определено в LLVM). Интересно отметить, однако, документы говорят LLVM (курсив мой):

Следовательно, тип анализ на основе псевдонима, также известный как TBAA, также известный как -fstrict-наложения спектров, это не относится к общему неукрашенному LLVM IR

Таким образом, кажется, что, как правило, до тех пор, пока в результате блока unsafe не запускается какое-либо другое небезопасное поведение, строгое сглаживание не является проблемой в Rust.


Это, как говорится, ваш конкретный пример, возможно, опасно, потому что, кажется, соответствует одному из небезопасного поведения со ссылкой:

недопустимых значений в примитивных типов, даже в частных полей/местных :

  • Дискриминантные в перечислении не включен в определении типа

Я написал небольшое расширение на ваш пример, который показывает двоичные представления вариантов перечислений, до и после небезопасной операции: http://is.gd/x0K9kN

Как вы можете видеть, назначая 42 к значению перечисления не соответствует ни одному из определенные значения дискриминатора. Если, однако, вы назначили 0 или 1 значению перечисления (или вместо этого определили явные дискриминаторы для вариантов перечисления), то операция должна теоретически быть прекрасной.

+2

«Если, однако, вы присвоили значение 0 или 1 значению перечисления (или вместо этого указали явные дискриминаторы для вариантов перечисления), то операция должна теоретически быть в порядке». Макет Enum на самом деле не определен, поэтому без явных descriminants даже назначение 0 или 1 возможно неопределенное поведение (то есть компилятору разрешено выбирать не использовать 0 и 1). – huon

+0

@dbaupp: текущие документы кажутся немного разреженными - я не мог найти нигде, где явно указано, что макет переименования C-типа не определен (C-подобные перечисления уже являются особым случаем, во всяком случае). Однако я нашел более старую статью, в которой [говорится, что автоматические дискриминаторы начинаются с 0] (https://gist.github.com/brson/9dec4195a88066fa42e6#enumerations), но, похоже, это не часть текущих документов больше. – voithos

+0

«Я понимаю, что общий код Rust [...], конечно, не содержит неопределенного поведения [...], и что Rust-language не определяет какое-либо неопределенное поведение, в отличие от C.». Правда для безопасного ржавчины, но небезопасная Rust имеет все те же проблемы, что и C, и требует определения UB так же, как и C. Это определение [WIP] (https://internals.rust-lang.org/t/proposal-reboot-the-unsafe-code-guidelines-team-as-a-working-group/7307). Но да, у Rust нет строгих псевдонимов на основе типов, как это делает C (++). Он имеет псевдонимы, основанные на '& mut' и' & ', но это не должно быть проблемой. –

Смежные вопросы