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