DD2016 – video

June 12, 2016 – 4:31 pm

A video from my DD2016 talk has been uploaded and can be viewed here:

Digital Dragons 2016

May 23, 2016 – 12:14 am

A few days ago I came back from the Digital Dragons 2016 conference. I’ve been in talks with these guys in the past years, but timing was never quite right, this time I finally could make it. Luckily for me, it was the same year they invited John Romero, David Brevik and Chris Avellone. In December 1993 my classmate brought an old floppy disc to school. He claimed it contained the best game ever. Obviously, at that time, pretty much any new game was ‘best ever’, so we took it with grain of salt. I still copied it and tried it at home. It was unlike anything I’ve seen before, I just couldn’t put it down. This was Wolfenstein 3D. This is one of my most vivid gaming memories, New Year’s Eve of 1993, sneaking upstairs to keep playing, much to chagrin of my mom. I think I was “programming” a little bit at that point, but it was mostly limited to printing “Maciej rules” on the screen. If you had told me that one day I’d actually speak at the same conference as John Romero, I’d probably have fainted. Almost 25 years later and here we are :). DD2016 was fun, ppl compare it to ‘early GDC’ and while my first GDC was 2005 (already huge), I can see where they’re coming from. It’s still relatively “fresh”, not too many sponsored sessions, you don’t have to pay for every little thing, very strong indie vibe. I definitely hope it keeps growing (within reason).

It was nice to meet my heroes and my old friends, but I was primarily there to present. I think organizers plan to upload videos soon, but for the time being, you can find my slides here. The presentation title is: “Debugging Multiplayer Games. Lessons from Warframe“. It’s probably a little bit too packed for 45 minutes (I had to talk really fast) and I should have removed more slides than I did (some extra slides left), but oh well. If slides feel to cryptic, feel free to ping me.

Elixir diaries

February 22, 2016 – 3:45 am

You have probably heard about an AI algorithm defeating a human professional in a game of Go. The algorithm itself has been developed by Deep Mind, an English company that’s now owned by Google. One of the founders is Demis Hassabis. If you were playing Bullfrog games in the late 90s, the name might ring  a bell, he’s one of the designers of Theme Park. Back in the day I remember reading a column in Edge magazine titled “The Elixir Diaries”. It was the diary of Elixir Studios, a game company Hassabis started after leaving Bullfrog. The DeepMind news made me think of that and wanted to refresh my memory and go through the diaries again. It turned out to be a little bit more difficult than expected (I didn’t really remember the exact name, so my Google search phrases weren’t very precise), but I eventually found them here. Pretty cool read, especially if you’re interested in the realities of making a game back in 90s/00s (the McD for breakfast story was painfully familiar…)


January 20, 2016 – 5:53 am

Recently, we’ve been collectively complaining on Twitter about going crazy in C++ (as we do every few weeks). This reminded me of my dark period around 2002 when I was *really* excited about templates and metaprogramming. I tried finding my old code, but turned out my previous website was completely gone. Fortunately (?), good folks from The Wayback Machine had some copies. I moved some of my articles to a new server. I don’t think they’re of much use nowadays, but thought they could be interesting if only as a historical curiosity. Without further ado:

Fantasy football and statistics

November 22, 2015 – 7:04 pm

I’m playing in a fantasy football league with some coworkers this year. I have always liked all kinds of sports, but it’s a little bit challenging to follow NFL from Europe. There’s not too many stations that actually show it (except for the Super Bowl) and even if they do, the time difference make it difficult to watch. I still followed major news and managed to catch a game every now and then, but I was very far from expert. Basically, only knew big names and the most popular teams. It did get a little bit better after I moved here, but I’m still very ignorant. My only chance not to embarrass myself completely was to follow the steps of Mark Watney and ‘science the shit out of this’.

If you’re not familiar with the concept of fantasy football, Wikipedia has a fairly detailed description , but a TLDR; version is this:

  • each participant drafts his team (of real NFL players),
  • every week you’re awarded points based on performance of your players. Exact scoring rules differ between leagues, but some key numbers from our league: touchdown is worth 6 (receiving/rushing) or 4 (for a quarterback) pts, every rushing/receiving yard is 0.1 pts and so on. 15pts/week is a decent score, anything over 20 is really good and 30+ is amazing (this shifts a little bit in PPR formats).
  • every week you only compete against 1 other team. Team that gets more points (sum of points from all players) wins. In our league, 100pts is a fairly decent score, 120+ will get you a guaranteed win most weeks
  • every week you’re allowed to replace your players with players that are free (not playing for any other team). You also have to decide who plays and who sits (full team includes substitute players).

