ПроблемаОперации bytewise с объектом нетривиального класса выполняются при использовании функций библиотеки C Standard для выполнения операций bytewise с объектами нетривиального или нестандартного типа класса макета. Определения тривиальных классов и классов типовой формы стандартов см. соответственно в пунктах 6 и 7 [класса] стандарта C++.
Средство проверки вызывает дефект, инициализируемый или копируемый объектами нетривиального типа класса с помощью следующих функций:
std::memset
std::memcpy
std::strcpy
std::memmove
Или при сравнении нестандартных объектов типа класса форматов с использованием следующих функций:
Операции bytewise над объектом нетривиального класса не вызывают дефектов, если операция bytewise выполняется через псевдоним. Например, при сравнении по байтам и операциях копирования в этом коде дефект не возникает. Использование побитовых операций 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!=()
|
Пример - использование memset с объектом нетривиального класса#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;
}