Created Remembrance, Permanence, & THERA
The Kyou System continued hammering and stirring, sleepless, indefatigable, at work upon the machines they were making.



KyouSystem
@KyouSystem

I swear, sometimes cleaning up the GNU Backgammon codebase feels like moving furniture around: The room will look clean-ish at a cursory glance, but then you slide the couch over by a meter and reveal a huge mess of old bits of food, candy wrappers, abandoned socks, the TV remote that's been missing for like three weeks, plus a few well-fed bugs with big shiny carapaces here and there...


KyouSystem
@KyouSystem

For reference, I found this gnarly bug last night during some code cleanup. After re-ordering the arguments passed to one of the functions I'd rewritten, I suddenly started seeing garbage values passed to it during testing (specifically, for the numbers rolled on the dice). I thought at first that I'd overlooked one of the calls to it and thus was seeing junk due to the out-of-order parameters, but nope.

As it turns out, the "findData" data structure used for evaluations that's supposed to be populated with all of the game's state (the positions of the tablemen, the numbers rolled on the dice, the value and owner of the doubling cube, etc) was NOT being fully initialized. No, some of the fields were being left completely uninitialized, most notably the dice roll numbers.

"But Kyou System," you might be thinking, "if that's true, wouldn't those values ALWAYS have been junk? How did it work at all beforehand?"

THAT'S A GREAT QUESTION~

You see, there's a global "matchstate" data structure (yes, with inconsistent capitalization for the data types) from which GNU Backgammon pulls the relevant data when setting up the local "findData" structure. And by "pulls data from" I mean "haphazardly assigns pointers to", as there are no local copies being made of this global data or any such thing, but instead the evaluation engine is given pointers to said global data.[1]

So, the only conclusion I can reach is that, by some miraculous combination of the way the global data is arranged in memory, the use of direct pointers to that global data, and however the compiler was optimizing the function call when it still had the old parameter ordering, the dice roll numbers passed to the function were SOMEHOW consistently correct.

Of course, that all promptly fell apart as soon as I reordered the function parameters. Fixing it was as simple as actually copying the dice roll numbers into the "findData" structure, but it took me a hot minute to figure out what the hell was happening in the first place, that's for sure, lol


[1] Sure, they're const pointers, but it's still bad practice IMO, especially considering the multithreading going on with rollout evaluations. I'd happily gut and rewrite all of that code myself, but I've got too much other stuff to do, and I've sank quite a bit of time into this already-major rewrite as it is. It'll have to wait for now...


You must log in to comment.

in reply to @KyouSystem's post:

I forget where GCC falls in the field, but an additional twist on issues like this is that many C compilers used to initialize all memory to zeroes, with many ending the practice in the late '90s. Since nobody back then read "compiler news" if you could even find updates, this meant that a lot of "averting Y2K problems" was secretly discovering a mess of uninitialized variables that now caused unpredictable behavior.