ПроблемаЭта проблема возникает, когда вы используете уже принадлежащий вам указатель в качестве аргумента:
Конструктор умных указателей. Например, в этом фрагменте кода, raw_ptr
уже принадлежит s_ptr1
и используется для инициализации s_ptr2
:
char *raw_ptr = new char;
std::shared_ptr<char> s_ptr1(raw_ptr);
std::shared_ptr<char> s_ptr2(raw_ptr); //raw_ptr is already owned by s_ptr1
Операция сброса смарт-указателя. Например, в этом фрагменте кода сброс s_ptr2
заменяет raw_ptr2
с уже принадлежащими raw_ptr1
:
char *raw_ptr1 = new char;
char *raw_ptr2 = new char;
std::shared_ptr<char> s_ptr1(raw_ptr1);
std::shared_ptr<char> s_ptr2(raw_ptr2);
s_ptr2.reset(raw_ptr1); // s_ptr2 releases raw_ptr2 and owns already owned raw_ptr1
Polyspace® проверяет только типы смарт-указателей std::shared_ptr
и std::unique_ptr
и считает, что определяемые пользователем распределители и разделители имеют стандартное поведение выделения и удаления.
Указатель уже принадлежит смарт-указателю, если тип указателя не std::nullptr_t
и либо:
Указатель использовался для инициализации смарт-указателя.
Указатель использовался как аргумент для смарт-указателя reset()
функции представителя.
Указатель является возвратом значением интеллектуального указателя get()
функции представителя.
Указатель является возвратом значением интеллектуального указателя operator->
функции представителя.
РискВы используете смарт-указатели, чтобы убедиться, что память, на которую указывает указатель, автоматически отменяется при уничтожении указателя, например, если указатель выходит из возможностей. Когда несвязанные смарт-указатели управляют тем же значением указателя, один из смарт-указателей может попытаться удалить память, которая уже была отключена другим смарт-указателем. Это приводит к двойной свободной уязвимости, которая повреждает структуру данных управления памятью вашей программы.
ЗафиксироватьИспользование std::make_shared
чтобы создать смарт-указатель, а затем использовать конструкцию копирования для создания связанного смарт-указателя. Базовым значением указателя управляют оба смарт-указателя, и указанная память не освобождается до тех пор, пока не будут уничтожены все смарт-указатели.
Если вы не намерены позволять нескольким смарт-указателям управлять одним и тем же значением указателя, используйте std::make_unique
чтобы создать std::unique_ptr
умный указатель. A std::unique_ptr
можно перемещать только, что отменяет владение базовым значением управляемого указателя.
Пример - Использование уже принадлежащего указателя
#include <memory>
#include <string>
struct Profile
{
virtual ~Profile()=default;
};
struct Player : public Profile
{
std::string name;
std::int8_t rank;
Player();
Player(const std::string& name_, const std::int8_t& rank_) :
name{ name_ }, rank{ rank_ } {}
};
void func(){
Player * player = new Player("Richard Roll",1);
std::shared_ptr<Player> player1(player);
std::shared_ptr<Player> top_rank(player); //Non-compliant
}
В этом примере использование значения указателя player
для создания смарт-указателя top_rank
в функциональных func
не соответствует требованиям. player
уже принадлежит смарт-указателю player1
. Когда player1
уничтожен, может попытаться удалить значение указателя player
который уже был удален top_rank
.
Коррекция - Использование std::make_shared
и скопируйте конструкцию, чтобы создать связанные интеллектуальные указатели
#include <memory>
#include <string>
struct Profile
{
virtual ~Profile()=default;
};
struct Player : public Profile
{
std::string name;
std::int8_t rank;
Player();
Player(const std::string& name_, const std::int8_t& rank_) :
name{ name_ }, rank{ rank_ } {}
};
void func2(){
std::shared_ptr<Player> player1_shared =
std::make_shared<Player>("Richard Roll",1);
std::shared_ptr<Player> top_rank_shared(player1_shared); //Compliant
}
Одной из возможных коррекций является использование std::make_shared
объявить player1_shared
, а затем используйте конструкцию копирования для создания связанного интеллектуального указателя top_rank_shared
. Базовое значение указателя не удаляется, пока не будут уничтожены все смарт-указатели.