FFI-функция может вернуть нулевой указатель как признак ошибки. Какой инвариант нужно проверить до преобразования результата в Rust-ссылку?
До преобразования указателя в Rust-ссылку нужно установить, что он не является null. Если FFI использует null как признак ошибки, Rust должен сначала обработать этот случай и только затем создавать ссылку; преобразование null-указателя в ссылку нарушает её базовый инвариант и приводит к неопределённому поведению.
Проверка на null сама по себе не доказывает безопасность указателя: дополнительно нужны корректные время жизни, выравнивание, инициализация и доступность объекта. Но именно ненулевое значение является обязательным первым условием для ссылки.
C-интерфейсы часто передают отсутствие результата или ошибку через специальное значение указателя — обычно null. Raw pointer в Rust способен представлять такой результат, потому что он допускает null и не утверждает компилятору, что за адресом находится корректный объект.
Rust-ссылка моделирует уже проверенный доступ к объекту. Поэтому её контракт строже: ссылка не может быть null и должна указывать на подходящий живой объект. Это позволяет безопасному коду Rust не обрабатывать null при каждом обычном разыменовании.
Если вернуть из FFI null и без проверки представить его как ссылку, программа нарушит инвариант ссылочного типа ещё до полезного чтения данных. Последствие — неопределённое поведение, а не гарантированная ошибка или безопасная паника.
Даже успешная проверка на null не делает любой адрес безопасным. Указатель может быть освобождён, иметь неверное выравнивание, указывать на неинициализированную память или обозначать объект, доступ к которому нарушает правила алиасинга Rust.
Сначала результат FFI нужно рассматривать как raw pointer. Нулевое значение преобразуется в ошибку, отсутствие результата или другой явно описанный вариант. Только ненулевой указатель можно передавать на следующий этап проверки и потенциального создания ссылки.
Для представления ненулевого raw pointer удобно использовать NonNull<T>. Он кодирует именно свойство ненулевого адреса, но не доказывает корректность объекта, его время жизни или уникальность доступа.
После получения NonNull<T> создание ссылки всё ещё выполняется в unsafe-контексте, потому что вызывающий код обязан подтвердить остальные условия. Для &T объект должен быть живым, корректно выровненным, инициализированным и доступным для чтения; для &mut T дополнительно требуется эксклюзивный доступ на соответствующее время жизни.
Если FFI-документация допускает null только при ошибке, безопасная Rust-обёртка должна скрыть raw pointer и вернуть, например, Result<T, Error> или Option<NonNull<T>>. Это переносит проверку границы FFI в одно место и не заставляет вызывающий код самостоятельно помнить о специальном значении.
Библиотека C возвращает указатель на созданный дескриптор, а null означает отказ из-за неверных параметров. Рассматривались три варианта:
Result или NonNull — требует небольшой дополнительной логики, зато централизует контракт.Выбирается третий вариант. Обёртка превращает null в ошибку, а ненулевой результат сохраняет как NonNull до тех пор, пока отдельная проверка не подтвердит корректность объекта. В результате безопасный вызывающий код не может случайно трактовать ошибочный результат как ссылку.
p != null для создания ссылки?Нет. Ненулевой адрес — только одно из необходимых условий. Нужно также доказать, что объект существует в течение времени жизни ссылки, адрес корректно выровнен для типа, память инициализирована, а доступ разрешён правилами алиасинга и конкретным контрактом FFI.
Ссылка в Rust не имеет соглашения «null означает отсутствие». Подмена null ссылкой на фиктивный объект меняет семантику API и может привести к обращению к памяти, которой не существует. Отсутствие результата нужно выразить типом вроде Option или Result, а не некорректным значением ссылки.
Проверка null всё равно обязательна: код ошибки и указатель должны рассматриваться как части одного контракта. Обёртка должна согласовать их состояния, например отвергнуть ненулевой указатель при ошибочном статусе или null при статусе успеха, если документация требует указатель. Иначе можно создать ссылку из формально ненулевого, но семантически недействительного результата.