Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top

Вебинар: SAST как Quality Gate - 13.03

>
>
>
V2629. MISRA. Pointer arguments to the …
menu mobile close menu
Проверка проектов
Сообщения PVS-Studio
Диагностики общего назначения (General Analysis, C++)
Диагностики общего назначения (General Analysis, C#)
Диагностики общего назначения (General Analysis, Java)
Микрооптимизации (C++)
Диагностика 64-битных ошибок (Viva64, C++)
Реализовано по запросам пользователей (C++)
Cтандарт MISRA
Стандарт AUTOSAR
Стандарт OWASP (C++)
Стандарт OWASP (C#)
Стандарт OWASP (Java)
Проблемы при работе анализатора кода
Дополнительная информация
toggle menu Оглавление

V2629. MISRA. Pointer arguments to the 'memcmp' function should point to an appropriate type.

07 Фев 2025

Данное диагностическое правило основано на руководстве MISRA (Motor Industry Software Reliability Association) по разработке программного обеспечения.

Это правило актуально только для C.

Использование функции memcmp из стандартной библиотеки может приводить к неожиданным результатам при использовании с определёнными типами данных.

Функция производит побайтовое сравнение первых n байт двух объектов, переданных через указатели. Однако есть случаи, когда не следует использовать memcmp для побайтового сравнения.

Случай N1. Структуры или объединения. Из-за байтов выравнивания при логически равных объектах можно получить различный результат.

Пример:

struct S 
{
  int  a;
  char b;
};

bool equals(struct S *s1, struct S *s2)
{
  return memcmp(s1, s2, sizeof(struct S)) == 0;
}

Для дальнейшего понимания примем, что размер и выравнивание типа int равно 4, а для char1. Вследствие того, что процессор должен эффективно работать с данными в памяти, структура S будет располагаться в памяти следующим образом:

class S size(8):
     +---
 0   | a
 4   | b
     | <alignment member> (size=3)
     +---

Первое поле расположено по смещению 0x0 и занимает 4 байта. Следующее поле расположено по смещению 0x4 и занимает 1 байт. Помимо этого, начиная со смещения 0x5 в объекты класса добавляются 3 байта для того, чтобы выровнить объекты класса по максимальному выравниванию в 4 байта.

Стандарт языка C не гарантирует, как именно будут инициализированы байты выравнивания. Из-за этого сравнение двух объектов через функцию memcmp может произойти неверно.

Корректным способом сравнения двух объектов будет попарное сравнение всех полей класса:

struct S 
{
  int  a;
  char b;
};

bool equals(struct S *s1, struct S *s2)
{
  return s1->a == s2->a && s1->b == s2->b;
}

Случай N2. Вещественные числа. Рассмотрим пример:

bool equals(double *lhs, double *rhs, size_t length)
{
  return memcmp(lhs, rhs, length * sizeof(double)) == 0;
}

Функция производит сравнение двух массивов вещественных чисел размера length. Из-за особенностей формата представления вещественных чисел одинаковые значения могут иметь различные байтовые представления. Из-за этого memcmp вернёт не тот результат, что ожидает разработчик.

Более корректный способ сравнения выглядит следующим образом:

bool equals_d(double lhs, double rhs, double eps = DBL_EPSILON);

bool equals(double *lhs, double *rhs, size_t length)
{
  for (size_t i = 0; i < length; ++i)
  {
    if (!equals_d(lhs[i], rhs[i])) return false;
  }

  return true;
}

Функция сравнения двух вещественных чисел подбирается исходя из условий сравнения. Например, она может быть такой:

bool equals_d(double lhs, double rhs, double eps)
{
  double diff = fabs(lhs - rhs);
  lhs = fabs(lhs);
  rhs = fabs(rhs);

  double largest = (rhs > lhs) ? rhs : lhs;

  return diff <= largest * eps;
}

Случай N3. Символьные массивы. Рассмотрим пример:

bool equals(const char *lhs, const char *rhs, size_t length)
{
  return memcmp(lhs, rhs, length) == 0;
}

При применении memcmp при сравнении символьных массивов терминальный ноль может быть интерпретирован как данные, а не как сигнал об остановке алгоритма. Из-за этого может произойти либо неверное сравнение, либо выход за границу массива, что ведёт к неопределённому поведению.

Корректный способ сравнения символьных массивов:

bool equals(const char *lhs, const char *rhs, size_t length)
{
  return strncmp(lhs, rhs, length) == 0;
}

Данная диагностика классифицируется как:

  • MISRA-C-21.16
close form

Заполните форму в два простых шага ниже:

Ваши контактные данные:

Шаг 1
Поздравляем! У вас есть промокод!

Тип желаемой лицензии:

Шаг 2
Team license
Enterprise license
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности
close form
Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Бесплатная лицензия PVS‑Studio для специалистов Microsoft MVP
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Я хочу принять участие в тестировании
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
check circle
Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте, отфильтровано ли письмо в одну из следующих стандартных папок:

  • Промоакции
  • Оповещения
  • Спам