Skip to content

Commit

Permalink
Fix OpenTTD#9588, 140a96b: [Squirrel] Reaching memory limit during sc…
Browse files Browse the repository at this point in the history
…ript registration could prevent further script detections

Also the allocation triggering the limit was never freed.
And if the exception was thrown in a constructor using placement new, the pre-allocated was not freed either.
  • Loading branch information
glx22 committed Oct 1, 2021
1 parent 78d66b7 commit bfbff0a
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 1 deletion.
15 changes: 15 additions & 0 deletions src/3rdparty/squirrel/squirrel/sqobject.h
Expand Up @@ -62,6 +62,21 @@ struct SQRefCounted
SQUnsignedInteger _uiRef;
struct SQWeakRef *_weakref;
virtual void Release()=0;

/* Placement new/delete to prevent memory leaks if constructor throws an exception. */
inline void *operator new(size_t size, SQRefCounted *place)
{
place->size = size;
return place;
}

inline void operator delete(void *ptr, SQRefCounted *place)
{
SQ_FREE(ptr, place->size);
}

private:
size_t size;
};

struct SQWeakRef : SQRefCounted
Expand Down
14 changes: 13 additions & 1 deletion src/script/squirrel.cpp
Expand Up @@ -67,7 +67,7 @@ struct ScriptAllocator {
* @param requested_size The requested size that was requested to be allocated.
* @param p The pointer to the allocated object, or null if allocation failed.
*/
void CheckAllocation(size_t requested_size, const void *p)
void CheckAllocation(size_t requested_size, void *p)
{
if (this->allocated_size > this->allocation_limit && !this->error_thrown) {
/* Do not allow allocating more than the allocation limit, except when an error is
Expand All @@ -77,6 +77,11 @@ struct ScriptAllocator {
char buff[128];
seprintf(buff, lastof(buff), "Maximum memory allocation exceeded by " PRINTF_SIZE " bytes when allocating " PRINTF_SIZE " bytes",
this->allocated_size - this->allocation_limit, requested_size);
/* Don't leak the rejected allocation. */
free(p);
p = nullptr;
/* Allocation rejected, don't count it. */
this->allocated_size -= requested_size;
throw Script_FatalError(buff);
}

Expand All @@ -93,6 +98,8 @@ struct ScriptAllocator {
this->error_thrown = true;
char buff[64];
seprintf(buff, lastof(buff), "Out of memory. Cannot allocate " PRINTF_SIZE " bytes", requested_size);
/* Allocation failed, don't count it. */
this->allocated_size -= requested_size;
throw Script_FatalError(buff);
}
}
Expand Down Expand Up @@ -757,6 +764,11 @@ void Squirrel::Uninitialize()
/* Clean up the stuff */
sq_pop(this->vm, 1);
sq_close(this->vm);

assert(this->allocator->allocated_size == 0);

/* Reset memory allocation errors. */
this->allocator->error_thrown = false;
}

void Squirrel::Reset()
Expand Down

0 comments on commit bfbff0a

Please sign in to comment.