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, ...)
|
void WriteLine(const utf8 * format, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
vfprintf(stdout, format, args);
|
WriteLine_VA(format, args);
|
||||||
puts("");
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WriteLine_VA(const utf8 * format, va_list args)
|
||||||
|
{
|
||||||
|
vfprintf(stdout, format, args);
|
||||||
|
puts("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -37,5 +37,6 @@ namespace Console
|
||||||
void WriteFormat(const utf8 * format, ...);
|
void WriteFormat(const utf8 * format, ...);
|
||||||
void WriteLine();
|
void WriteLine();
|
||||||
void WriteLine(const utf8 * format, ...);
|
void WriteLine(const utf8 * format, ...);
|
||||||
|
void WriteLine_VA(const utf8 * format, va_list args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,34 +15,83 @@
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef __WINDOWS__
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "Console.hpp"
|
#include "Console.hpp"
|
||||||
#include "Diagnostics.hpp"
|
#include "Diagnostics.hpp"
|
||||||
#include "Guard.hpp"
|
#include "Guard.hpp"
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include "../openrct2.h"
|
||||||
|
}
|
||||||
|
|
||||||
namespace Guard
|
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 (expression) return;
|
||||||
|
|
||||||
if (message != nullptr)
|
if (message != nullptr)
|
||||||
{
|
{
|
||||||
Console::Error::WriteLine(message);
|
Console::Error::WriteLine("Assertion failed:");
|
||||||
|
Console::Error::WriteLine_VA(message, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#ifdef DEBUG
|
||||||
Debug::Break();
|
Debug::Break();
|
||||||
#endif
|
#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);
|
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)
|
if (message != nullptr)
|
||||||
{
|
{
|
||||||
Console::Error::WriteLine(message);
|
Console::Error::WriteLine_VA(message, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
|
|
@ -16,23 +16,35 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility methods for asserting function parameters.
|
* Utility methods for asserting function parameters.
|
||||||
*/
|
*/
|
||||||
namespace Guard
|
namespace Guard
|
||||||
{
|
{
|
||||||
void Assert(bool expression, const char * message = nullptr);
|
void Assert(bool expression, const char * message = nullptr, ...);
|
||||||
void Fail(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>
|
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>
|
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)
|
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);
|
this->insert(this->begin() + index, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ public:
|
||||||
|
|
||||||
void RemoveAt(size_t index)
|
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);
|
this->erase(this->begin() + index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,13 +102,13 @@ public:
|
||||||
|
|
||||||
const_reference operator[](size_t index) const
|
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);
|
return std::vector<T>::operator[](index);
|
||||||
}
|
}
|
||||||
|
|
||||||
reference operator[](size_t 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);
|
return std::vector<T>::operator[](index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ static bool AllocatedListContains(uint32 baseImageId, uint32 count)
|
||||||
|
|
||||||
static uint32 AllocateImageList(uint32 count)
|
static uint32 AllocateImageList(uint32 count)
|
||||||
{
|
{
|
||||||
Guard::Assert(count != 0);
|
Guard::Assert(count == 0, GUARD_LINE);
|
||||||
|
|
||||||
if (!_initialised)
|
if (!_initialised)
|
||||||
{
|
{
|
||||||
|
@ -92,12 +92,12 @@ static uint32 AllocateImageList(uint32 count)
|
||||||
|
|
||||||
static void FreeImageList(uint32 baseImageId, uint32 count)
|
static void FreeImageList(uint32 baseImageId, uint32 count)
|
||||||
{
|
{
|
||||||
Guard::Assert(_initialised);
|
Guard::Assert(_initialised, GUARD_LINE);
|
||||||
Guard::Assert(baseImageId >= BASE_IMAGE_ID);
|
Guard::Assert(baseImageId >= BASE_IMAGE_ID, GUARD_LINE);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
bool contains = AllocatedListContains(baseImageId, count);
|
bool contains = AllocatedListContains(baseImageId, count);
|
||||||
Guard::Assert(contains);
|
Guard::Assert(contains, GUARD_LINE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (auto it = _freeLists.begin(); it != _freeLists.end(); it++)
|
for (auto it = _freeLists.begin(); it != _freeLists.end(); it++)
|
||||||
|
|
|
@ -510,7 +510,7 @@ namespace ThemeManager
|
||||||
|
|
||||||
static void GetAvailableThemes(List<AvailableTheme> * outThemes)
|
static void GetAvailableThemes(List<AvailableTheme> * outThemes)
|
||||||
{
|
{
|
||||||
Guard::ArgumentNotNull(outThemes);
|
Guard::ArgumentNotNull(outThemes, GUARD_LINE);
|
||||||
|
|
||||||
outThemes->Clear();
|
outThemes->Clear();
|
||||||
|
|
||||||
|
|
|
@ -166,8 +166,8 @@ namespace ObjectFactory
|
||||||
|
|
||||||
Object * CreateObjectFromLegacyData(const rct_object_entry * entry, const void * data, size_t dataSize)
|
Object * CreateObjectFromLegacyData(const rct_object_entry * entry, const void * data, size_t dataSize)
|
||||||
{
|
{
|
||||||
Guard::ArgumentNotNull(entry);
|
Guard::ArgumentNotNull(entry, GUARD_LINE);
|
||||||
Guard::ArgumentNotNull(data);
|
Guard::ArgumentNotNull(data, GUARD_LINE);
|
||||||
|
|
||||||
Object * result = CreateObject(*entry);
|
Object * result = CreateObject(*entry);
|
||||||
if (result != nullptr)
|
if (result != nullptr)
|
||||||
|
|
|
@ -225,7 +225,7 @@ private:
|
||||||
|
|
||||||
size_t GetLoadedObjectIndex(const Object * object)
|
size_t GetLoadedObjectIndex(const Object * object)
|
||||||
{
|
{
|
||||||
Guard::ArgumentNotNull(object);
|
Guard::ArgumentNotNull(object, GUARD_LINE);
|
||||||
|
|
||||||
size_t result = SIZE_MAX;
|
size_t result = SIZE_MAX;
|
||||||
if (_loadedObjects != nullptr)
|
if (_loadedObjects != nullptr)
|
||||||
|
|
|
@ -167,7 +167,7 @@ public:
|
||||||
|
|
||||||
Object * LoadObject(const ObjectRepositoryItem * ori) override
|
Object * LoadObject(const ObjectRepositoryItem * ori) override
|
||||||
{
|
{
|
||||||
Guard::ArgumentNotNull(ori);
|
Guard::ArgumentNotNull(ori, GUARD_LINE);
|
||||||
|
|
||||||
Object * object = ObjectFactory::CreateObjectFromLegacyFile(ori->Path);
|
Object * object = ObjectFactory::CreateObjectFromLegacyFile(ori->Path);
|
||||||
return object;
|
return object;
|
||||||
|
@ -177,7 +177,7 @@ public:
|
||||||
{
|
{
|
||||||
ObjectRepositoryItem * item = &_items[ori->Id];
|
ObjectRepositoryItem * item = &_items[ori->Id];
|
||||||
|
|
||||||
Guard::Assert(item->LoadedObject == nullptr);
|
Guard::Assert(item->LoadedObject == nullptr, GUARD_LINE);
|
||||||
item->LoadedObject = object;
|
item->LoadedObject = object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,7 +518,7 @@ private:
|
||||||
int newRealChecksum = object_calculate_checksum(entry, newData, newDataSize);
|
int newRealChecksum = object_calculate_checksum(entry, newData, newDataSize);
|
||||||
if (newRealChecksum != entry->checksum)
|
if (newRealChecksum != entry->checksum)
|
||||||
{
|
{
|
||||||
Guard::Fail("CalculateExtraBytesToFixChecksum failed to fix checksum.");
|
Guard::Fail("CalculateExtraBytesToFixChecksum failed to fix checksum.", GUARD_LINE);
|
||||||
|
|
||||||
// Save old data form
|
// Save old data form
|
||||||
SaveObject(path, entry, data, dataSize, false);
|
SaveObject(path, entry, data, dataSize, false);
|
||||||
|
|
|
@ -94,7 +94,7 @@ void SceneryGroupObject::UpdateEntryIndexes()
|
||||||
if (ori->LoadedObject == nullptr) continue;
|
if (ori->LoadedObject == nullptr) continue;
|
||||||
|
|
||||||
uint16 sceneryEntry = objectManager->GetLoadedObjectEntryIndex(ori->LoadedObject);
|
uint16 sceneryEntry = objectManager->GetLoadedObjectEntryIndex(ori->LoadedObject);
|
||||||
Guard::Assert(sceneryEntry != UINT8_MAX);
|
Guard::Assert(sceneryEntry != UINT8_MAX, GUARD_LINE);
|
||||||
|
|
||||||
uint8 objectType = objectEntry->flags & 0x0F;
|
uint8 objectType = objectEntry->flags & 0x0F;
|
||||||
switch (objectType) {
|
switch (objectType) {
|
||||||
|
|
|
@ -360,7 +360,7 @@ namespace RCT1
|
||||||
"LEMST ", // RCT1_RIDE_TYPE_LEMONADE_STALL
|
"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];
|
return map[rideType];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,7 +459,7 @@ namespace RCT1
|
||||||
"ENTERP ", // RCT1_VEHICLE_TYPE_ENTERPRISE_WHEEL
|
"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];
|
return map[vehicleType];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue