CERT.DCL.SAME_SCOPE_ALLOC_DEALLOC
同一のスコープでペアとして割り当て関数と割り当て解除関数をオーバーロードしてください。
同一のスコープでペアとして割り当て関数と割り当て解除関数をオーバーロードしてください。
脆弱性とリスク
対応する動的なストレージ関数のオーバーロードに失敗すると、MEM51-CPP などの規則に違反する可能性があります。動的に割り当てられたリソースは、適切に割り当てを解除してください。たとえば、オーバーロードされた割り当て関数がプライベートヒープを使用してその割り当てを実行する場合、返されたポインターをデフォルトの割り当て解除関数に渡すと、定義されていない動作が発生する可能性があります。割り当て関数が最終的にデフォルトのアロケータを使用してメモリへのポインターを取得する状況でも、対応する割り当て解除関数のオーバーロードが失敗すると、カスタムアロケータの内部データが更新されなくなり、プログラムが予期しない状態になる可能性があります。
軽減と防止
割り当て関数を特定のスコープでオーバーロードする場合、対応する割り当て解除関数も同じスコープでオーバーロードする必要があります (この逆も同様)。
例
コピー
#include <Windows.h>
#include <new>
extern "C++" void update_bookkeeping(void *allocated_ptr, std::size_t size, bool alloc);
void *operator new(std::size_t size) noexcept(false) { // uncompliant code, it only overloads 'new' in std namespace, not 'delete'.
static HANDLE h = ::HeapCreate(0, 0, 0); // Private, expandable heap.
if (h) {
return ::HeapAlloc(h, 0, size);
}
throw std::bad_alloc();
}
struct S_positive {
void *operator new(std::size_t size) noexcept(false) {
void *ptr = ::operator new(size);
update_bookkeeping(ptr, size, true); // uncompliant code
return ptr;
}
};
struct S_negative { // compliant code
void *operator new(std::size_t size) noexcept(false) {
void *ptr = ::operator new(size);
update_bookkeeping(ptr, size, true);
return ptr;
}
void operator delete(void *ptr, std::size_t size) noexcept {
::operator delete(ptr);
update_bookkeeping(ptr, size, false);
}
};
6 行目と 15 行目の割り当てメソッドと同じスコープ内には、オーバーロードされた対応する割り当て解除メソッドが存在しません。38 行目のオーバーロードされた割り当てメソッドは適合していると言えます。対応する割り当て解除メソッドが 29 行目でオーバーロードされているためです。