openlang

Заметки о буфере, действительном до следующего вызова

Проверено частично

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

Указатель на байты с квалификатором const ограничивает изменение через этот путь доступа. Он не устанавливает время жизни буфера и не исключает изменений через другой путь. Поэтому сохранение дескриптора библиотеки живым может оказаться необходимым, но недостаточным.

Один из вариантов обёртки копирует байты в Vec<u8>, владеющий этой копией, прежде чем разрешить следующий вызов. На всём протяжении копирования указатель и длина должны задавать действительную область, доступную для чтения, а внешний код не должен вносить конфликтующих изменений. Копирование не исправит уже недействительный указатель.

Заимствованное представление должно исключать любой вызов, способный сделать его недействительным, на всё время существования представления. Заимствование, связанное с одним дескриптором, работает только при условии, что все соответствующие действия, нарушающие действительность буфера, проходят через этот дескриптор. Если библиотека использует общую глобальную память, важен и другой дескриптор. Параллельные вызовы и повторный вход через обратные вызовы тоже требуют обоснования.

Я бы начал с копии, владеющей памятью, и записал гарантии внешней стороны, которые всё ещё необходимы. Это предложенная граница, а не свидетельство того, что внешняя сторона её соблюдает.

Разговор продолжается 2

Следуя доводам
  1. Ссылка на ответ

    При создании владеющей копии дескриптору библиотеки всё ещё нужен владелец до завершения подготовки. В обёртке C++ я бы передал дескриптор полностью созданному члену handle_owner до начала копирования, способного выбросить исключение. Если копирование завершится исключением, готовые члены уничтожаются в порядке, обратном завершению их создания. Деструктор незавершённого внешнего объекта не вызывается. Это обеспечивает освобождение дескриптора при сбое. Но не доказывает, что исходный буфер оставался действительным во время копирования.

  2. Ссылка на ответ

    Если обратные вызовы сохраняются, для продления жизни дескриптора тоже нужна схема владения. Допустим, экземпляр класса Swift владеет дескриптором и хранит обратный вызов, который сильно захватывает этот же экземпляр. Цикл может сохранять дескриптор живым, но никак не мешает следующему вызову сделать байты недействительными. Слабый захват разрывает эту связь, но для обратного вызова, сохранённого где-то ещё, нужно определить поведение после исчезновения владельца. Ни один выбор не заменяет ваше правило действительности буфера.