mirror of https://github.com/OpenRCT2/OpenRCT2.git
Merge pull request #4106 from IntelOrca/improve-assertions
Improve guard assertions so that they display the location of where the guard was and also allow a dump file to be created on abort.
This commit is contained in:
commit
c123673d6f
|
@ -94,11 +94,15 @@ namespace Console
|
|||
void WriteLine(const utf8 * format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
WriteLine_VA(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void WriteLine_VA(const utf8 * format, va_list args)
|
||||
{
|
||||
vfprintf(stdout, format, args);
|
||||
puts("");
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,5 +37,6 @@ namespace Console
|
|||
void WriteFormat(const utf8 * format, ...);
|
||||
void WriteLine();
|
||||
void WriteLine(const utf8 * format, ...);
|
||||
void WriteLine_VA(const utf8 * format, va_list args);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,34 +15,83 @@
|
|||
#pragma endregion
|
||||
|
||||
#include <cassert>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "Console.hpp"
|
||||
#include "Diagnostics.hpp"
|
||||
#include "Guard.hpp"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "../openrct2.h"
|
||||
}
|
||||
|
||||
namespace Guard
|
||||
{
|
||||
void Assert(bool expression, const char * message)
|
||||
void Assert(bool expression, const char * message, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
Assert_VA(expression, message, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Assert_VA(bool expression, const char * message, va_list args)
|
||||
{
|
||||
if (expression) return;
|
||||
|
||||
if (message != nullptr)
|
||||
{
|
||||
Console::Error::WriteLine(message);
|
||||
Console::Error::WriteLine("Assertion failed:");
|
||||
Console::Error::WriteLine_VA(message, args);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
#ifdef DEBUG
|
||||
Debug::Break();
|
||||
#endif
|
||||
#ifdef __WINDOWS__
|
||||
char version[128];
|
||||
openrct2_write_full_version_info(version, sizeof(version));
|
||||
|
||||
char buffer[512];
|
||||
strcpy(buffer, "An assertion failed, please report this to the OpenRCT2 developers.\r\n\r\nVersion: ");
|
||||
strcat(buffer, version);
|
||||
strcat(buffer, "\r\n");
|
||||
vsprintf((char *)strchr(buffer, 0), message, args);
|
||||
int result = MessageBox(nullptr, buffer, OPENRCT2_NAME, MB_ABORTRETRYIGNORE | MB_ICONEXCLAMATION);
|
||||
if (result == IDABORT)
|
||||
{
|
||||
#ifdef USE_BREAKPAD
|
||||
// Force a crash that breakpad will handle allowing us to get a dump
|
||||
*((void**)0) = 0;
|
||||
#else
|
||||
assert(false);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
assert(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Fail(const char * message)
|
||||
void Fail(const char * message, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
Fail_VA(message, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Fail_VA(const char * message, va_list args)
|
||||
{
|
||||
if (message != nullptr)
|
||||
{
|
||||
Console::Error::WriteLine(message);
|
||||
Console::Error::WriteLine_VA(message, args);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
|
|
@ -16,23 +16,35 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/**
|
||||
* Utility methods for asserting function parameters.
|
||||
*/
|
||||
namespace Guard
|
||||
{
|
||||
void Assert(bool expression, const char * message = nullptr);
|
||||
void Fail(const char * message = nullptr);
|
||||
void Assert(bool expression, const char * message = nullptr, ...);
|
||||
void Assert_VA(bool expression, const char * message, va_list args);
|
||||
void Fail(const char * message = nullptr, ...);
|
||||
void Fail_VA(const char * message, va_list args);
|
||||
|
||||
template<typename T>
|
||||
void ArgumentNotNull(T * argument, const char * message = nullptr)
|
||||
void ArgumentNotNull(T * argument, const char * message = nullptr, ...)
|
||||
{
|
||||
Assert(argument != nullptr, message);
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
Assert_VA(argument != nullptr, message, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ArgumentInRange(T argument, T min, T max, const char * message = nullptr)
|
||||
void ArgumentInRange(T argument, T min, T max, const char * message = nullptr, ...)
|
||||
{
|
||||
Assert(argument >= min && argument <= max, message);
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
Assert(argument >= min && argument <= max, message, args);
|
||||
va_end(args);
|
||||
}
|
||||
};
|
||||
|
||||
#define GUARD_LINE "Location: %s:%d", __func__, __LINE__
|
||||
|
|
|
@ -72,7 +72,7 @@ public:
|
|||
|
||||
void Insert(T item, size_t index)
|
||||
{
|
||||
Guard::ArgumentInRange(index, (size_t)0, this->size());
|
||||
Guard::ArgumentInRange(index, (size_t)0, this->size(), GUARD_LINE);
|
||||
this->insert(this->begin() + index, item);
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ public:
|
|||
|
||||
void RemoveAt(size_t index)
|
||||
{
|
||||
Guard::ArgumentInRange(index, (size_t)0, this->size() - 1);
|
||||
Guard::ArgumentInRange(index, (size_t)0, this->size() - 1, GUARD_LINE);
|
||||
this->erase(this->begin() + index);
|
||||
}
|
||||
|
||||
|
@ -102,13 +102,13 @@ public:
|
|||
|
||||
const_reference operator[](size_t index) const
|
||||
{
|
||||
Guard::ArgumentInRange(index, (size_t)0, this->size() - 1);
|
||||
Guard::ArgumentInRange(index, (size_t)0, this->size() - 1, GUARD_LINE);
|
||||
return std::vector<T>::operator[](index);
|
||||
}
|
||||
|
||||
reference operator[](size_t index)
|
||||
{
|
||||
Guard::ArgumentInRange(index, (size_t)0, this->size() - 1);
|
||||
Guard::ArgumentInRange(index, (size_t)0, this->size() - 1, GUARD_LINE);
|
||||
return std::vector<T>::operator[](index);
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ static bool AllocatedListContains(uint32 baseImageId, uint32 count)
|
|||
|
||||
static uint32 AllocateImageList(uint32 count)
|
||||
{
|
||||
Guard::Assert(count != 0);
|
||||
Guard::Assert(count == 0, GUARD_LINE);
|
||||
|
||||
if (!_initialised)
|
||||
{
|
||||
|
@ -92,12 +92,12 @@ static uint32 AllocateImageList(uint32 count)
|
|||
|
||||
static void FreeImageList(uint32 baseImageId, uint32 count)
|
||||
{
|
||||
Guard::Assert(_initialised);
|
||||
Guard::Assert(baseImageId >= BASE_IMAGE_ID);
|
||||
Guard::Assert(_initialised, GUARD_LINE);
|
||||
Guard::Assert(baseImageId >= BASE_IMAGE_ID, GUARD_LINE);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool contains = AllocatedListContains(baseImageId, count);
|
||||
Guard::Assert(contains);
|
||||
Guard::Assert(contains, GUARD_LINE);
|
||||
#endif
|
||||
|
||||
for (auto it = _freeLists.begin(); it != _freeLists.end(); it++)
|
||||
|
|
|
@ -510,7 +510,7 @@ namespace ThemeManager
|
|||
|
||||
static void GetAvailableThemes(List<AvailableTheme> * outThemes)
|
||||
{
|
||||
Guard::ArgumentNotNull(outThemes);
|
||||
Guard::ArgumentNotNull(outThemes, GUARD_LINE);
|
||||
|
||||
outThemes->Clear();
|
||||
|
||||
|
|
|
@ -166,8 +166,8 @@ namespace ObjectFactory
|
|||
|
||||
Object * CreateObjectFromLegacyData(const rct_object_entry * entry, const void * data, size_t dataSize)
|
||||
{
|
||||
Guard::ArgumentNotNull(entry);
|
||||
Guard::ArgumentNotNull(data);
|
||||
Guard::ArgumentNotNull(entry, GUARD_LINE);
|
||||
Guard::ArgumentNotNull(data, GUARD_LINE);
|
||||
|
||||
Object * result = CreateObject(*entry);
|
||||
if (result != nullptr)
|
||||
|
|
|
@ -225,7 +225,7 @@ private:
|
|||
|
||||
size_t GetLoadedObjectIndex(const Object * object)
|
||||
{
|
||||
Guard::ArgumentNotNull(object);
|
||||
Guard::ArgumentNotNull(object, GUARD_LINE);
|
||||
|
||||
size_t result = SIZE_MAX;
|
||||
if (_loadedObjects != nullptr)
|
||||
|
|
|
@ -167,7 +167,7 @@ public:
|
|||
|
||||
Object * LoadObject(const ObjectRepositoryItem * ori) override
|
||||
{
|
||||
Guard::ArgumentNotNull(ori);
|
||||
Guard::ArgumentNotNull(ori, GUARD_LINE);
|
||||
|
||||
Object * object = ObjectFactory::CreateObjectFromLegacyFile(ori->Path);
|
||||
return object;
|
||||
|
@ -177,7 +177,7 @@ public:
|
|||
{
|
||||
ObjectRepositoryItem * item = &_items[ori->Id];
|
||||
|
||||
Guard::Assert(item->LoadedObject == nullptr);
|
||||
Guard::Assert(item->LoadedObject == nullptr, GUARD_LINE);
|
||||
item->LoadedObject = object;
|
||||
}
|
||||
|
||||
|
@ -518,7 +518,7 @@ private:
|
|||
int newRealChecksum = object_calculate_checksum(entry, newData, newDataSize);
|
||||
if (newRealChecksum != entry->checksum)
|
||||
{
|
||||
Guard::Fail("CalculateExtraBytesToFixChecksum failed to fix checksum.");
|
||||
Guard::Fail("CalculateExtraBytesToFixChecksum failed to fix checksum.", GUARD_LINE);
|
||||
|
||||
// Save old data form
|
||||
SaveObject(path, entry, data, dataSize, false);
|
||||
|
|
|
@ -94,7 +94,7 @@ void SceneryGroupObject::UpdateEntryIndexes()
|
|||
if (ori->LoadedObject == nullptr) continue;
|
||||
|
||||
uint16 sceneryEntry = objectManager->GetLoadedObjectEntryIndex(ori->LoadedObject);
|
||||
Guard::Assert(sceneryEntry != UINT8_MAX);
|
||||
Guard::Assert(sceneryEntry != UINT8_MAX, GUARD_LINE);
|
||||
|
||||
uint8 objectType = objectEntry->flags & 0x0F;
|
||||
switch (objectType) {
|
||||
|
|
|
@ -360,7 +360,7 @@ namespace RCT1
|
|||
"LEMST ", // RCT1_RIDE_TYPE_LEMONADE_STALL
|
||||
};
|
||||
|
||||
Guard::ArgumentInRange<size_t>(rideType, 0, Util::CountOf(map), "");
|
||||
Guard::ArgumentInRange<size_t>(rideType, 0, Util::CountOf(map), "Unsupported RCT1 ride type.");
|
||||
return map[rideType];
|
||||
}
|
||||
|
||||
|
@ -459,7 +459,7 @@ namespace RCT1
|
|||
"ENTERP ", // RCT1_VEHICLE_TYPE_ENTERPRISE_WHEEL
|
||||
};
|
||||
|
||||
Guard::ArgumentInRange<size_t>(vehicleType, 0, Util::CountOf(map), "");
|
||||
Guard::ArgumentInRange<size_t>(vehicleType, 0, Util::CountOf(map), "Unsupported RCT1 vehicle type.");
|
||||
return map[vehicleType];
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue