Analyzing The BASIC Bug
Last month I showed some ways to minimize the problems caused by the bugs in revision B Atari BASIC (the built-in BASIC in the 600XL and 800XL). But many of you are curious about exactly why these bugs happen, and what effect they can have on your programs.
Let me begin by telling what did not cause the error. Rev B BASIC has a peculiar problem: Each time you LOAD (or CLOAD or RUN "filename") a program, rev B adds 16 bytes to the size of your program. If you then save the program, the next time you load it in it grows by another 16 bytes, and so on.
Now believe it or else, these additional 16 bytes were put in deliberately. It seems that there is a minor, undocumented bug in the Atari S: (graphics screen) driver. Under some circumstances, it will use a few bytes below MEMHI (contents of locations $2E5–$2E6, 741–742 decimal). So, if you have a program which extends right to the very top of memory, you can wipe out a little bit of the runtime stack where GOSUBs and FORs are remembered. Somebody at the old Atari apparently had the bright idea that if BASIC told you that memory was full when your program got within 16 bytes of MEMHI, the screen/BASIC conflict could be avoided.
A Fix Gone Sour
Pretty good idea. Except for a few problems. First, BASIC doesn't save the string/array space of the runtime stack; both are created when a program is run. So the nice fact that the saved file is guaranteed to have 16 bytes of space left is negated as soon as you DIMension a string or an array or use a GOSUB or FOR. Second, the 16 bytes are added to all of BASIC'S size pointers before the comparison with MEMHI is made. Good. But the newly increased value is then stored as the new pointer value. That effectively moves the program upward in memory by 16 bytes, meaning that the desired 16 bytes of free space aren't there anyway!
Well, the point of this digression is twofold: (1) This is yet another reason to use LIST and ENTER with rev B BASIC, since ENTERing a program does not trigger this silly 16-byte bug. (2) Several people wrote and suggested that this 16-byte bug is what causes the infamous keyboard lockup bug. Sorry, folks.
Last month, I mentioned the detailed explanation of the rev A Atari BASIC lockup bug which is to be found in COMPUTE! 's Atari BASIC Source Book. Well, apparently somebody at Atari read the book. Or maybe they just noticed that my company had fixed the lockup bug in one of the three or four revised versions of BASIC that we did for Atari back in 1979 (yes, that's 1979). It turns out that the lockup resulted from two missing instructions (and a total of two bytes) within the routine which "contracts" memory. (We say "contracts" because it is used when you delete a program line, so the program is contracted in size.)
Then that same somebody looked at the "expand" routine and saw almost identical code. "Aha!" they say, "Methinks there is a bug here which just hasn't been discovered yet!"
If It Ain't Broken …
But they were wrong. The reason the bug appeared in the contract routine is because that routine was written after the expand routine and copied its pattern too closely. So our unknown someone at Atari blindly added code to the healthy expand routine and introduced a very nasty new bug. In fact, because this bug appears when you add lines to an existing program, it is probably more likely to occur than the original rev A bug!
To see a demonstration of the bug, enter the following statements in direct mode (without line numbers):
DIM A$(249) A$="ANY STRING YOU LIKE" PRINT A$ PRINT A$, PRINT A$,
The last two statements won't print A$ properly in either rev A or rev B Atari BASIC—in fact, they'll mess it up two different ways. Cute, eh? The problem is that tacking that comma on the end of the PRINT statement moves the string/array space (and thus A$) by one byte. Except it doesn't, really, so the variable value table address of A$ points to the wrong place in memory! Imagine your program being destroyed in a similar way. Is it any wonder you experience keyboard lockup and scrambled listings?
What former Atari employee did I bribe to get all this information about the bugs in rev B BASIC? Did I get the listing on a microdot hidden in a pack of blank disks? Sorry to disappoint you, but I did what any other hacker would do: I dragged out my trusty machine language debugger and carefully disassembled certain portions of rev B BASIC.
Finally, here's how the two bugs we have discussed were fixed in rev C BASIC, which is built into the new XE series computers (and also is available for older Ataris on cartridge at nominal cost—see last month's column). Since both bugs were caused by adding things to code which worked before, you would think that Atari could simply take the "fixes" back out. Nope. Instead, they patched over the extraneous instructions with what are effectively NOP (NO oPeration) instructions. Tacky? Well, I've certainly done it to DOS here in this column enough times, so who am I to say?