Now, when I make a programming mistake with pointers in C, I get a nice segmentation fault, my program crashes and the debugger can even tell me where it went wrong.
How did they do that in the time when memory protection wasn’t available? I can see a DOS programmer fiddling away and crashing the entire OS when he made a mistake. Virtualization wasn’t available, so all he could do was restart and retry. Did it really go like that?
4
I can see a DOS programmer fiddling away and crashing the entire OS when he made a mistake.
Yeah, that’s pretty much what happened. On most systems that had memory maps, location 0 was marked invalid, so that null pointers could be easily detected, because that was the most common case. But there were lots of other cases, and they caused havoc.
At the risk of sounding like a geezer, I should point out that the current focus on debugging is not the way of the past. Much more effort was previously made to write correct programs, rather than to remove bugs from incorrect programs. Some of that was because that was our goal, but a lot was because the tools made things hard. Try writing your programs on paper or on punched cards, not in an IDE, and without the benefit of an interactive debugger. It gives you a taste for correctness.
6
Back in my day, we didn’t have memory protection and all that snazzy business! We used printf to determine where we were in the program, and we liked it!
Though in all seriousness, it usually meant we were just more careful. Where malloc is called, there had to be a free somewhere else in the program, and such checking was rigorous because in the case of a problem, as you’ve clearly pointed out, segmentation faults are not helpful errors.
In the case of such errors, the best you could do is try to understand when such segmentation faults occur (using printf) and, looking at the code, determine why access to memory at that point was not valid and work backwards from there.
In essence, the same thing happens today, except we use debuggers to determine when errors occur, but you still have to understand why it happened, and it isn’t always as simple as finding the line in which the error occurred. Errors cause errors like a chain reaction, and if you were a C programmer in those days, you spent 20% of your time coding and the rest of the time pulling your hair out fixing bugs.
3
well ..
a segfault is a really nice indicator that something is wrong but you still have to find the root cause. So if you ask the question how do you find the root cause than the answer is not much different today than it was then. Of course the languages and tools became easier to work with but the general taktik is the same:
- logging helps to find the area where your problem is. Binary search printf is a form of it.
- debugging, step by step, break points and watches
- refactoring to get a better understanding
- staring hard at the code
- look at the memory / core dump
- feeding it with different data
- showing it to other people
- switch to a language without pointers (and a new set of problems)
…
On a more abstract level you have three approaches:
1. work with the code
2. look at the program while it runs
3. look the results after it did something stupid
btw a pointer error does not have to create a segfault.
As a Amiga programmer I used pretty much all of it.
And yes restarts where common practise.
On the IBM 360, running Fortran batch jobs, we used to get hex core dumps. Such a dump could be as much as an inch thick of fan-fold green-and-white printer paper. It would tell what the registers were, and from there we could backtrack and figure out what the program was doing. We could find each subroutine and figure out where it stored its return address, so we could see the context. It would help to have an assembler listing of the program.
Once I was working on bugfixing on a then famous Windows 3.1 Presentation software.
I had a bug which, when it occurred, caused the Blue Screen of Death.
The bug only occurred when a certain loop had been executed over 1000 times. I used the advanced features of the debugger to let a break point pass 1000 times and then I carefully stepped through the program. Every time I went too far or skipped over a function call which contained the bug Windows Blue Screened.
Finally, after several days of work, I narrowed it down to a function that was running out of memory and instead of displaying an error message, appended the error message to a buffer. With every subsequent iteration it trashed more memory until something crucial was overwritten and Windows was trashed.
Debugging skills and perseverance was the solution.