Change window allocation/destruction to avoid undefined behaviour

Create a new window base class which holds the front/back pointers
and the window class.
This fixes the voluminous warning spam about deleted windows when using
UndefinedBehaviorSanitizer.
This commit is contained in:
Jonathan G Rennison
2018-06-06 18:14:51 +01:00
parent d8ab61cab3
commit 6573a67b69
4 changed files with 83 additions and 19 deletions

View File

@@ -480,7 +480,7 @@ static void SetViewportPosition(Window *w, int x, int y, bool force_update_overl
i = top + height - _screen.height; i = top + height - _screen.height;
if (i >= 0) height -= i; if (i >= 0) height -= i;
if (height > 0) DoSetViewportPosition(w->z_front, left, top, width, height); if (height > 0) DoSetViewportPosition((const Window *) w->z_front, left, top, width, height);
} }
} }

View File

@@ -52,9 +52,9 @@ static Window *_mouseover_last_w = NULL; ///< Window of the last #MOUSEOVER even
static Window *_last_scroll_window = NULL; ///< Window of the last scroll event. static Window *_last_scroll_window = NULL; ///< Window of the last scroll event.
/** List of windows opened at the screen sorted from the front. */ /** List of windows opened at the screen sorted from the front. */
Window *_z_front_window = NULL; WindowBase *_z_front_window = NULL;
/** List of windows opened at the screen sorted from the back. */ /** List of windows opened at the screen sorted from the back. */
Window *_z_back_window = NULL; WindowBase *_z_back_window = NULL;
/** If false, highlight is white, otherwise the by the widget defined colour. */ /** If false, highlight is white, otherwise the by the widget defined colour. */
bool _window_highlight_colour = false; bool _window_highlight_colour = false;
@@ -1359,7 +1359,7 @@ static void AddWindowToZOrdering(Window *w)
w->z_front = w->z_back = NULL; w->z_front = w->z_back = NULL;
} else { } else {
/* Search down the z-ordering for its location. */ /* Search down the z-ordering for its location. */
Window *v = _z_front_window; WindowBase *v = _z_front_window;
uint last_z_priority = UINT_MAX; uint last_z_priority = UINT_MAX;
while (v != NULL && (v->window_class == WC_INVALID || GetWindowZPriority(v->window_class) > GetWindowZPriority(w->window_class))) { while (v != NULL && (v->window_class == WC_INVALID || GetWindowZPriority(v->window_class) > GetWindowZPriority(w->window_class))) {
if (v->window_class != WC_INVALID) { if (v->window_class != WC_INVALID) {
@@ -1398,7 +1398,7 @@ static void AddWindowToZOrdering(Window *w)
* Removes a window from the z-ordering. * Removes a window from the z-ordering.
* @param w Window to remove * @param w Window to remove
*/ */
static void RemoveWindowFromZOrdering(Window *w) static void RemoveWindowFromZOrdering(WindowBase *w)
{ {
if (w->z_front == NULL) { if (w->z_front == NULL) {
assert(_z_front_window == w); assert(_z_front_window == w);
@@ -1897,11 +1897,11 @@ void UnInitWindowSystem()
{ {
UnshowCriticalError(); UnshowCriticalError();
Window *w; Window *v;
FOR_ALL_WINDOWS_FROM_FRONT(w) delete w; FOR_ALL_WINDOWS_FROM_FRONT(v) delete v;
for (w = _z_front_window; w != NULL; /* nothing */) { for (WindowBase *w = _z_front_window; w != NULL; /* nothing */) {
Window *to_del = w; WindowBase *to_del = w;
w = w->z_back; w = w->z_back;
free(to_del); free(to_del);
} }
@@ -3080,8 +3080,8 @@ void InputLoop()
HandleKeyScrolling(); HandleKeyScrolling();
/* Do the actual free of the deleted windows. */ /* Do the actual free of the deleted windows. */
for (Window *v = _z_front_window; v != NULL; /* nothing */) { for (WindowBase *v = _z_front_window; v != NULL; /* nothing */) {
Window *w = v; WindowBase *w = v;
v = v->z_back; v = v->z_back;
if (w->window_class != WC_INVALID) continue; if (w->window_class != WC_INVALID) continue;

View File

@@ -145,8 +145,8 @@ void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, Fra
void DrawCaption(const Rect &r, Colours colour, Owner owner, StringID str); void DrawCaption(const Rect &r, Colours colour, Owner owner, StringID str);
/* window.cpp */ /* window.cpp */
extern Window *_z_front_window; extern WindowBase *_z_front_window;
extern Window *_z_back_window; extern WindowBase *_z_back_window;
extern Window *_focused_window; extern Window *_focused_window;
inline uint64 GetWindowUpdateNumber() inline uint64 GetWindowUpdateNumber()
@@ -277,10 +277,48 @@ struct ViewportData : ViewPort {
struct QueryString; struct QueryString;
struct WindowBase {
WindowBase *z_front; ///< The window in front of us in z-order.
WindowBase *z_back; ///< The window behind us in z-order.
WindowClass window_class; ///< Window class
virtual ~WindowBase() {}
/**
* Memory allocator for a single class instance.
* @param size the amount of bytes to allocate.
* @return the given amounts of bytes zeroed.
*/
inline void *operator new(size_t size) { return CallocT<byte>(size); }
protected:
WindowBase() {}
private:
/**
* Memory allocator for an array of class instances.
* @param size the amount of bytes to allocate.
* @return the given amounts of bytes zeroed.
*/
inline void *operator new[](size_t size) { NOT_REACHED(); }
/**
* Memory release for a single class instance.
* @param ptr the memory to free.
*/
inline void operator delete(void *ptr) { NOT_REACHED(); }
/**
* Memory release for an array of class instances.
* @param ptr the memory to free.
*/
inline void operator delete[](void *ptr) { NOT_REACHED(); }
};
/** /**
* Data structure for an opened window * Data structure for an opened window
*/ */
struct Window : ZeroedMemoryAllocator { struct Window : WindowBase {
protected: protected:
void InitializeData(WindowNumber window_number); void InitializeData(WindowNumber window_number);
void InitializePositionSize(int x, int y, int min_width, int min_height); void InitializePositionSize(int x, int y, int min_width, int min_height);
@@ -315,7 +353,6 @@ public:
WindowDesc *window_desc; ///< Window description WindowDesc *window_desc; ///< Window description
WindowFlags flags; ///< Window flags WindowFlags flags; ///< Window flags
WindowClass window_class; ///< Window class
WindowNumber window_number; ///< Window number within the window class WindowNumber window_number; ///< Window number within the window class
uint8 timeout_timer; ///< Timer value of the WF_TIMEOUT for flags. uint8 timeout_timer; ///< Timer value of the WF_TIMEOUT for flags.
@@ -342,8 +379,6 @@ public:
int scrolling_scrollbar; ///< Widgetindex of just being dragged scrollbar. -1 if none is active. int scrolling_scrollbar; ///< Widgetindex of just being dragged scrollbar. -1 if none is active.
Window *parent; ///< Parent window. Window *parent; ///< Parent window.
Window *z_front; ///< The window in front of us in z-order.
Window *z_back; ///< The window behind us in z-order.
template <class NWID> template <class NWID>
inline const NWID *GetWidget(uint widnum) const; inline const NWID *GetWidget(uint widnum) const;
@@ -891,9 +926,37 @@ void GuiShowTooltips(Window *parent, StringID str, uint paramcount = 0, const ui
/* widget.cpp */ /* widget.cpp */
int GetWidgetFromPos(const Window *w, int x, int y); int GetWidgetFromPos(const Window *w, int x, int y);
inline const Window *FromBaseWindowFront(const WindowBase *w)
{
while (w) {
if (w->window_class != WC_INVALID) return (const Window *) w;
w = w->z_front;
}
return nullptr;
}
inline Window *FromBaseWindowFront(WindowBase *w)
{
return const_cast<Window *>(FromBaseWindowFront(const_cast<const WindowBase *>(w)));
}
inline const Window *FromBaseWindowBack(const WindowBase *w)
{
while (w) {
if (w->window_class != WC_INVALID) return (const Window *) w;
w = w->z_back;
}
return nullptr;
}
inline Window *FromBaseWindowBack(WindowBase *w)
{
return const_cast<Window *>(FromBaseWindowBack(const_cast<const WindowBase *>(w)));
}
/** Iterate over all windows */ /** Iterate over all windows */
#define FOR_ALL_WINDOWS_FROM_BACK_FROM(w, start) for (w = start; w != NULL; w = w->z_front) if (w->window_class != WC_INVALID) #define FOR_ALL_WINDOWS_FROM_BACK_FROM(w, start) for (w = FromBaseWindowFront(start); w != NULL; w = FromBaseWindowFront(w->z_front))
#define FOR_ALL_WINDOWS_FROM_FRONT_FROM(w, start) for (w = start; w != NULL; w = w->z_back) if (w->window_class != WC_INVALID) #define FOR_ALL_WINDOWS_FROM_FRONT_FROM(w, start) for (w = FromBaseWindowBack(start); w != NULL; w = FromBaseWindowBack(w->z_back))
#define FOR_ALL_WINDOWS_FROM_BACK(w) FOR_ALL_WINDOWS_FROM_BACK_FROM(w, _z_back_window) #define FOR_ALL_WINDOWS_FROM_BACK(w) FOR_ALL_WINDOWS_FROM_BACK_FROM(w, _z_back_window)
#define FOR_ALL_WINDOWS_FROM_FRONT(w) FOR_ALL_WINDOWS_FROM_FRONT_FROM(w, _z_front_window) #define FOR_ALL_WINDOWS_FROM_FRONT(w) FOR_ALL_WINDOWS_FROM_FRONT_FROM(w, _z_front_window)

View File

@@ -755,6 +755,7 @@ enum GameOptionsInvalidationData {
}; };
struct Window; struct Window;
struct WindowBase;
/** Number to differentiate different windows of the same class */ /** Number to differentiate different windows of the same class */
typedef int32 WindowNumber; typedef int32 WindowNumber;