The Worst Bug I Ever Wrote
The worst bug I ever wrote happened on the first day of the project, and I still remember making the edit that introduced that bug.
During my second year of college, one of my friends got a 6 month “co-op” internship at IBM in Boca Raton. She came back with a ton of confidence, a long distance boyfriend, and a bunch of stories about working on real software. Up until that point, I’d been just trying to get through my classes. After her stories of freedom and paychecks, the idea of working someplace real felt like something I could - and should - do.
So I signed up for the U. C. Berkeley engineering school’s co-op program, sent out some resumes and waited for a response. The first place to get back to me was Unisys, a business computer manufacturer in Southern California that had just been formed by merging old-guard mainframe makers Sperry and Burroughs. Unisys flew me down to Orange County (first flight on my own, I think), put me up in a hotel, and brought me into the offices in Irvine for a day of interviews. My first interviewer wanted to give me a good grounding in what they made, so he led me through various machine rooms to show off the mainframe computers they built for banks and insurance companies. He showed off the A Series first - more modern computers suitable for modern computer languages. He then took me back to a separate machine room to see a larger B series computer. Stopping, he slammed his hand down on the case like a used car dealer eager to make a sale. “Now, this is a great COBOL machine!”
My other choice was a small software company in Berkeley: Berkeley Softworks. They wrote productivity software for the Commodore 64 microcomputers, making these cheap, discount-store computers behave like a Macintosh with a GUI interface - quite an amazing feat for an 8 bit processor and 64k of memory. The company published lots of big recruiting ads in the Daily Cal newspaper, and billed themselves as irreverent and exciting. Their offices, in the big "Great Western Bank" office building overlooking the Berkeley BART station, looked more grown-up than the suburban office park of Unisys, but the employees didn’t look corporate. Everyone was in their 20s and 30s, and most of the programmers were either recent Berkeley grads or undergrads working part time. The general feel was a little bit like fraternity brothers (several of the guys had been in one particular frat at Berkeley) with a good number of the usual Bay Area mix of artists and musicians looking for day jobs to pay the rent. A couple of the finance folks were my parents’ age, and one of the sales guys was an ex-Cal Bears linebacker who was always grinning and would practically push you out of the aisle when he came charging through the offices. The interview schedule also had a wild mix, from the “old-timers” (mid 30s) engineers pressing on machine code knowledge to two of the recent grads having a “cruise director” interview round pressing on culture and sharing stories about how much fun the place was, stories about the annual inner tube rafting trip on Cache Creek, and the various hijinks folks had been involved in. (A daily newspaper article on the company had commented that the employees looked young enough to be picked up by the truant officer, which supposedly led to the suggestion that they egg the reporter's house.) More importantly, everyone reminded me that Berkeley Softworks would give interns significant projects, working on creating new products on their own rather than just writing test code or working on someone’s pet experiment.
Needless to say, I went to Berkeley Softworks because it sounded exciting, challenging, and modern. The staff also seemed accomplished - many of the folks had worked at early video game companies. The company founders had actually been early employees and founders of Imagic, which made Atari 2600 video games like “Demon Attack”. They were all expert assembly language programmers on the 6502 processor who could write insanely optimized code. Once you’ve developed code in 4k of ROM and 256 bytes of memory for an Atari 2600, a Commodore 64 seems limitless.
Somehow I managed to pass their screening, and ended up in the summer-fall 1987 cohort of interns; I found a sublet apartment for the summer, got a clean t-shirt and jeans to fit the dress code, and showed up at the Great Western building. There were five software interns that June: Andrew and Brian (both Apple ][ programmers who were trading their “hacker names” that they’d used on pirate software bulletin boards), Augie, Byron, and me. Our first job was the standard startup task for new employees: build our own desks that the company picked up at the proto-Ikea down the street. We then spent a week or two learning GEOS, their operating system for their Commodore 64 software, and each of us chose and built our own sample project. I remember discovering the Commodore 64’s advanced sound chip (“SID chip”), and decided to build a GUI app in GEOS for designing sounds on the SID chip. I remember getting some nice feedback and compliments on the app, but I didn’t think of as more than a throwaway for learning. I’m surprised I didn’t get into digital music back then because of that project alone, but it didn’t stick. Someone asked if they could use it a year or two later to design some sounds for a new product, but I realized I’d already deleted it - even in those days, disk space was scarce.
In another case of dodging interests in electronic music, when I looked for a way to spend my first year’s savings from Berkeley Softworks, I was torn between blowing the money on a synthesizer - a Yamaha DX7, the cool, techie electronic music instrument - or taking the money and wandering around Europe for a month and a half. I ended up deciding to go for travel. It was the right choice in the end - the travel was great for building my independence. Sharing stories about that trip also led to meeting a future girlfriend. I’m still happy about the choice.
Once we interns completed our sample projects, we got our real projects. Byron and Augie were going to work on GeoBASIC, a graphical programming environment for GEOS - the equivalent of today’s Scratch. Brian, Andrew, and I got a more ambitious project: porting GEOS and its applications over to the Apple ][ computer so Berkeley Softworks could go after another computer market. We had six months.
Before going further, I ought to explain how Berkeley Softworks did software development. One of the competitive advantages of the company was developing software on UNIX computers, then using a device called an “in-circuit emulator” to load a test program into the memory of the microcomputer and see if it run. This was such a wonderful experience, and so different from how most software developers wrote microcomputer code in the 1980s. Most folks still wrote software for microcomputers on microcomputers. This was amazingly painful - the tools were primitive, floppy disks didn’t have much capacity for code, computers were slow to process code into executable form, and any hiccups in the program would reboot the computer with no chance to figure out what happened and with the risk of corrupting the program you'd just written. By contrast, working on UNIX meant we had access to UNIX editors like vi, utilities like Make, and megabytes of disk space. The in-circuit emulators meant that a misbehaving program could be interrupted and we could see where it had ended up. We could even set hardware breakpoints, watching the address bus for a particular memory location to be written or read!
As close as this might seem to 21st century development practices, it was still a primitive and resource-scarce time. Hard disks were new and expensive, so we didn’t have room for too many duplicate copies of files. We also didn’t have any kind of source code control to keep track of changes. In those days, source code control was a new idea, and little companies like Berkeley Softworks didn’t have explicit ways to do versioning - at best, folks made tape backup copies of software daily or weekly, though most folks didn’t have enough disk space for multiple copies let alone the overhead of remembering changes. We didn't do code reviews. We also didn't try to keep a single codebase for the C64 and Apple versions because of the size of the changes we expected. (Berkeley Softworks did keep a single codebase for the Commodore-related code - the Commodore 128 version of GEOS was controlled by #ifdefs in the C64 source code.)
So after we learned our project, the three of us wandered back to our desks and our UNIX terminals (24x80 green screen, no windows in those days!) to look at the Commodore 64 version, copy the files to make the starting point for the Apple ][ version, and start figuring out what changes we’d make. We broke up the work functionally: Andrew was going to work on graphics and the drawing program; Brian would work on fonts and the file browser, and I’d work on the core operating system and the word processing application. I also ended up picking up modifying and extending printer drivers, which deserves its own stories.
So, on that first day of the project, I made a copy of the Commodore 64 code in a new directory, and started reading through the code to figure out where to start. The first thing I saw was the list of constants - symbolic names for constant numeric values. The code at the top of the file looked like this in 6502 assembly code:
;; Boolean values used in GEOS
TRUE = -1
FALSE = 0
“Huh, that’s wrong! On UNIX, TRUE is always defined as one, not negative one! “ I remember changing the code in the define from the incorrect TRUE value to the one certain and true TRUE value from UNIX. With that change, we went off and started working on the Apple ][ version of GEOS.
A year or so after Apple GEOS shipped, I was sitting at my desk helping out on porting our spreadsheet program from the Commodore 64 GEOS to the new Apple GEOS. I noticed two engineers headed straight for my desk - our tech writer and the software engineer working on GeoPublish, our desktop publishing program. “Hey, Robert- here’s a question for you. On Commodore 64 GEOS, TRUE is defined as 255, but on the Apple ][ version, it’s 1. Any idea why there’s a difference?”
“Oh, yeah, I changed that on the first day because it was wrong….”
Oops. It took a year and a half for anyone to notice the change. Most people, when comparing a value for truth or falsity would compare a value to true or false:
;; Test whether drawing is in progress, and skip if so.
LDA $DrawingStarted
CPA #$TRUE
BEQ DrawingAlreadyRunning
Here, the programmer loads the contents of the memory location holding the DrawingStarted variable into register A, then compares it to true. The compare instruction will set various flags in the processor’s status registers - whether the last value compared is zero, if it’s equal or not, etc. The BEQ (“branch if equal”) checks the flag state, and if the equal flag is set, then the computer will jump off and start executing the code at DrawingAlreadyRunning.
That’s not efficient because “CPA #$TRUE” is a two byte instruction, one byte for the instruction “compare against A” and a second byte to hold the constant value to compare (#$TRUE). And, of course, the hot shit programmers at Berkeley Softworks learned their trade working on video games with exactly 4,096 bytes for instructions. They wouldn’t waste a byte of program space. A more efficient way to write the code is to just decrement the value to set the flag, then check whether the value went negative (decrementing 0 leads to 255, or -1).
;; Test whether drawing is in progress, and skip if so.
LDA $DrawingStarted
# Decrement A. If it’s false (0), then decrementing will set the carry flag.
DECA
BCS DrawingAlreadyRunning
The “decrement and check for carry” worked whether TRUE was 1 or negative one because it was testing whether something happened when changing from 0 to 255. But the GeoPublish programmer had done a slightly different comparison, equally efficient:
;; Test whether drawing is in progress, and skip if so.
LDA $DrawingStarted
# Increment A. If it’s TRUE (-1), then incrementing will change the value to 0 and set the ZERO flag.
INCA
BEQ DrawingAlreadyRunning.
That code most certainly did not work the same if TRUE was 1 - the increment would change the value from 1 to 2, and the zero flag wouldn’t be set.
Luckily, GeoPublish was the only place where such code lived. We couldn’t change the definition now - we had no idea where in the Apple GEOS code we assumed TRUE would be 1. The GeoPublish engineer instead just changed his code to do a different comparison on the Apple ][ and Commodore 64. It wasn’t too traumatic a bug, but Matt the tech writer did have to leave an unpleasant note in the programmer’s guide, explaining how TRUE had different values on the different computers.
And I learned (1) don’t change things I don’t understand, and (2) choices I make years in the past might creep up and bite me one day.
And that’s the worst bug I ever did, making an assumption on the first day of a project and my first real big day as a programmer. I’ve written bugs in code since then, but I still remember changing that value of TRUE forty years later.



Hi Robert, thanks for reminding me of the really raw development back in the days! My first professional job was developing on the Apple 2 in 6502. I actually did do development on the Apple itself.
ReplyDeleteGlad it brought back memories of assembly! Those days likely made better programmers of us in later years - I know the knowledge of coding "down to the metal" helped me when I was working on firmware for a network co-processor. But I'm saving that story for later.
Delete