Something is erasing my program while it's running (oh wait oops)
jvns.ca
jvns.ca
Like in the 80's, writing games for the Commodore 64... Where they kept the memory for the program at a location shortly after where they kept the screen memory... So if you forgot to bounds-check the coordinates of the little guy you had running around on the screen, you could run him right off the bottom.
Where he'd start overwriting random bits of memory. Until eventually he walked right over your source code. Which was being interpreted. Until, of course, the guy caught up with the current execution point.
At which point, you hoped you had spent 10 minutes saving a copy of your code recently. Because listing your source you'd find it speckled with random special characters and changed values. Tire tracks from that little guy.
And you learned that the first thing you do when implementing that joystick routine is to also implement bounds checking.
It reminded me of this classic GHC error: https://twitter.com/bos31337/status/116372971509121025
Not quite the same, but still "outright program destruction" of a sort.
She freaks out a bit, I freak out a lot. We're both worried that something really bad happened, then I realized that DEAD is actually a number in hex. I look through the data segment, and I see a AD DE in there (yay Intel byte reversal!).
I check through the code a bit, and even though it looks like the data segment is being initialized properly, it's still reading from the Program Segment Prefix. So, I find the Wikipedia article on the PSP and see that address 05h in the PSP has a cross-segment jump to CP/M compatibility code.
But, there's nothing at address DEAD (at least, nothing sensible). So I go searching through the DOSBox code for that string, and I find these lines:
// far call to interrupt 0x21 - faked for bill & ted
// lets hope nobody really uses this address
sSave(sPSP,cpm_entry,RealMake(0xDEAD,0xFFFF));
As it turns out, because DOSBox doesn't implement CP/M compatibility, they simply made it jump to DEAD instead, just to make sure that if anyone tried running a CP/M program they would get the picture. And the assembler just happened to put the variable in the right place that the load pulled the DEAD instead of random nonsense.I can only imagine the problems that can manifest when you're dealing directly with hardware, and don't have access to commented source code.
Change the linker script randomly (actual thing that has worked)
Change variable attributes from ‘private’ to ‘public’ at random (actual other thing that has worked)...
Changing stuff at random (without having any idea why you're doing it and without keeping track of what you've already done) isn't a very productive debugging strategy - it's more like an act of desperation. At least use the scientific method:
- Make a hypothesis about what might happen if you change X.
- Observe and record what actually happens.
- Think about why this could be, and then think about what experiment you could do next to get another step closer to the answer.
If you have a hard time coming up with a reasonable hypothesis, it might help to learn more about the system. In this case, reading the linker documentation to find out what the various options do could be more productive than just making random changes to the linker script.
If you haven't been faced with a mystifying bug where randomly futzing with things in the hope that you would find a change that had a reliable effect was the best hope you had of solving it then you probably haven't been programming long enough.
And I've dealt with lots of mystifying bugs. But my approach to debugging isn't trying random things, it's gathering more information in deliberate ways: reading the code, tracing code with the debugger, adding logging information if the problem doesn't reproduce under the debugger, running test cases that attempt to narrow down the scope of the bug, etc.
I've even debugged customer problems that I couldn't reproduce locally by looking at the code and deducing what execution path had to have occurred to account for the reported behavior. That's one situation in which you absolutely can't try random things to see if they work.
If I were truly making random changes, it would suggest to me that I had no understanding of how the system worked. If you do understand the system and its potential failure modes, then you can do better than random.
Now in your infinite and sagacious wisdom you've told us all how she should obviously have been able to debug this problem in a trice using your superior methods. Me, I'm happy to cut her some slack, and recognise that systems development can be a complete nightmare!
[1] http://chrononsystems.com/products/chronon-time-travelling-d...
(1) Go into the debugger and trace how the system got to the bad state it was in.
(2) Randomly change stuff and see if it fixes the problem.
After doing (1), you understand exactly what your code is doing and why. After doing (2), you may not even understand what the problem really was, or why it got fixed, or whether it's really fixed or just doesn't happen any more in this particular situation.
I've seen people debug using strategy (2), and when they give up and ask for help, stopping, thinking a while and employing strategy (1) will usually find the problem.
Needless to say that was a bugger to debug. We didn't believe what was happening until we literally saw a jar disappear before our eyes.
Sun fixed the problem pretty quickly!
I don't remember the exact code, but it was something like:
function clear_dir($dir) {
$contents = scandir($dir); // returns array of directory contents
foreach($dir => $file) {
if(is_dir($file)) {
clear_dir($file);
}
else {
unlink($file);
}
}
}
The function names may not all be correct, been a while since I PHP'dAnyway, so the code looks like it should work. The problem is the scandir function result includes . and ..
So my little function would see .., recognise it as a directory, and recursively call itself on the parent of the directory I wanted to empty. I lost a fair few files before I realised what was happening. Luckily I had back ups, as this was before I started using SCMs.