Найти дыры в структурах C из-за выравнивания

Есть ли способ в gcc или clang (или любом другом компиляторе) выплевывать информацию о том, есть ли в структуре дыры (выравнивание памяти) в ней?

Спасибо.

PS: Если есть другой способ сделать это, пожалуйста, сообщите мне.


person John    schedule 06.10.2011    source источник
comment
Существуют известные методы написания структур, поэтому вы можете быть практически уверены, что они не содержат отступов. Если это поможет, дайте мне знать, и я расскажу вам подробности.   -  person Lindydancer    schedule 06.10.2011


Ответы (7)


Вы можете использовать pahole для вывода информации о дырах в структурах и при необходимости попытаться их запаковать.

Вы можете прочитать "Poke-a-hole and friends" и объявление pahole для получения дополнительной информации

person Hasturkun    schedule 06.10.2011
comment
Спасибо. Думаю, это то, что я искал. - person John; 06.10.2011

Я не знаю никакого автоматического инструмента, но это может быть полезным примером:

#include <stddef.h>

struct test {
  typea a;
  typeb b;
  typec c;
};

int gapB = offsetof(struct test, b) - (offsetof(struct test, a) + sizeof(typea));
int gapC = offsetof(struct test, c) - (offsetof(struct test, b) + sizeof(typeb));

printf("Gap of b:%d/n", gapB);
printf("Gap of c:%d/n", gapC);

*Примечание: вам придется сделать это для каждых двух участников в вашем застревании.

person Roee Gavirel    schedule 06.10.2011

Это можно сделать с помощью FlexeLint/PClint от Gimpel.

$ cat tst.c
int main (void)
{
    struct {
        char c;
        double d;
        short s;
    } f = { 1, 2.0, 3 };

    return f.c;
}

Он сообщит

$ flexelint -w1 +e95? tst.c
FlexeLint for C/C++ (Unix) Vers. 9.00L, Copyright Gimpel Software 1985-2014

--- Module:   tst.c (C)
                _
        double d;
tst.c  5  Note 958: Padding of 7 byte(s) is required to align member on 8 byte
    boundary
    _
    } f = { 1, 2.0, 3 };
tst.c  7  Note 959: Nominal struct size (18 bytes) is not an even multiple of
    the maximum member alignment (8 bytes)
tst.c  7  Note 958: Padding of 6 byte(s) is required to align end of struct on
    8 byte boundary
person Jens    schedule 18.06.2015

Вы можете изучить этот вопрос, написав тестовый код для конкретного struct, используя sizeof и &; если sizeof n-й член не равен адресу следующего члена минус адрес этого члена, есть дыра.

person Ernest Friedman-Hill    schedule 06.10.2011

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

person Alexey Frunze    schedule 06.10.2011
comment
Так что я думаю, что нет переключателя компилятора :). Тем не менее, это интересная (по крайней мере для меня) тема. С чего бы мне начать, если бы я хотел анализировать объектные файлы? - person John; 06.10.2011
comment
@John: сначала посмотрите, есть ли какие-либо инструменты, которые могут считывать информацию о символах / отладке и выводить ее в удобочитаемой форме. Если нет, посмотрите, какие инструменты, для которых у вас есть исходный код, используют эти данные и разрабатывают на их основе свои собственные. И, как обычно, смотрите документацию по форматам файлов. - person Alexey Frunze; 06.10.2011
comment
это то, что делают pahole и другие - person underscore_d; 12.03.2016

Вы можете обнаружить такие «дыры» с помощью макроса offsetof:

#include <stddef.h>

struct test {
  char a;
  int b;
};
...
printf("%zu", offsetof(struct test, b));

Если это напечатает больше, чем 1, b очевидно требует выравнивания, и компилятор создает промежуток между ними.

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

Я не думаю, что какой-либо компилятор предоставляет возможность уведомить вас об этом.

person Blagovest Buyukliev    schedule 06.10.2011
comment
Есть ли способ автоматизировать это? - person John; 06.10.2011
comment
Изучение структур может быть недостаточным, есть опции выравнивания либо в коде, либо даже в CFLAGS. О каком количестве строк кода вы говорите? Возможно ли, что структуры используются для хранения данных в файлах? - person ott--; 06.10.2011
comment
Мой вопрос в основном академического характера, но я хотел бы протестировать пару миллионов LOC. Структуры в основном представляют собой объекты CAD/CAE. - person John; 06.10.2011

Вам нужен синтаксический анализатор, который понимает структуры c/c++ и включает в себя необходимые включаемые файлы.

Как ответил @roee-gavirel, я думаю, что более простым решением является создание тестовой программы для распечатки смещений.

#include <stdio.h>
#include <stddef.h>

typedef struct tData {
  long   id;       /* 8 bytes */
  char   name[8];  /* 8 bytes */
  float  salary;   /* 4 bytes */
} tData;

tData d;

int main()
{
  size_t s_tData  = sizeof(tData);
  size_t s_id     = sizeof(d.id);
  size_t s_name   = sizeof(d.name);
  size_t s_salary = sizeof(d.salary);

  printf("sizeof(tData) = %zu\n\n", sizeof(d));

  printf("'id'     is at = %3zu  occupies %zu bytes\n",
         offsetof(tData, id), s_id);
  printf("'name'   is at = %3zu  occupies %zu bytes\n",
         offsetof(tData, name), s_name);
  printf("'salary' is at = %3zu  occupies %zu bytes\n",
         offsetof(tData, salary), s_salary);

  printf("\n");

  if (s_tData != s_id + s_name + s_salary)
    printf("There is/are holes\n");

  return 0;
}
person yoonghm    schedule 10.03.2018