Как стать автором
Обновить

Комментарии 10

Это вполне очевидное поведение для интернированых строк, куда входят все строковые литералы. Вполне можно "украсть" и заменить чужой литерал через string.Intern()

Это не является какой-то проблемой unsafe кода, это проблема тех кто мутирует общие ресурсы объявленные иммутабельными. Аналогично можно скастить IReadOnlyCollection<T> к T[] и изменить массив, а потом обвинять механизм каста в том что он помог нарушить контракт.

Со строкой вполне можно создать новую через `new string('\0', 100)` и спокойно ее менять.

скастить IReadOnlyCollection<T> к T[] и изменить массив

Если там под капотом реальный ReadOnlyCollection, то он упадёт при попытке изменить его в рантайме

Однако, в том же Linq Expressions на всякий случай под капотом используется класс TrueReadOnlyCollection

Вы описали часть того, для чего именно существует небезопасный контекст в .NET. То что через небезопасный код можно менять интернированные строки -- не новости. И описанные вами проблемы не являются проблемами как таковыми.

Если вы читали Рихтера, то должны помнить вот эту часть:

По умолчанию компилятор C# компании Microsoft генерирует безопасный код. Под этим термином понимается код, безопасность которого подтверждается в процессе верификации. Тем не менее компилятор Microsoft C# также позволяет разработчикам писать небезопасный код, способный напрямую работать с адресами памяти и манипулировать с байтами по этим адресам. Как правило, эти чрезвычайно мощные средства применяются для взаимодействия с неуправляемым кодом или для оптимизации алгоритмов, критичных по времени.
Однако использование небезопасного кода создает значительный риск: небезопасный код может повредить структуры данных и использовать (или даже создавать) уязвимости в системе безопасности.

Собственно, unsafe обозначает, что своими кривыми руками можно сломать все, что вздумается. ССЗБ.

Про ваш пример в листинге 3.2: из-за JIT-компиляции подгрузилась новая строка, потому что в кэше не нашлась эта же строка. Механизм интернирования на стороне CoreCLR вы можете посмотреть здесь: https://github.com/dotnet/runtime/blob/319391eb90065ec2aca29c6de0046e47a1286016/src/coreclr/vm/stringliteralmap.cpp#L403

Мы не можем изменить ссылку, но значение по ссылке изменить проще простого.

К слову, того же можно добиться рефлексией:

typeof(ImmutablePerson)
    .GetField("<Name>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic)
    .SetValue(person, "Michael");

У меня такие задачи люди на скрининге перед собесом решают. Придётся менять задачу, становится слишком легко найти ответ :/

А в реальных проектах часто unsafe код и рефлексия встречается? На какую должность такие вопросы задают?

В библиотеках, latency critical систем, например сериализации, маршрутизации и иной инфраструктуры -да. В остальном нет. В коде прикладного уровня, который писали мои команды,мы такого не допускали. Но задачи собеседования на то и задачи, чтобы тестировать экспертизу, понимание платформы и прочее. Все мы желаем работать с ребятами, которые понимают, что происходит в их коде.

[StructLayout(LayoutKind.Explicit)]
struct BiteData {
    [FieldOffset(0)] byte[] bytes;
    [FieldOffset(0)] Data data;
}

А в чем могут быть проблемы с преобразованием типов с помощью этого? Это не unsafe, и по другому сделать сложно, чтоб без лишнего выделения памяти, мусора и быстро.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории