Squirrel: Change SQRefCounted allocator to avoid undefined behaviour

pull/451/head
Jonathan G Rennison 2 years ago
parent 449ed7aa51
commit 2b5456a664

@ -57,13 +57,12 @@ HSQUIRRELVM sq_open(SQInteger initialstacksize)
SQSharedState *ss;
SQVM *v;
sq_new(ss, SQSharedState);
v = (SQVM *)SQ_MALLOC(sizeof(SQVM));
new (v) SQVM(ss);
v = new (SQAllocationTag{}) SQVM(ss);
ss->_root_vm = v;
if(v->Init(nullptr, initialstacksize)) {
return v;
} else {
sq_delete(v, SQVM);
sq_delete_refcounted(v, SQVM);
return nullptr;
}
return v;
@ -75,14 +74,13 @@ HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize)
SQVM *v;
ss=_ss(friendvm);
v= (SQVM *)SQ_MALLOC(sizeof(SQVM));
new (v) SQVM(ss);
v = new (SQAllocationTag{}) SQVM(ss);
if(v->Init(friendvm, initialstacksize)) {
friendvm->Push(v);
return v;
} else {
sq_delete(v, SQVM);
sq_delete_refcounted(v, SQVM);
return nullptr;
}
}

@ -12,8 +12,7 @@ private:
}
public:
static SQArray* Create(SQSharedState *ss,SQInteger nInitialSize){
SQArray *newarray=(SQArray*)SQ_MALLOC(sizeof(SQArray));
new (newarray) SQArray(ss,nInitialSize);
SQArray *newarray = new (SQAllocationTag{}) SQArray(ss,nInitialSize);
return newarray;
}
#ifndef NO_GARBAGE_COLLECTOR
@ -84,7 +83,7 @@ public:
}
void FinalFree() override
{
sq_delete(this, SQArray);
sq_delete_refcounted(this, SQArray);
}
SQObjectPtrVec _values;
};

@ -147,9 +147,8 @@ void SQInstance::Init(SQSharedState *ss)
ADD_TO_CHAIN(&_sharedstate->_gc_chain, this);
}
SQInstance::SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize)
SQInstance::SQInstance(SQSharedState *ss, SQClass *c)
{
_memsize = memsize;
_class = c;
SQUnsignedInteger nvalues = _class->_defaultvalues.size();
for(SQUnsignedInteger n = 0; n < nvalues; n++) {
@ -158,9 +157,8 @@ SQInstance::SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize)
Init(ss);
}
SQInstance::SQInstance(SQSharedState *ss, SQInstance *i, SQInteger memsize)
SQInstance::SQInstance(SQSharedState *ss, SQInstance *i)
{
_memsize = memsize;
_class = i->_class;
SQUnsignedInteger nvalues = _class->_defaultvalues.size();
for(SQUnsignedInteger n = 0; n < nvalues; n++) {

@ -31,8 +31,7 @@ struct SQClass : public CHAINABLE_OBJ
SQClass(SQSharedState *ss,SQClass *base);
public:
static SQClass* Create(SQSharedState *ss,SQClass *base) {
SQClass *newclass = (SQClass *)SQ_MALLOC(sizeof(SQClass));
new (newclass) SQClass(ss, base);
SQClass *newclass = new (SQAllocationTag{}) SQClass(ss, base);
return newclass;
}
~SQClass();
@ -55,7 +54,7 @@ public:
void Lock() { _locked = true; if(_base) _base->Lock(); }
void Release() {
if (_hook) { _hook(_typetag,0);}
sq_delete(this, SQClass);
sq_delete_refcounted(this, SQClass);
}
void Finalize();
#ifndef NO_GARBAGE_COLLECTOR
@ -81,14 +80,13 @@ public:
struct SQInstance : public SQDelegable
{
void Init(SQSharedState *ss);
SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize);
SQInstance(SQSharedState *ss, SQInstance *c, SQInteger memsize);
SQInstance(SQSharedState *ss, SQClass *c);
SQInstance(SQSharedState *ss, SQInstance *c);
public:
static SQInstance* Create(SQSharedState *ss,SQClass *theclass) {
SQInteger size = calcinstancesize(theclass);
SQInstance *newinst = (SQInstance *)SQ_MALLOC(size);
new (newinst) SQInstance(ss, theclass,size);
SQInstance *newinst = new (SQSizedAllocationTag(size)) SQInstance(ss, theclass);
if(theclass->_udsize) {
newinst->_userpointer = ((unsigned char *)newinst) + (size - theclass->_udsize);
}
@ -97,8 +95,7 @@ public:
SQInstance *Clone(SQSharedState *ss)
{
SQInteger size = calcinstancesize(_class);
SQInstance *newinst = (SQInstance *)SQ_MALLOC(size);
new (newinst) SQInstance(ss, this,size);
SQInstance *newinst = new (SQSizedAllocationTag(size)) SQInstance(ss, this);
if(_class->_udsize) {
newinst->_userpointer = ((unsigned char *)newinst) + (size - _class->_udsize);
}
@ -143,9 +140,7 @@ public:
}
void FinalFree() override
{
SQInteger size = _memsize;
this->~SQInstance();
SQ_FREE(this, size);
sq_delete_refcounted(this, SQInstance);
}
void Finalize() override;
#ifndef NO_GARBAGE_COLLECTOR
@ -157,7 +152,6 @@ public:
SQClass *_class;
SQUserPointer _userpointer;
SQRELEASEHOOK _hook;
SQInteger _memsize;
SQObjectPtr _values[1];
};

@ -10,12 +10,11 @@ private:
SQClosure(SQSharedState *ss,SQFunctionProto *func){_function=func; INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);}
public:
static SQClosure *Create(SQSharedState *ss,SQFunctionProto *func){
SQClosure *nc=(SQClosure*)SQ_MALLOC(sizeof(SQClosure));
new (nc) SQClosure(ss,func);
SQClosure *nc = new (SQAllocationTag{}) SQClosure(ss,func);
return nc;
}
void Release(){
sq_delete(this,SQClosure);
sq_delete_refcounted(this,SQClosure);
}
SQClosure *Clone()
{
@ -48,8 +47,7 @@ private:
SQGenerator(SQSharedState *ss,SQClosure *closure){_closure=closure;_state=eRunning;_ci._generator=nullptr;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);}
public:
static SQGenerator *Create(SQSharedState *ss,SQClosure *closure){
SQGenerator *nc=(SQGenerator*)SQ_MALLOC(sizeof(SQGenerator));
new (nc) SQGenerator(ss,closure);
SQGenerator *nc = new (SQAllocationTag{}) SQGenerator(ss,closure);
return nc;
}
~SQGenerator()
@ -61,7 +59,7 @@ public:
_stack.resize(0);
_closure=_null_;}
void Release(){
sq_delete(this,SQGenerator);
sq_delete_refcounted(this,SQGenerator);
}
bool Yield(SQVM *v);
bool Resume(SQVM *v,SQInteger target);
@ -84,8 +82,7 @@ private:
public:
static SQNativeClosure *Create(SQSharedState *ss,SQFUNCTION func)
{
SQNativeClosure *nc=(SQNativeClosure*)SQ_MALLOC(sizeof(SQNativeClosure));
new (nc) SQNativeClosure(ss,func);
SQNativeClosure *nc = new (SQAllocationTag{}) SQNativeClosure(ss,func);
return nc;
}
SQNativeClosure *Clone()
@ -103,7 +100,7 @@ public:
REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);
}
void Release(){
sq_delete(this,SQNativeClosure);
sq_delete_refcounted(this,SQNativeClosure);
}
#ifndef NO_GARBAGE_COLLECTOR
void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue);

@ -97,10 +97,9 @@ public:
SQInteger nfunctions,SQInteger noutervalues,
SQInteger nlineinfos,SQInteger nlocalvarinfos,SQInteger ndefaultparams)
{
SQFunctionProto *f;
//I compact the whole class and members in a single memory allocation
f = (SQFunctionProto *)sq_vm_malloc(_FUNC_SIZE(ninstructions,nliterals,nparameters,nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams));
new (f) SQFunctionProto(ninstructions, nliterals, nparameters, nfunctions, noutervalues, nlineinfos, nlocalvarinfos, ndefaultparams);
size_t size = _FUNC_SIZE(ninstructions,nliterals,nparameters,nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams);
SQFunctionProto *f = new (SQSizedAllocationTag(size)) SQFunctionProto(ninstructions, nliterals, nparameters, nfunctions, noutervalues, nlineinfos, nlocalvarinfos, ndefaultparams);
return f;
}
void Release(){
@ -110,9 +109,8 @@ public:
_DESTRUCT_VECTOR(SQOuterVar,_noutervalues,_outervalues);
//_DESTRUCT_VECTOR(SQLineInfo,_nlineinfos,_lineinfos); //not required are 2 integers
_DESTRUCT_VECTOR(SQLocalVarInfo,_nlocalvarinfos,_localvarinfos);
SQInteger size = _FUNC_SIZE(_ninstructions,_nliterals,_nparameters,_nfunctions,_noutervalues,_nlineinfos,_nlocalvarinfos,_ndefaultparams);
this->~SQFunctionProto();
sq_vm_free(this,size);
SQFunctionProto::SQDeallocate(this);
}
const SQChar* GetLocal(SQVM *v,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop);
SQInteger GetLine(SQInstruction *curr);

@ -90,7 +90,7 @@ SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx)
SQWeakRef *SQRefCounted::GetWeakRef(SQObjectType type)
{
if(!_weakref) {
sq_new(_weakref,SQWeakRef);
_weakref = new (SQAllocationTag{}) SQWeakRef();
_weakref->_obj._type = type;
_weakref->_obj._unVal.pRefCounted = this;
}
@ -109,7 +109,7 @@ void SQWeakRef::Release() {
if(ISREFCOUNTED(_obj._type)) {
_obj._unVal.pRefCounted->_weakref = nullptr;
}
sq_delete(this,SQWeakRef);
sq_delete_refcounted(this,SQWeakRef);
}
bool SQDelegable::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) {

@ -54,6 +54,14 @@ enum SQMetaMethod{
#define MINPOWER2 4
struct SQAllocationTag{};
struct SQSizedAllocationTag {
size_t alloc_size;
SQSizedAllocationTag(size_t alloc_size) : alloc_size(alloc_size) {}
};
struct SQRefCounted
{
SQRefCounted() { _uiRef = 0; _weakref = nullptr; }
@ -63,23 +71,44 @@ struct SQRefCounted
struct SQWeakRef *_weakref;
virtual void Release()=0;
inline void *operator new(size_t size, SQRefCounted *place) = delete;
inline void operator delete(void *ptr, SQRefCounted *place) = delete;
/* Placement new/delete to prevent memory leaks if constructor throws an exception. */
inline void *operator new(size_t size, SQRefCounted *place)
inline void *operator new(size_t size, SQAllocationTag tag)
{
size += sizeof(size_t);
size_t *ptr = (size_t *)SQ_MALLOC(size);
*ptr = size;
return ptr + 1;
}
inline static void SQDeallocate(void *ptr)
{
place->size = size;
return place;
size_t *base = static_cast<size_t *>(ptr) - 1;
SQ_FREE(base, *base);
}
inline void operator delete(void *ptr, SQRefCounted *place)
inline void operator delete(void *ptr, SQAllocationTag tag)
{
SQ_FREE(ptr, place->size);
SQDeallocate(ptr);
}
inline void *operator new(size_t size, SQSizedAllocationTag sized_tag)
{
size_t alloc_size = sized_tag.alloc_size + sizeof(size_t);
size_t *ptr = (size_t *)SQ_MALLOC(alloc_size);
*ptr = alloc_size;
return ptr + 1;
}
inline void operator delete(void *ptr, SQSizedAllocationTag sized_tag)
{
SQDeallocate(ptr);
}
/* Never used but required. */
inline void operator delete(void *ptr) { NOT_REACHED(); }
private:
size_t size;
};
struct SQWeakRef : SQRefCounted

@ -564,8 +564,7 @@ SQString *SQStringTable::Add(const SQChar *news,SQInteger len)
return s; //found
}
SQString *t=(SQString *)SQ_MALLOC(len+sizeof(SQString));
new (t) SQString(news, len);
SQString *t = new (SQSizedAllocationTag(len + sizeof(SQString))) SQString(news, len);
t->_next = _strings[h];
_strings[h] = t;
_slotused++;
@ -615,9 +614,7 @@ void SQStringTable::Remove(SQString *bs)
else
_strings[h] = s->_next;
_slotused--;
SQInteger slen = s->_len;
s->~SQString();
SQ_FREE(s,sizeof(SQString) + slen);
sq_delete_refcounted(s, SQString);
return;
}
prev = s;

@ -45,8 +45,7 @@ private:
public:
static SQTable* Create(SQSharedState *ss,SQInteger nInitialSize)
{
SQTable *newtable = (SQTable*)SQ_MALLOC(sizeof(SQTable));
new (newtable) SQTable(ss, nInitialSize);
SQTable *newtable = new (SQAllocationTag{}) SQTable(ss, nInitialSize);
newtable->_delegate = nullptr;
return newtable;
}
@ -87,7 +86,7 @@ public:
}
void FinalFree() override
{
sq_delete(this, SQTable);
sq_delete_refcounted(this, SQTable);
}
};

@ -13,8 +13,7 @@ struct SQUserData : SQDelegable
}
static SQUserData* Create(SQSharedState *ss, SQInteger size)
{
SQUserData* ud = (SQUserData*)SQ_MALLOC(sizeof(SQUserData)+(size-1));
new (ud) SQUserData(ss, size);
SQUserData *ud = new (SQSizedAllocationTag(sizeof(SQUserData)+(size-1))) SQUserData(ss, size);
return ud;
}
#ifndef NO_GARBAGE_COLLECTOR
@ -23,9 +22,7 @@ struct SQUserData : SQDelegable
#endif
void Release() {
if (_hook) _hook(_val,_size);
SQInteger tsize = _size - 1;
this->~SQUserData();
SQ_FREE(this, sizeof(SQUserData) + tsize);
sq_delete_refcounted(this, SQUserData);
}
SQInteger _size;

@ -2,14 +2,17 @@
#ifndef _SQUTILS_H_
#define _SQUTILS_H_
#include <type_traits>
void *sq_vm_malloc(SQUnsignedInteger size);
void *sq_vm_realloc(void *p,SQUnsignedInteger oldsize,SQUnsignedInteger size);
void sq_vm_free(void *p,SQUnsignedInteger size);
#define sq_new(__ptr,__type) {__ptr=(__type *)sq_vm_malloc(sizeof(__type));new (__ptr) __type;}
#define sq_delete(__ptr,__type) {__ptr->~__type();sq_vm_free(__ptr,sizeof(__type));}
#define sq_delete(__ptr,__type) {__ptr->~__type();sq_vm_free(__ptr,sizeof(__type));static_assert(!std::is_base_of<SQRefCounted,__type>());}
#define sq_delete_refcounted(__ptr,__type) {__ptr->~__type();__ptr->SQDeallocate(__ptr);}
#define SQ_MALLOC(__size) sq_vm_malloc((__size));
#define SQ_FREE(__ptr,__size) sq_vm_free((__ptr),(__size));
#define SQ_FREE(__ptr,__size) {sq_vm_free((__ptr),(__size));static_assert(!std::is_base_of<SQRefCounted,std::remove_pointer_t<decltype(__ptr)>>());}
#define SQ_REALLOC(__ptr,__oldsize,__size) sq_vm_realloc((__ptr),(__oldsize),(__size));
//sqvector mini vector class, supports objects by value

@ -122,7 +122,7 @@ public:
_callsstack = &_callstackdata[0];
_alloccallsstacksize = newsize;
}
void Release(){ sq_delete(this,SQVM); } //does nothing
void Release(){ sq_delete_refcounted(this,SQVM); } //does nothing
////////////////////////////////////////////////////////////////////////////
//stack functions for the api
void Remove(SQInteger n);

Loading…
Cancel
Save