There’s plenty of draft strategies, but I feel it’s still the most “random” point of the season. You can only go by past data and projections, but it’s hard to say how it’ll translate to current seasons. I’m not going to talk about draft here. My system comes into play after few weeks after we’ve collected some samples from the new season. We want to see who to grab from the waiver wire and who to sit/play. Again, it’s a matter of personal preferences, but I’m fairly risk averse, so I was mostly interested in finding most “consistently decent” players. For example, consider these 2 stat lines:

  • player A: 7, 21, 5, 16 (mean: 12.25, std dev: 7.54)
  • player B: 11.5, 10.5, 12, 11.5 (mean: 11.375, std dev: 0.63)

Player A gets more points on average (12.25 vs 11.375), but I’d take player B. He’s way more reliable. I can plan my team better, I know (roughly) what to expect. Player A is the type that you sit, he gets 18, you let him play next week and he gets 5. My quest was to find players who’re not necessarily the most flash and bring the most points, but to find who’s the most consistent and should bring at least X pts every week. Before we start, a small disclaimer: my methodology here has almost nothing to do with actual science. Sample sizes are laughably small and fantasy points distribution definitely isn’t guaranteed to be normal. I basically tweaked various factors until I got results that made sense.

My idea was simple: grab data from some site, calculate mean/variance/std deviation for every player, reject outliers, recalculate, compute the “floor” (mean – std dev * some_weight). Our “floor” is basically telling us the minimum number of points we can reasonably expect. As mentioned, I’m fairly conservative, so I actually had an option to only reject “positive outliers” (that is, outliers that are greater than mean + std dev, we still keep samples where player underperformed). In our example, it’d keep all the samples for players B, but reject 21 points for player A. After rejection, player A’s average drops to 9.33 (new std dev is 5.86).

Spent some time trying to find the best source of stats and opted for FF Today. They update their stats quite often and format is fairly easy to parse. I couldn’t find an aggregate version, so I simply visit category stats and then traverse all the top players pages. My go-to combo for simple web scraping is Python+Beautiful Soup. ~100 lines of code later I had the first version of my script ready. My first hit was Stefon Diggs, but you could argue he wasn’t a real sleeper after Week 7 (script actually pointed him out after W6, but it was also due to super small sample size…). I got him from the waiver wire, but didn’t trust him enough to let him play (not enough data) and that turned out to be a good decision (his last two games were not that great). Week 10 brought a more serious try — I had to find a new kicker (my main kicker Matt Bryant didn’t play that week). Based on expert prediction I should have gone with Greg Zuerlein or Caleb Sturgis (these were the highest ranked kickers that were still available in my league). However, the script had the following to say:

1. Connor Barth 11.1004809472
2. Nick Folk 5.47483805032
3. Chandler Catanzaro 5.47186593476
4. Stephen Gostkowski 5.46112639465
5. Brandon McManus 5.24049168899
6. Dan Bailey 4.91128425904
7. Dustin Hopkins 4.61254139118
8. Steve Hauschka 4.60733909541
9. Blair Walsh 4.15430405875
10. Josh Lambo 4.0
12. Greg Zuerlein 3.82037546488
14. Caleb Sturgis 2.69765682193

Most of the highest ranked kickers were not available/injured, but Dustin Hopkins was still for grabs. As you can see, he’s expected to bring more points than both Zuerlein and Sturgis. Experts ranked him around 20th place this week, so not much confidence. I’m not entirely sure why tbh, I think it’s mostly no one really cares much about kickers. He’s only missed one FG this season (~92%). He plays for a mediocre team, but that factor is actually ‘encoded’ in the score above, he was playing for the same team when earning fantasy points so far. I decided to go with Hopkins and it ended way better than I could expect — he got me 17 pts this week. Now, if I want to be fair, I have to admit this was completely unexpected, based on his history his expected max score was around 12, but I’ll take it. It is a “positive outlier” I mentioned before, though so my algorithm will reject it when evaluating it in the future.

Hopefully it’s obvious, but I’d like to stress that this is just pure data analysis. Algorithm cares only about fantasy points. It has no idea about matchups, injuries and team strategy. In theory, fantasy points encode all these and ideally we’re looking for players “immune” to these factors, but some domain knowledge is recommended. For example, if you run the script with my default settings (stddevweight=1, rejectonlyposoutliers), top RBs look like:
python.exe nfl_crawler2.py –pos rb –rejectonlyposoutliers

1. Jamaal Charles — 10.66
2. Karlos Williams — 9.93
3. Mark Ingram — 9.01
4. LeSean McCoy — 8.83
5. Todd Gurley — 8.26
6. Devonta Freeman — 8.19
It can surprising to see Gurley and Freeman so low (and Miller is nowhere to be found), but it makes more sense if you remember Gurley had a very short outing in his first game (1.4pts) and Freeman’s actually fairly volatile (still brilliant) and that affects his deviation (he also had a 4.7pts game). Miller is not even in the top 10 because he wasn’t getting many touches with the old coach. If we run the same script with different options (reject all outliers, not only positives and only consider last 6 games, results are a little bit different):

python.exe nfl_crawler2.py –pos rb –lastn 6

1. Todd Gurley — 14.91
2. Devonta Freeman — 13.46
3. Chris Ivory — 11.79
4. Lamar Miller — 11.15
5. LeSean McCoy — 10.96
6. Adrian Peterson — 10.54
7. Karlos Williams — 9.93

