Проблема с хрупким двоичным интерфейсом - Fragile binary interface problem

В проблема хрупкого двоичного интерфейса или же ФБР это недостаток некоторых объектно-ориентированного программирования язык компиляторы, в котором внутренние изменения в базовой библиотеке классов могут привести к прекращению работы дочерних библиотек или программ. Это пример уязвимость программного обеспечения.

Эту проблему чаще называют хрупкий базовый класс проблема или же FBC; однако этот термин имеет более широкий смысл.

Причина

Проблема возникает из-за «ярлыка», используемого с компиляторами для многих распространенных объектно-ориентированных (OO) языков, особенности дизайна, которая сохранялась, когда объектно-ориентированные языки развивались из более ранних, не-объектно-ориентированных языков. структурное программирование языки, такие как C и Паскаль.

В этих языках не было объектов в современном понимании, но была похожая конструкция, известная как записывать (или «структура» в C), которая содержала разнообразную связанную информацию в одном фрагменте памяти. Доступ к частям в конкретной записи осуществлялся путем отслеживания начального местоположения записи и знания компенсировать от этой отправной точки до рассматриваемой части. Например, запись «человека» может иметь имя, фамилию и инициал отчества, чтобы получить доступ к инициалу, который записывает программист. thisPerson.middleInitial который компилятор превращает во что-то вроде a = местоположение (thisPerson) + смещение (middleInitial). Современные процессоры обычно включают инструкции для этого общего вида доступа.

Когда впервые разрабатывались компиляторы объектно-ориентированного языка, использовалась большая часть существующей технологии компилятора, а объекты строились на основе концепции записи. В этих языках объекты упоминались по их начальной точке, а доступ к их общедоступным данным, известным как «поля», осуществлялся через известное смещение. По сути, единственным изменением было добавление в запись еще одного поля, которое указывает на неизменяемый таблица виртуальных методов для каждого класса, так что запись описывает как его данные, так и методы (функции). При компиляции смещения используются для доступа как к данным, так и к коду (через таблицу виртуальных методов).

Симптомы

Это приводит к проблеме большего программы когда они построены из библиотеки. Если автор библиотеки изменит размер или макет общедоступных полей в объекте, смещения станут недействительными, и программа больше не будет работать. Это проблема ФБР.

Хотя можно ожидать, что изменения в реализации вызовут проблемы, коварство ФБР заключается в том, что ничего В самом деле изменен только макет объекта, который скрыт в скомпилированной библиотеке. Можно было ожидать, что если кто-то изменится сделай что-нибудь к doSomethingElse что это может вызвать проблемы, но в этом случае можно вызвать проблемы без изменения сделай что-нибудь, это может быть вызвано так же легко, как перемещение строк исходного кода для ясности. Хуже того, программист практически не может контролировать результирующий макет, созданный компилятором, что делает эту проблему почти полностью скрытой от просмотра.

В сложных объектно-ориентированных программы или же библиотеки классы самого высокого уровня могут быть унаследованы от десятков классов. Каждый из этих базовых классов может быть унаследован сотнями других классов. Эти базовые классы хрупки, потому что небольшое изменение одного из них может вызвать проблемы для любого класса, который наследуется от него напрямую или от другого класса, который наследуется. Это может привести к сворачиванию библиотеки как дом из карт столько классов повреждено одним изменением базового класса. Проблема может быть не замечена при написании изменений, если дерево наследования сложное. Действительно, разработчик, изменяющий базовый класс, обычно не знает, какие классы, разработанные другими, используют его.

Решения

Языки

Одно из решений проблемы хрупкого двоичного интерфейса - написать язык, который знает, что проблема существует, и не позволяет ей возникать. Большинство ОО-языков, написанных на заказ, в отличие от языков, созданных на основе более ранних языков, создают все свои таблицы смещения во время загрузки. На этом этапе изменения в макете библиотеки будут «замечены». Другие языки OO, например Себя, создавайте все во время выполнения, копируя и изменяя объекты, найденные в библиотеках, и поэтому на самом деле у них нет базового класса, который может быть хрупким. Некоторые языки, например Ява, располагайте обширной документацией о том, какие изменения можно безопасно внести, не вызывая проблем у ФБР.

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

Однако рынок выбрал такие языки программирования, как C ++ которые действительно «зависят от позиции» и, следовательно, демонстрируют ФБР. В этих случаях есть еще ряд решений проблемы. Один из них возлагает бремя на автора библиотеки, заставляя его вставлять несколько объектов-заполнителей на случай, если им понадобится добавить дополнительные функции в будущем (это можно увидеть в структурах, используемых в DirectX библиотека). Это решение работает хорошо, пока у вас не закончатся эти манекены - и вы не хотите добавлять слишком много, потому что это занимает память.

Цель-C 2.0 обеспечивает нехрупкие переменные экземпляра за счет наличия дополнительного уровня косвенного обращения, например, доступа к переменной.

Другое частичное решение - использовать Образец моста, иногда известный как "Pimpl "(" Указатель на реализацию "). Фреймворк Qt является примером такой реализации. Каждый класс определяет только один член данных, который является указателем на структуру, содержащую данные реализации. Размер самого указателя вряд ли изменится (для данной платформы), поэтому изменение данных реализации не влияет на размер публичной структуры. Однако это не позволяет избежать других критических изменений, таких как введение виртуальных методов в класс, у которого их нет, или изменение графа наследования.

Линкеры

Другое решение требует более умного компоновщика. В оригинальной версии Цель-C формат библиотеки допускал использование нескольких версий одной библиотеки и включал некоторые функции для выбора нужной библиотеки при вызове. Однако это не всегда было необходимо, потому что смещения были необходимы только для полей, поскольку смещения методов собирались во время выполнения и не могли вызвать FBI. Поскольку методы, как правило, изменяются чаще, чем поля, у ObjC изначально было мало проблем с ФБР, и те, которые он делал, можно было исправить с помощью системы контроля версий. В Objective-C 2.0 добавлена ​​«современная среда выполнения», которая также решила проблему ФБР для полей. Кроме того, ТОМ язык использует смещения, собранные во время выполнения, для всего, что делает невозможным ФБР.

Другим решением является использование статических библиотек вместо динамических, где это возможно, поскольку в этом случае библиотеку нельзя изменить без перекомпиляции приложения и обновления используемых смещений. Однако у статических библиотек есть собственные серьезные проблемы, такие как бинарный файл большего размера и невозможность использовать новые версии библиотеки «автоматически» по мере их появления.

Архитектура

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

Метод распространения

Вся проблема рушится, если доступен исходный код библиотек. Тогда простая перекомпиляция сделает свое дело.

Смотрите также

внешняя ссылка