• entries
24
21
• views
17662

# If You Can't Join 'em, Beat 'em

345 views

This journal entry was written a fortnight ago, but couldn't be posted then due to GameDevs downtime. Not much of interest has happened between then and now so I'm posting this old entry tonight and will get back on track next week.

Saving vertices in the problem map turned out not to be possible. Various possible workarounds were mooted, but before taking any potentially drastic decisions I decided to have one last go at fixing things. As I said before, 128 000 seemed a rather arbitrary limit. The UT public headers include a templated dynamic array class, so my first thought was that the 128 000 vertex limit must have been a static array. The problematic map was failing to load by hitting an assert, so I started by searching the UnrealTournament exe and dlls for the text string in the assert message. That narrowed me down to one highly probable dll.

Next I pulled out my downloaded PE format document (including covenant not-to-sue with Microsoft) and started parsing through the headers. The data segments weren't large enough to contain a 128 000 vertex static array, which left either a stack array (unlikely), a dynamically allocated array or I was looking in the wrong file. If it was a dynamically allocated array then odds were the allocation size would be stored in either the data segment or as an immediate operand. I therefore tried scanning the file for any four consecutive bytes which could be interpreted as a non-zero multiple of 128 000. The results were very promising - although there were a good fifty or so matches, most of them were clearly irrelevant. Only six or seven of the results seemed plausible.

From earlier testing I knew that one of the 128 000 entries was from the test which triggered the assert (I'd tried suppressing the assert previously on the off chance, but unsurprisingly that led to a crash). With so few possibilities to choose from I decided to use educated guess work to find the values I needed. I patched the file by doubling selected multiples of 128 000 and tried running the map. After a few false starts I hit pay dirt. Although there was some significant rendering corruption the map was loading and rendering. I tried a few more similar combinations and quickly found one which fixed the remaining issues. Vertex limit? What vertex limit?

I'm not sure if I've mentioned it before but at work our coding standards for our current project disallow exceptions. I don't know the reasons for this although I can think of several reasonable possibilities and the decision is a slightly contentious one. Anyway, as a result we have our own exception-free implementations of some parts of the standard library. One such implementation is the standard list class. Unfortunately I ran across a slight problem with it a couple of weeks ago. The end iterator was implemented using a null pointer, which meant that you couldn't use --end() to get an iterator to the last element. I decided to fix this and add sentinel nodes to the list implementation.

Now every competent programmer should be able to write a linked list implementation. I've done it myself several times. It turns out modifying somebody else's implementation is a bit harder. Add to this the fact that all this was taking place while my computer was out of action (see my previous journal previous entry), leaving me working on a tight time limit to be checked in before the end of the day because I was working on somebody else's box as they were away for the day. And on top of that our distributed build system wasn't set-up on that machine for me and every change to list required a rebuild of practically the entire project.

I worked as quickly as possible and got my changes checked in at the end of day. I knew there were a couple of issues remaining, but I thought they were minor. Turns out I was wrong. I came in the following Monday to find that I'd basically broken half the project and spent half a day fixing bugs in at least half the list member functions. Moral of the story? If at all possible use an existing standard library implementation. Don't write your own!

A few days later I found a curious problem with some usage of our list template. Compilation of one function was failing with an error that the compiler couldn't convert from pointer to reference. Fair enough I thought, except that it shouldn't have been trying to convert to reference. I played around with it a bit and managed to boil it down the roughly the following snippet:
typedef list< Type * >::const_reverse_iterator iterator;typedef iterator::reference reference;Type * p = 0;reference r = p;reference (iterator::* f)() const = &iterator::operator*;
list< Type * >::const_reverse_iterator was a typedef of std::reverse_iterator< list< Type * >::const_iterator >, of which the relevant bits of implementation are:
class reverse_iterator		: public _Iterator_base_secure	{	// wrap iterator to run it backwards/* snip */	typedef typename iterator_traits<_RanIt>::reference reference;/* snip */	reference __CLR_OR_THIS_CALL operator*() const		{	// return designated value		_RanIt _Tmp = current;		return (*--_Tmp);		}/* snip */	};
list< Type * >::const_iterator::reference was Type * &.

The confusing thing was that the test code snippet was compiling the line reference r = p; fine, thus proving that Type * was convertible to reference, but was choking on the following line, complaining that it could not convert type Type & (iterator::*)() const to Type * (iterator::*)(). I don't understand how iterator::reference can be Type & in the iterator class scope and Type * outside it. The only possibility I can think of is that this is another ODR violation error, but wasn't able to find any reason why the ODR might have been violated. I'm going to have another look when I have some time to try and figure out what's going on, but for now this one has me baffled. I anyone has any ideas please let me know.

?nigma

There are no comments to display.

## Create an account

Register a new account