Может ли изменение sizeof (bool) действительно сломать старый код? - PullRequest
0 голосов
/ 06 февраля 2019

У меня есть библиотека C, которая использует что-то вроде этого:

struct Foo {
  const char *bar;
  bool important;
  struct Baz *baz;
}

Недавно я использовал ее в проекте, где important должен был быть false, однако он оценивался как true.Глядя на структуру памяти (дамп) структуры, я заметил (с самого начала):

  • 8 ненулевых байтов
  • 1 нулевой байт
  • 7 ненулевыхбайты
  • ...

Поскольку моя архитектура x86_64, я предполагаю, что:

  • первые 8 байтов были bar членом
  • затем был элемент important, который, как ожидалось, должен был иметь ширину 1B с помощью кода, который его установил (отсюда 1 нулевой байт), но в то же время он должен был иметь ширину 4B (sizeof int) по коду, который проверил его истинность (отсюда его оценку как true)
  • , затем было заполнение до 8B

Если это актуально, моя платформа - CentOS7 с дистрибутивной версией GCC (4.8.5 RedHat).


Мой вопрос - может ли это действительно произойти?Может ли ничего не подозревающий программист столкнуться с поломкой ABI из-за изменения sizeof (bool)?Дополнительные советы:

  • как это проверить (MWE)
  • какая версия стандарта GCC / glibc / C приносит это изменение
  • как этого избежать

Добро пожаловать.

1 Ответ

0 голосов
/ 06 февраля 2019

Может ли изменение sizeof (bool) действительно сломать старый код?

Да.Довольно просто найти код, который предполагает неправильно что-то о размере bool и (отсутствии) заполнения.

... был элемент important, которыйОжидалось, что он будет иметь ширину 1B с помощью кода, который его установил (отсюда 1 нулевой байт), но в то же время ожидается, что он будет иметь ширину 4B (sizeof int)

Даже есликод был до C99, размер определяемого кодом типа bool должен был быть sizeof(bool) или лучше как struct Foo f; sizeof(f.important), а не sizeof int.

Далее, хотя код не показывает, как этиРазмеры были применены, другая проблема - отступы.Макеты могли бы быть

8 byte pointer,  1 byte bool, 7 padding
8 byte pointer,  4 byte bool, 0 padding
8 byte pointer,  4 byte bool, 4 padding
4 byte pointer,  1 byte bool, 3 padding
2 byte pointer,  4 byte bool, 0 padding
etc.

. Для лучшего кода использовалось бы offsetof(), чтобы найти смещение, и sizeof(object.member), чтобы найти размер.

...