Заметки о Unix: надёжная работа с API C-библиотеки Unix возможна только из программ, написанных на C

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.
Для того чтобы полностью реализовать требования системы верификации источника системных вызовов, разработчики OpenBSD хотят, чтобы Go выполнял бы системные вызовы через C-библиотеку, а не напрямую, из собственной среды выполнения (а у Go есть некоторые причины поступать именно так). На первый взгляд это кажется не особенно серьёзной проблемой. Это, конечно, немного неудобно, но у языка вроде Go должна быть возможность просто выполнять вызовы обычных функций из C-библиотеки, вроде open() (и использовать ABI вызова C-функций). К сожалению, не так всё просто, так как очень часто фрагменты обычного API C-библиотеки, на самом деле, реализованы в препроцессоре C. Из-за этого API C-библиотеки нельзя надёжно использовать для решения обычных задач без написания собственного связующего кода на C.



Звучит это, пожалуй, дико, поэтому позвольте мне проиллюстрировать это на примере всеми любимого значения errno, к которому обращаются для получения кода ошибки в том случае, если системный вызов даёт сбой (им же пользуются и для получения кодов ошибок от некоторых библиотечных вызовов). В этом материале я рассказывал о том, что в современных условиях механизм errno должен быть реализован так, чтобы у разных потоков были бы разные значения errno, так как они могут в одно и то же время выполнять различные системные вызовы. Это требует наличия у потоков собственных локальных хранилищ, а к такому хранилищу нельзя обратиться так же, как к простой переменной. Доступ к нему должен быть организован через специальный механизм, поддерживаемый средой выполнения C. Вот объявления errno из OpenBSD 6.6 и из текущей версии Fedora Linux с glibc:

/* OpenBSD */
int *__errno(void);
#define errno (*__errno())

/* Fedora glibc */
extern int *__errno_location (void) __THROW __attribute_const__;
# define errno (*__errno_location ())

В обоих этих случаях переменная errno, на самом деле, представлена определением препроцессора. Это определение ссылается на внутренние недокументированные функции C-библиотеки (на что указывают два символа подчёркивания в их именах), которые не входят в состав общедоступного API. Если скомпилировать код, написанный на C, рассчитанный на работу с этим API errno (включив в код errno.h), то он будет работать, но это — единственный официальный способ работы с errno. Нет некоей обычной переменной errno, которую можно загрузить в среде выполнения своего языка, например, после вызова функции open(). А если вызвать __errno или ____errno_location в своей среде выполнения, то это будет означать использование внутреннего API, который в будущем вполне может измениться (хотя он, вероятно, не изменится). Для того чтобы создавать надёжные среды выполнения языков программирования, которые ориентированы на общедоступный API С-библиотеки, недостаточно просто вызвать экспортированную функцию вроде open(); нужно ещё написать и скомпилировать собственную маленькую C-функцию, которая просто возвращает среде выполнения errno.

(Тут, помимо errno, могут быть и другие важные моменты; я предлагаю самостоятельно поискать их тем, кому интересна эта тема.)

Это, конечно, не какая-то новая проблема Unix. С первых дней stdio в V7 некоторые из «функций» stdio были реализованы в stdio.h в виде макросов препроцессора. Но в течение долгого времени никто не настаивал на том, чтобы единственным официально поддерживаемым способом выполнения системных вызовов было бы их выполнение из C-библиотеки, что позволяло обойти нечто вроде того, что представляет собой современный механизм errno, в тех случаях, когда не нужна совместимость с C-кодом.

(До того, как в Unix появилась многопоточность, сущность errno была представлена простой переменной и, в целом, выглядела как хороший, хотя и не идеальный интерфейс.)

Пользовались ли вы когда-нибудь недокументированными API?


Источник: https://habr.com/ru/company/ruvds/blog/555658/


Интересные статьи

Интересные статьи

Я прочитал немало статей о том, что удалёнка — это зло для разработчика. Что проседает продуктивность, потому что отвлекаешься на бытовуху. Что человек не может сосредоточиться, потому чт...
Коничива Хабр! В глазах многих людей Япония — земля спокойствия дзен-садов, безмятежные храмы и изысканные чайные церемонии. Как традиционные, так и современные японские архитектура, кн...
«УРАЛХИМ» делает удобрения. № 1 в России — по производству аммиачной селитры, например, входит в топ-3 отечественных производителей аммиака, карбамида, азотных удобрений. Выпускаются ...
Всем привет. В этой статье я опишу свой опыт настройки и использования sway — тайлингового оконного менеджера для Linux. Читать дальше →
Google недавно выпустила в публичный доступ новую версию Google Analytics под названием App + Web. Симо Ахава уже написал отличную пошаговую инструкцию о том, как начать работать с инструментом, ...