Williams is probably the biggest surprise here, but he’s been posting great numbers so far (if not injured). His worst game was 9.7pts and while his ceiling might be lower than other guys he’s actually very consistent (dev of 4.5). His main problem is named McCoy (#5) who’s Buffalo’s RB1.

Without further ado, here’s a list for wide receivers:

python.exe nfl_crawler2.py –pos wr –rejectonlyposoutliers

1. Eric Decker — 9.71
2. Brandon Marshall — 8.08
3. DeAndre Hopkins — 7.53
4. Allen Hurns — 7.06
5. Larry Fitzgerald — 6.96
6. Jarvis Landry — 6.58
7. Julio Jones — 6.43
8. Allen Robinson — 6.30
9. Julian Edelman — 6.04
10. Demaryius Thomas — 5.43
11. Odell Beckham Jr. — 5.41
12. Keenan Allen — 5.15
13. Stefon Diggs — 5.10
14. Calvin Johnson — 5.07
15. Amari Cooper — 4.80
16. Rishard Matthews — 4.72
17. Alshon Jeffery — 4.66
18. T.Y. Hilton — 4.35
19. A.J. Green — 4.20
20. Travis Benjamin — 4.10
21. Mike Evans — 3.76
22. Antonio Brown — 3.74

Again, it can be a little bit surprising (especially Brown at 22, but he really suffered while Big Ben was away), but that’s an ultra conservative setting, it’s easy to adjust the script to match different preferences (e.g. stddevweight=0 gives just the average, doesn’t subtract deviation). It’s probably best to run the script with different settings, decide what’s important for us and cross reference the results.

Github project can be found here (requires Python 2.7 + Beautiful Soup).


August 4, 2015 – 4:45 am

I’ve been debugging a rare memory corruption bug recently and – as usual – it turned out to be an exercise in frustration. This time only part of that was because of the bug itself, the other was because methods I chose were not very helpful (in my defense, it’s been a while, so I was a little bit rusty).

The bug itself was fairly boring – sometimes, when leaving a certain UI screen game would crash. It was usually one of few places – either our UI drawing/updating code or some memory manager function. All traces lead to memory corruption. Fortunately for me, it was quite consistent and the UI crash was almost always happening because the exact same element was getting corrupted. To be more precise, UI code keeps an array of pointers to elements to tick/draw. One of the pointers (usually index 2 or 3) was getting modified. The object itself was still there, it’s just the pointer that was now pointing to some other address (not far from the object, too). I’ll describe the process briefly, hopefully it’ll save someone from going down the dead end route and wasting time.

I knew the array was OK shortly after initialization, so it was getting corrupted at some point before shutting down the movie. My first thought was to use VirtualAlloc+VirtualProtect to protect the region (we were not writing to the array again), but I dismissed it quickly. This would give us a completely different address range then when using our mem manager, so whoever was corrupting the memory would probably now just stomp over something else. I still tried that, but as expected – came short (it was not an easy repro, but I could usually get it within 5-10 minutes of constant open/close loop).

My next idea was to use debug registers. They are my go-to tool when trying to track small, localized corruptions like this. I quickly hacked something and to my surprise — the game eventually crashed, but my single-step exception has never been thrown! I started digging and to my dismay quickly confirmed that debug registers are pretty much useless in a multi-threaded environment. You could kinda expect that, seeing as we use thread context to control them, but making them work only from single thread seemed so bizarre I went with it anyway. It seems like I’m not that the only one that got that impression. Maybe they used to work differently in the past, but as of VS2012, if you enable them in thread A and thread B comes along writing to your protected address — it’ll go through without a single peep. I tried a half-hearted approach of sprinkling the same code over our other threads, but I had a feeling it was some thread that was being spawned later/not by us that was triggering the crash. Further tests seemed to confirm that theory.

This basically means we’re down to a good, old brute force method – debugger data breakpoints. They do use debug registers, but debugger will actually take a snapshot of all running threads and set debug registers for all of them (plus also any threads that are spawned afterwards). This is something you can maybe do yourself as well, but I was running it on a platform that didn’t have toolhelp32 functionality exposed (..and that still doesn’t solve a problem for threads that are forked later). Once again, this turned out to be a little bit more cumbersome than it should. Back in the old good days of VS2008 you could run macros from a breakpoint (ie. ‘run when hit’). I actually had a bunch of macros for cases like this (enable/disable next bp etc). At some point Microsoft had decided to remove it and only left an option to print a message (shame). I guess you can still do it if you write your own add-in, but that seemed like an overkill. Added some code detecting my case, put an ordinary breakpoint and then kept enabling my data breakpoint by hand. 20 minutes of keyboard mashing later I finally found my culprit (as expected, it wasn’t coming from a thread that’s been spawned by us (callback was ours, though)).

The whole thing took me way longer than it should have and in the end it turned out to be something fairly straightforward (recent modification to an async handler that wasn’t flushed before destroying a parent object, so it could have been released/reallocated in the meantime. We were only writing to one byte, but that was enough, obviously), but at least I learned a few things on the way (mostly not to rely on debug registers for stuff like that).

Know your assembly (part N)

June 3, 2015 – 5:48 am

An entertaining head-scratcher from today. Application has suddenly started crashing at launch, seemingly inside steam_api.dll. It’d be easy to blame external code, but as mentioned – it’s a new thing, so most likely related to our changes. To make things more interesting, it’s only 32-bit build that crashes, 64-bit seems fine. High-level code looks like (simplified):

struct tester
    virtual bool foo();
    virtual void bar()
    virtual void lol()

Crash occurs when trying to call bar() [the original code was actually crashing ‘inside’ bar, which debugger claimed to be inside aforementioned DLL]:

00199FB3 8B 06            mov         eax,dword ptr [esi]
00199FB5 8B 10            mov         edx,dword ptr [eax]
00199FB7 FF D2            call        edx
00199FB9 84 C0            test        al,al
00199FBB 75 10            jne         tester::lol+1Dh (199FCDh)
00199FCD 8B 06            mov         eax,dword ptr [esi]
00199FCF 8B 50 04         mov         edx,dword ptr [eax+4] ***
00199FD2 8B CE            mov         ecx,esi
00199FD4 5E               pop         esi
00199FD5 FF E2            jmp         edx

Crash line marked with stars – Access violation reading location 0x00000018, EAX=0x14 at this point. That’d suggest something’s wrong with our vtable. How can this be, though, we have just called another virtual method (foo) and it’s been fine! As you might have guessed, it’s foo itself that’s wreaking havoc. It’s been modified recently and now contains the following code:

virtual bool foo()
    EnumPageFiles(MyCallback, NULL);
    return true;

EnumPageFiles is a system function, so we’ll ignore it for now. Perhaps there’s something in the MyCallback that causes problems. Let’s remove everything and try running with empty callback function. Still crashes. Remove call to EnumPageFiles altogether – works fine…

Did some more poking and discovered that the vtable itself is actually OK and never modified by our code (data breakpoint at EAX+4 before calling foo). It’s the value of ESI that changes! See the 2 places where we move [ESI] to EAX? ESI differs between these 2 points. It’s like foo doesn’t restore it properly! Let’s keep digging… Deep inside the EnumPageFiles there is a push/pop esi pair, so it should be fine, right? The problem is, ESP doesn’t match. When trying to pop, it’s 12 bytes less than it should be, so we’re popping a completely unrelated value (in the original code it happened to point to the middle of some function in Steam DLL). You can probably guess where this is going. Stack mismatches like that are usually as sign of calling convention issues. Quick inspection of the code that executes our callback confirms it’s the problem:

75C08D83 50               push        eax
75C08D84 8D 45 E0         lea         eax,[ebp-20h]
75C08D87 50               push        eax
75C08D88 FF 75 0C         push        dword ptr [ebp+0Ch]
75C08D8B FF 55 08         call        dword ptr [ebp+8]
// Callback body (return true):
003C9F90 B8 01 00 00 00   mov         eax,1
003C9F95 C3               ret

As you can see, caller pushes 3 arguments to the stack (12 bytes!), but there’s no code that pops them (we expect callee to clean-up). Consulting the documentation confirms our findings, callback function is supposed to follow the stdcall convention. We’re not done yet, adding


doesn’t seem to cut it, compiler complains:
EnumPageFilesW’ : cannot convert parameter 1 from ‘BOOL (__stdcall *)(LPVOID,PENUM_PAGE_FILE_INFORMATION,LPCTSTR)’ to ‘PENUM_PAGE_FILE_CALLBACKW’

As it turns out, the PENUM_PAGE_FILE_CALLBACKW type doesn’t actually include __stdcall… Let’s try to force it nonetheless:

EnumPageFiles(cb, NULL);
// Callback code:
00D99F90 B8 01 00 00 00   mov         eax,1
00D99F95 C2 0C 00         ret         0Ch

As you can see, MyCallback now cleans everything up properly and – as expected – code runs without crashing. Not sure where does the discrepancy between system headers and documentation come from.

Now, you might wonder – why did the x64 build worked fine? Well, we’ve been lucky. Callback function has only 3 arguments and x64 calling convention will pass them all in registers (r8, rdx, rcx) so that stack stays untouched. If it had just 1 more — we’d run into trouble. (Correction: as pointed by Ofek, this would still be fine, there’s 1 calling convention on x64 anyway). Interestingly enough, debug version worked “fine” as well (or at least was hiding the problem more effectively, as it was using more registers so one of the top functions was saving/restoring ESI too).

C++ 11 final

April 30, 2015 – 5:20 am

I’ve been doing some micro-optimizations recently. One of the things I’ve been trying is eliminating virtual method calls in ‘leaf’ types. Consider the following snippet (simplified):

struct Bar
  virtual bool Func1() { return false; }
struct Foo : public Bar
  virtual bool Func1()
    return true;
  virtual void Func2()
    if (Func1())

void DoSomething(Foo& f)

Calling DoSomething will result in 2 virtual method calls – and rightly so, there’s no way to tell if Func1/Func2 were not modified in some class that’s derived from Foo.

It can be a little bit wasteful, especially if we – a programmer – know for a fact that nothing derives from Foo. Func2 calling Func1 will always, in every single case call just that – Func1. I used a not-so-sophisticated method to work around that:


This works, but can be dangerous. Imagine one day some other programmer decides to derive from Foo and provide new implementation of Func1. He’s in for a nasty surprise (and I’m in for some public shaming). Traditionally, C++ offers a few ways of preventing inheritance, but they’re all fairly ugly (private constructors etc). Fortunately, C++ 11 introduced a new keyword – final – which does exactly what we want.

It also got me thinking – does it mean that compiler has additional knowledge it was lacking before. Couldn’t it use it to employ the same optimizations we’ve just tried to force? Are my changes even necessary? Sadly, as it often happens, the answer is — it depends.

AFAICT, Visual Studio doesn’t care much. Yes, it’ll prevent inheritance, but doesn’t seem like it affects code generation at all. Here’s assembly for our code fragment (with final keyword added):

// struct Foo final : public Bar

// DoSomething
000000013FE15460 48 8B 01             mov         rax,qword ptr [rcx]
000000013FE15463 48 FF 60 08          jmp         qword ptr [rax+8] ***

virtual void Func2()
00000001407426D0 48 83 EC 28          sub         rsp,28h
00000001407426D4 48 8B 01             mov         rax,qword ptr [rcx]
00000001407426D7 FF 10                call        qword ptr [rax] ***
00000001407426D9 84 C0                test        al,al
00000001407426DB 74 10                je          Foo::Func2+1Dh (01407426EDh)
00000001407426DD 48 8D 0D 04 3B EF 00 lea         rcx,[string "Hello" (01416361E8h)]
00000001407426E4 48 83 C4 28          add         rsp,28h
00000001407426E8 E9 B3 FB 85 00       jmp         printf (0140FA22A0h)
00000001407426ED 48 83 C4 28          add         rsp,28h
00000001407426F1 C3                   ret

As you can see – still 2 vtable accesses (lines marked with stars). Let’s see if GCC/Clang does any better (Compiler Explorer to the rescue). Just look at this beauty (that’s a body of DoSomething):

    movl    $.L.str, %edi
    xorl    %eax, %eax
    jmp    printf                  # TAILCALL
    .asciz    "Hello"

Not only did the compiler de-virtualize both calls, it also inlined them and sprinkled with a tailcall. Impressive.

Sadly, as mentioned – we can’t rely on these optimizations being employed consistently, but at the very least – final will prevent another programmer from making a mistake he’d later regret.

Instrumenting crash dumps

April 4, 2015 – 2:16 am

I’ve been planning to write a post about debugging multiplayer games (post-mortem) for a while now, but it keeps getting bigger and bigger, so instead of waiting until I can get enough time to finish it, I thought it’d be easier to share some quick’n’easy tricks first.

I’d like to show  a simple way of “instrumenting” a crash dump so that it gives us more info about the crime scene. Let’s assume we’ve received a crash from the following piece of code (it’s actually very close to a real-life scenario I encountered). Short side note first: I’m talking about crash dumps coming from public here and usually extremely rare cases, too. If this was something you could repro in-house, we wouldn’t have this conversation.

struct SType
    SType() : parentType(NULL) {}
    SType* parentType;
struct SObj
    SObj(SType* t) : type(t) {}
    SType* type;

    bool IsA(const SType* t) const;
bool SObj::IsA(const SType* t) const
    const SType* iter = type;
        if(iter == t)
            return true;
        // Crashes in the line below. Access Violation when reading 'iter->parentType'
        iter = iter->parentType;

Our crash dumps points to the line 23, obviously something’s wrong with the ‘iter‘ variable. Corresponding assembly code (just the while loop):

003A2172 3B 44 24 04      cmp         eax,dword ptr [esp+4]
003A2176 74 0B            je          SObj::IsA+15h (3A2183h)
003A2178 8B 00            mov         eax,dword ptr [eax]
003A217A 85 C0            test        eax,eax
003A217C 75 F4            jne         SObj::IsA+4 (3A2172h)

Crash happens in the mov eax, dword ptr [eax] line. Sadly, given only this dump, it’s hard to form any solid theories. We don’t even know what iteration is that, so can’t tell if it’s the object itself that’s corrupted (so accessing obj->type) or the type chain. We suspect something wrote over either object instance or type definition, but most of the time, we can’t see what’s in memory corresponding to either of these objects (I’ve tried inspecting memory associated with ECX, but nothing interesting there, not included in the dump). Yes, you can try grabbing full memory dumps, but they’re usually too huge to be practical (good luck having people send you gigs of data). Normal crash dumps only contain very limited information, registers, stack, call stacks and so on. Wait a moment, did I say “stack”? What if we instrument our function, so that it tries to store crucial information where we can find it? For the sake of this example let’s assume our object is corrupted  by the following code:

SType st;
SObj obj(&st);

static void Corrupt()
    const char* str = "Hello world!";
    memcpy(&obj, str, 10);

Here’s a temporarily modified version of the IsA method:

bool SObj::IsA(const SType* t) const
    volatile unsigned int stackInfo[4];
    const volatile unsigned int* fmem = reinterpret_cast<const volatile unsigned int*>(this);
    for(size_t i = 0; i < 4; ++i)
        stackInfo[i] = fmem[i];
// Everything else stays the same

Remember, this is temporary, diagnostic code, it doesn’t need to be pretty. The idea is to store data associated with “this” pointer on the stack, so that we can take a look later. Yes, it comes with a slight performance hit, but it’s less severe than most alternatives (e.g. logging). We deploy a new build and wait for fresh dumps. Finally, we can answer some of our questions:

(Immediate Window)
> stackInfo
[0x0]: 0x6c6c6548
[0x1]: 0x6f77206f
[0x2]: 0x00ee6c72
[0x3]: 0x00000000
> eax

At this point we know it’s actually memory associated with the object itself that’s written over, we crashed during the first iteration (EAX == first 4 bytes of the object memory == obj.type). Let’s see if we can get more info about the data that’s in memory right now:

> (const char*)stackInfo
0x012afcc4 "Hello worl?"

A-ha! We’re being written over by a familiar looking string. Obviously, it’s a contrived example, in real-life it rarely is that easy, but in my experience looking at “corrupted” memory can often give you valuable hints (is it a string, maybe some common floating-point bit pattern like 0x3f800000 etc).

Tricks like this are most valuable in a scenario, where we have a luxury of regular, frequent deployments (so that we can push instrumented build & the fix) and, sadly, are less helpful for more traditional, boxed products. Even then, it’s good to remember that you can stuff some of your crucial info (global state) in the stack space of your main loop as well. This can be especially helpful on consoles, where dumps are often all you get (no log files). In most cases you can get 90% of what you need from a raw dump, but having a way to get the extra few % when needed can be priceless. It did save my sanity many times in the past.

NaN memories

March 12, 2015 – 6:02 am

A nice thing about Twitter is that single tweet can bring so many memories. It all started when Fiora posted this. It reminded me of an old bug I encountered few years ago when working on a multi-platform (PC/X360/PS3) title. One day we started getting strange bug reports. Apparently, if you jumped down the roof at a very specific position, player would start to slide across the map. To make things more interesting, this was only happening on consoles, PC version was fine. After few minutes of investigation I narrowed it down to a fragment of code that looked roughly like this (don’t have access to the original code anymore, trying to recreate it from memory, that was player movement module):

float x = y / sfactor;
float vx = fmax(0.0001f, fmin(x, MAX_RESPONSE));

Looks innocent, but it’d break completely for y==0.0. The whole block has been added recently and the ‘sfactor‘ property was exposed to the editor and controlled by designers. As it turned out, it’s been set to 0.0 as well. If y == 0.0 and sfactor == 0.0, then x is NaN. fmax and fmin are, as you probably have guessed, floating-point versions of the min/max functions. For PC we were using a naive/reference implementation, ie:

float fmax(float a, b) { return a > b ? a : b; }
float fmin(float a, b) { return a < b ? a : b; }

Let’s see what happens in our case. fmin(NaN, MAX_RESPONSE) returns MAX_RESPONSE, as any comparison against NaN returns false. It’ll be fed to fmax and since it’s greater than 0.0001f, vx = MAX_RESPONSE.

Things are a little bit more interesting on PPC, though. If you coded for PowerPC, you’re aware of two facts:

  • it hates branches,
  • it has a ‘fsel’ instruction that allows for branchless floating-point code. Basically it ‘selects’ one of two given values based on another value (depending if it’s greater or less than zero).

The usual way of implementing fmin & fmax using fsel would be:

float fmax(float a, float b) { return fsel(a - b, a, b); }
float fmin(float a, float b) { return fsel(a - b, b, a); }

You can probably spot a problem already. If not, refer to this bit of fsel description (+my notes): “If the value in FRA [a – b in our case] is less than zero or is a NaN, floating point register FRT is set to the contents of floating-point register FRB [3rd argument]”. Think about what happens as our NaN flows through the fmin & fmax functions in this case:

  • fmin(x, MAX_RESPONSE): a – b is still NaN, so ‘a’ (x) is returned,
  • fmax(0.0001f, x): a – b is NaN, b (x) is returned.

In this case, NaN would just go through both functions and we ended up with an invalid vx. In this particular case it was an unfortunate coincidence that the original author used fmin(x, MAX_RESPONSE) — fmin(MAX_RESPONSE, x) would have been “fine”, but at least it helped us find the actual problem which was invalid value of the ‘sfactor‘ property (..and incompatibilities between fmin/fmax on different platforms).