ПроблемаЭта проблема возникает при использовании уже принадлежащего указателя в качестве аргумента:
Конструктор смарт-указателей. Например, в этом фрагменте кода 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. Нижележащее значение указателя не удаляется, пока не будут уничтожены все смарт-указатели.