exponenta event banner

Побитовые операции над объектом нетривиального класса

Представления значений могут быть неправильно инициализированы или сравнены

Описание

Этот дефект возникает при использовании функций библиотеки C Standard для выполнения байтовой операции с нетривиальными или нестандартными объектами типа класса компоновки. Определения тривиальных классов и классов типовой формы стандартов см. соответственно в пунктах 6 и 7 [класса] стандарта C++.

Средство проверки вызывает дефект при инициализации или копировании объектов нетривиального типа класса с помощью следующих функций:

  • std::memset

  • std::memcpy

  • std::strcpy

  • std::memmove

Или при сравнении нестандартных объектов типа класса форматов с использованием следующих функций:

  • std::memcmp

  • std::strcmp

Средство проверки не вызывает дефектов, если байтовая операция выполняется через псевдоним. Например, при сравнении по байтам и операциях копирования в этом коде дефект не возникает. Использование побитовых операций dptr и sptr, псевдонимы нетривиальных или нестандартных объектов класса макета d и s.

void func(NonTrivialNonStdLayout *d, const NonTrivialNonStdLayout *s)
{
   void* dptr = (void*)d; 
   const void* sptr = (void*)s;
   // ...
   // ...
   // ...
   if (!std::memcmp(dptr, sptr, sizeof(NonTrivialNonStdLayout))) {  
     (void)std::memcpy(dptr, sptr, sizeof(NonTrivialNonStdLayout)); 
      // ...
   }
}

Риск

Выполнение операций сравнения по байтам с использованием функций библиотеки C Standard для нетривиальных или нестандартных объектов типа класса макета может привести к непредвиденным значениям из-за подробностей реализации. Представление объекта зависит от деталей реализации, таких как порядок частных и открытых членов или использование таблиц указателей виртуальных функций для представления объекта.

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

Зафиксировать

Для выполнения байтовых операций нетривиальных или нестандартных объектов типа класса макета используйте эти специальные функции-члены C++ вместо функций библиотеки C Standard.

Стандартные библиотечные функции CФункции-члены C++

std::memset

Конструктор класса

std::memcpy

std::strcpy

std::memmove

Конструктор копирования класса

Конструктор перемещения класса

Копировать оператор назначения

Оператор назначения перемещения

std::memcmp

std::strcmp

operator<()

operator>()

operator==()

operator!=()

Примеры

развернуть все

#include <cstring>
#include <iostream>
#include <utility>

class nonTrivialClass
{
    int scalingFactor;
    int otherData;
public:
    nonTrivialClass() : scalingFactor(1) {}
    void set_other_data(int i);
    int f(int i)
    {
        return i / scalingFactor;
    }
    // ...
};

void func()
{
    nonTrivialClass c;
    // ... Code that mutates c ...
    std::memset(&c, 0, sizeof(nonTrivialClass));
    std::cout << c.f(100) << std::endl;
}

В этом примере: func() использование std::memset для повторной инициализации объекта нетривиального класса c после первой инициализации с помощью конструктора по умолчанию. Эта байтовая операция может неправильно инициализировать представление значения c.

Коррекция - определение шаблона функции, который использует std::swap

Одной из возможных корректировок является определение шаблона функции. clear() который использует std::swap для выполнения операции подкачки. Вызов clear()правильно повторно инициализирует объект c путем замены содержимого c и инициализированный объект по умолчанию empty.

 #include <cstring>
#include <iostream>
#include <utility>

class nonTrivialClass
{
    int scalingFactor;
    int otherData;
public:
    nonTrivialClass() : scalingFactor(1) {}
    void set_other_data(int i);
    int f(int i)
    {
        return i / scalingFactor;
    }
    // ...
};

template <typename T>
T& clear(T& o)
{
    using std::swap;
    T empty;
    swap(o, empty);
    return o;
}

void func()
{
    nonTrivialClass c;
    // ... Code that mutates c ...

    clear(c);
    std::cout << c.f(100) << std::endl;
}

Информация о результатах

Группа: Объектно-ориентированная
Язык: C++
По умолчанию: Откл.
Синтаксис командной строки: MEMOP_ON_NONTRIVIAL_OBJ
Воздействие: среднее
Представлен в R2019b