Выравнивание буфера приема Netlink

Статический анализатор PVS-Studio сообщает, что в nh = (struct nlmsghdr *) buf,

Указатель 'buf' преобразуется в более строго выровненный тип указателя.

Я думаю, что предупреждение правильное. Это серьезная проблема? Код должен быть переносимым на различные архитектуры. Как я могу это исправить?

Я знаю несколько способов:

  • выделить буфер в куче;
  • использовать функции stdalign, но они не C99,
  • cmsghdr API использует объединение для обработки выравнивания, но я не уверен, что netlink это делает.

Есть ли другой вариант?

Приведенный ниже код взят с справочной страницы netlink.

int len;
char buf[8192];     /* 8192 to avoid message truncation on
                       platforms with page size > 4096 */
struct iovec iov = { buf, sizeof(buf) };
struct sockaddr_nl sa;
struct msghdr msg;
struct nlmsghdr *nh;

msg = { &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
len = recvmsg(fd, &msg, 0);

for (nh = (struct nlmsghdr *) buf; NLMSG_OK (nh, len);
     nh = NLMSG_NEXT (nh, len)) {
     /* The end of multipart message */
     if (nh->nlmsg_type == NLMSG_DONE)
     return;

     if (nh->nlmsg_type == NLMSG_ERROR)
     /* Do some error handling */
     ...

     /* Continue with parsing payload */
     ...
}

Спасибо.


person Antonin Décimo    schedule 01.09.2019    source источник
comment
Код вызывает неопределенное поведение, поскольку он нарушает как строгое использование псевдонимов, так и 6.3.2.3 Указатели, параграф 7 : Указатель на тип объекта может быть преобразован в указатель на другой тип объекта. Если результирующий указатель неправильно выровнен для типа, на который указывает ссылка, поведение не определено. Невозможно безопасно назвать фактический массив char чем-то другим. Просто погуглите SIGBUS arm или SIGBUS sparc.   -  person Andrew Henle    schedule 01.09.2019
comment
Спасибо что подметил это. Следует ли сообщить об этом проекту netlink?   -  person Antonin Décimo    schedule 01.09.2019


Ответы (1)


Не лучше ли взять указатель на выделенный struct nlmsghdr вместо char buf[8192]?

Например:

int len;
struct nlmsghdr buf;
struct iovec iov = { &buf, sizeof(buf) };
struct sockaddr_nl sa;
struct msghdr msg;
struct nlmsghdr *nh;

msg = { &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
len = recvmsg(fd, &msg, 0);

for (nh = &buf; NLMSG_OK (nh, len);
    nh = NLMSG_NEXT (nh, len)) {
    /* The end of multipart message */
    if (nh->nlmsg_type == NLMSG_DONE)
    return;

    if (nh->nlmsg_type == NLMSG_ERROR)
    /* Do some error handling */
    ...

    /* Continue with parsing payload */
    ...
}
person Memos Electron    schedule 01.09.2019
comment
sizeof(buf) дает размер указателя, а не массива. Не в размещенном коде, поскольку доступно полное определение массива. - person Andrew Henle; 01.09.2019
comment
Я не уверен, но я думаю, что в этом примере будет получена только одна структура nlmsghdr, тогда как с буфером char можно добавлять несколько сообщений. - person Antonin Décimo; 01.09.2019
comment
Это не единственное, что может быть неправильным. Также длина сообщения в NLMSG_OK (nh, len), например, я думаю, вам нужно nh->nlmsg_len вместо этого. У меня сейчас нет ничего готового для тестирования. Хотя, если это только для 1 сообщения, просто выделите массив struct nlmsghdr, например struct nlmsghdr buf[256] - person Memos Electron; 01.09.2019
comment
Нет, прототип int NLMSG_OK(struct nlmsghdr *nlh, int len);. Я использую struct nlmsghdr buf[8192/sizeof(struct nlmsghdr)];, а sizeof(buf) возвращает размер buf в байтах, как и ожидалось. - person Antonin Décimo; 01.09.2019
comment
Патч с использованием моего решения был принят; см. ae10667. - person Antonin Décimo; 07.01.2020