[*] Hardening in the form of the prevention of future bad rewrites of similar code

[+] MemoryView::AtOffset
[+] MemoryView::Take
This commit is contained in:
Reece Wilson 2024-03-10 09:46:53 +00:00
parent 951f9b73f3
commit 9c4315ff95
2 changed files with 126 additions and 64 deletions

View File

@ -648,28 +648,13 @@ namespace Aurora::Memory
inline AuSPtr<MemoryViewWrite> ToSharedWriteView()
{
MemoryViewWrite view = *this;
struct View : MemoryViewWrite
{
View(MemoryViewWrite &&in) : MemoryViewWrite(in)
{ }
~View()
{
this->ResetControlBlock();
AuResetMember(this->pin);
}
AuSPtr<void> pin;
};
if (!view)
{
return {};
}
if (auto pView = AuMakeShared<View>(AuMove(view)))
if (auto pView = AuMakeShared<MemoryViewWrite>(view.ptr, view.length, &this->uInUseCounter, AuSharedFromThis()))
{
pView->pin = AuSharedFromThis();
return pView;
}
else
@ -681,28 +666,13 @@ namespace Aurora::Memory
inline AuSPtr<MemoryViewRead> ToSharedReadView()
{
MemoryViewRead view = *this;
struct View : MemoryViewRead
{
View(MemoryViewRead &&in) : MemoryViewRead(in)
{ }
~View()
{
this->ResetControlBlock();
AuResetMember(this->pin);
}
AuSPtr<void> pin;
};
if (!view)
{
return {};
}
if (auto pView = AuMakeShared<View>(AuMove(view)))
if (auto pView = AuMakeShared<MemoryViewRead>(view.ptr, view.length, &this->uInUseCounter, AuSharedFromThis()))
{
pView->pin = AuSharedFromThis();
return pView;
}
else

View File

@ -11,7 +11,21 @@ namespace Aurora::Memory
{
struct MemoryControlBlock
{
// Free-after-use mitigator: ensures a non-zero flag is kept whilst other memory views are present
// This helps mitigate:
// -> Take view from object
// -> Make view shared
// -> Pass off shared view to another subsystem
// -> Use the aforementioned object to resize, release, or do something bad with the memory pointed to by the initial view
// Mitgation: SysAssert(!pObject->uInUse)
AuAUInt32 *pInUseCounter {};
// Mitigation (cont) and reducing code reuse:
// -> Allow for [shared!] memory views to have a shared freestanding owner
// -> Ensure reference counters or other forms of memory management don't free the owner before us
// (Consider inverse construction order, for instance, we'd have to always call MemoryView::ResetControlBlock()
// in a derived subclass, in order release the pInUseCounter reference before the derived shared members get released)
AuSPtr<void> pPinner; // WARNING: as usual, std types don't validate their allocator, and our shared ptrs can be different between binaries!
};
template<bool Readonly_b>
@ -62,6 +76,7 @@ namespace Aurora::Memory
{
AuAtomicAdd(this->controlBlock.pInUseCounter, 1u);
}
this->controlBlock.pPinner = view.controlBlock.pPinner;
}
MemoryView(MemoryView &&view)
@ -69,38 +84,10 @@ namespace Aurora::Memory
this->ptr = view.ptr;
this->length = view.length;
this->controlBlock.pInUseCounter = view.controlBlock.pInUseCounter;
this->controlBlock.pPinner = AuMove(view.controlBlock.pPinner);
view.controlBlock.pInUseCounter = nullptr;
}
~MemoryView()
{
if (controlBlock.pInUseCounter)
{
AuAtomicSub(controlBlock.pInUseCounter, 1u);
}
}
MemoryView &operator =(MemoryView &&view)
{
this->ptr = view.ptr;
this->length = view.length;
this->controlBlock.pInUseCounter = view.controlBlock.pInUseCounter;
view.controlBlock.pInUseCounter = nullptr;
return *this;
}
MemoryView &operator =(const MemoryView &view)
{
this->ptr = view.ptr;
this->length = view.length;
this->controlBlock.pInUseCounter = view.controlBlock.pInUseCounter;
if (this->controlBlock.pInUseCounter)
{
AuAtomicAdd(this->controlBlock.pInUseCounter, 1u);
}
return *this;
}
template<typename T, int Z>
constexpr MemoryView(T(&a)[Z])
{
@ -139,6 +126,24 @@ namespace Aurora::Memory
AuAtomicAdd(pInUseCounter, 1u);
}
template<typename T>
constexpr MemoryView(T *start, T *end, AuAUInt32 *pInUseCounter, const AuSPtr<void> &pRAIIOwner)
{
this->ptr = start;
if constexpr (AuIsSame_v<T, Void_t>)
{
this->length = reinterpret_cast<const AuUInt8 *>(end) - reinterpret_cast<const AuUInt8 *>(start);
}
else
{
this->length = (end - start) * sizeof(T);
}
this->controlBlock.pInUseCounter = pInUseCounter;
AuAtomicAdd(pInUseCounter, 1u);
this->controlBlock.pPinner = pRAIIOwner;
}
template<typename T>
constexpr MemoryView(T *start, AuUInt length) // WARNING: length != count
// where T = whogivesafuck
@ -156,6 +161,58 @@ namespace Aurora::Memory
AuAtomicAdd(pInUseCounter, 1u);
}
template<typename T>
constexpr MemoryView(T *start, AuUInt length, AuAUInt32 *pInUseCounter, const AuSPtr<void> &pRAIIOwner) // WARNING: length != count
{
this->ptr = start;
this->length = length;
this->controlBlock.pInUseCounter = pInUseCounter;
AuAtomicAdd(pInUseCounter, 1u);
this->controlBlock.pPinner = pRAIIOwner;
}
~MemoryView()
{
this->ResetControlBlock();
}
private:
template<typename T>
MemoryView(T *start, AuUInt length, const MemoryControlBlock &copyBlock)
{
this->ptr = start;
this->length = length;
this->controlBlock = copyBlock;
if (this->controlBlock.pInUseCounter)
{
AuAtomicAdd(this->controlBlock.pInUseCounter, 1u);
}
}
public:
MemoryView &operator =(MemoryView &&view)
{
this->ptr = view.ptr;
this->length = view.length;
this->controlBlock.pInUseCounter = view.controlBlock.pInUseCounter;
view.controlBlock.pInUseCounter = nullptr;
this->controlBlock.pPinner = AuMove(view.controlBlock.pPinner);
return *this;
}
MemoryView &operator =(const MemoryView &view)
{
this->ptr = view.ptr;
this->length = view.length;
this->controlBlock.pInUseCounter = view.controlBlock.pInUseCounter;
if (this->controlBlock.pInUseCounter)
{
AuAtomicAdd(this->controlBlock.pInUseCounter, 1u);
}
this->controlBlock.pPinner = view.controlBlock.pPinner;
return *this;
}
AuUInt ToPointerValue() const
{
return reinterpret_cast<const AuUInt>(this->ptr);
@ -191,7 +248,7 @@ namespace Aurora::Memory
operator bool() const
{
return HasMemory();
return this->HasMemory();
}
U8_t ToPointer() const
@ -219,8 +276,41 @@ namespace Aurora::Memory
return reinterpret_cast<U8_t>(this->ptr) + this->length;
}
MemoryView AtOffset(AuUInt uOffset)
{
if (uOffset < this->uLength)
{
return MemoryView(this->pBase + uOffset, this->uLength - uOffset, this->controlBlock);
}
else
{
return {};
}
}
MemoryView Take(AuUInt uLength)
{
if (uLength <= this->uLength)
{
return MemoryView(this->pBase, uLength, this->controlBlock);
}
else
{
return {};
}
}
union
{
Void_t /*const*/ ptr;
Void_t /*const*/ pBase;
};
union
{
AuUInt /*const*/ length;
AuUInt /*const*/ uLength;
};
private:
MemoryControlBlock controlBlock;
@ -231,6 +321,8 @@ namespace Aurora::Memory
{
AuAtomicSub(pCounter, 1u);
}
AuResetMember(this->controlBlock.pPinner);
}
};