Everything I've ever written. It's awful. Don't look at it. Any of it.
You've seen things people wouldn't believe – so tell us your programming horrors
Shellshock. Heartbleed. That CCTV storage firmware with a hardcoded password. We've all seen some really bad code. Maybe that's just me. Given that many of our sysadmin readers have poured in tales of fixing impossibly broken servers for our On-Call series, we know our software-wrangling readers have faced similar battles …
COMMENTS
-
-
-
-
Friday 29th January 2016 11:47 GMT tfewster
> What are the other 11 steps?
There's probably a library of books and websites devoted to this, but in my experience:
Step 2: As noted by other commentards, leaving a comment saying "Kludge" or similar; Bonus points for pointing out situations where it will fail.
Step 3: A comment describing what you're actually trying to achieve; Best case, someone else will know how to fix it; Worst case, it will help you with Rubber Duck debugging. Nowadays I usually start by writing pseudocode anyway, so the comments are already in place.
Step 4: Review your assumptions: Will this code definitely be rewritten/replaced/binned before Y2K? Will it scale [so `if (a ~b)` doesn't come back to bite you when b > 9]?
(Step 1.5 should probably be "Don't call your variables 'a' and 'b' ")
Step 5:???
(Obligatory Step 6: PROFIT!!!)
-
Friday 29th January 2016 12:13 GMT BongoJoe
(Step 1.5 should probably be "Don't call your variables 'a' and 'b' ")
Ah, but there is, or was, a time when it was worthwhile to do so.
Many years ago I wrote code onto Hollorith Cards and if you recall these then there's basically one line of code per punched card. Sometimes the ladies in the card punch room would fail to read my handwriting on the coding form and type something slightly different.
And if this was the case then one had to find the card and replace it with one of one's own. Now there was a number of options available. The first was to go and put through the single card required through the system which could take a day or so (and the single card may get lost between the punch card room and oneself).
The second option was to go into an auxiliary room with a crufty old machine that one could stamp out the card for oneself. This option meant moving off one's arse and to use a machine which was, effectively, running off three phase mains with cloth covered mains cable and the machine, because the girls wouldn't touch it, would be a heath hazard. And in the 70s a Health Hazard was really a Health Hazard.
The third option was Cut And Paste. Seventies style.
If one purposely didn't use descriptive variables and just stuck to the likes of x and y then it would be simple enough to find a card from another application, borrow that and shove it into one's card stack in the right place.
Which really had a number of side effects. First this didn't lend itself to good naming conventions (which didn't exist in those days anyway) and, secondly, if one forgot or didn't even know that your code was tampered with then the debugging became a real nightmare.
Hollorith cards. That was real programming. Especially if carrying the deck of cards to the machine room and they fell out of their elastic band and spilled all over the floor requiring a massive sort run manually...
-
Friday 29th January 2016 17:41 GMT Brewster's Angle Grinder
>(Step 1.5 should probably be "Don't call your variables 'a' and 'b' ")
The first BASIC interpreter I used only paid attention to the first two characters of a variable's name. So the variables
STRENGTH
andSTUPIDITY
were both handles to the variableST
. For that reason, it was considered good practice to only give your variables two letter names so as to avoid unintended collisions.Even today, Chrome decides to inline based on the length of the text in a javascript function. But obviously, good practice is to minify.
-
-
Monday 1st February 2016 12:28 GMT Brewster's Angle Grinder
IIRC, Commodore BASIC as used on the Vic 20 and C64 had that first two character approach - though probably not the only version.
Right era. Difference device. This interpreter was written by a company based in Redmond -- giving me early warning of what to expect. All numbers were treated as floats, too, so performance was terrible; but it spurred me into learning asm.
-
-
-
Saturday 30th January 2016 11:54 GMT David Roberts
80 colum cards
Firstly you should have a hand punch with lots of 3 key combinations for one off cards - this makes it relatively easy to replace a defective card.
Secondly if you can't be arsed to punch a whole new card you just fish a chard out of the punch and block up the incorrect hole by rubbing the chard in with a soft pencil prior to punching the correct hole(s).
Thirdly you always mark up the card deck with thick diagonal lines from a board marker so you can get them (almost) back in order by eye.
Tcah. Kids of today.......
-
-
Monday 1st February 2016 18:43 GMT Number6
Step 3: A comment describing what you're actually trying to achieve; Best case, someone else will know how to fix it;
I often put assumptions in the comments. "At this point x, y, z should be the case" "Assumes argument non zero" or whatever. Sometimes it's because I want to go back and put in the error checking once I've verified that I'm on the correct track (i.e. go write it properly second time). This helps with debugging and hopefully provides some level of documentation for the poor sod who has to fix or upgrade it once I've moved on. Fond memories of spherical geometry and a few short cuts and assumptions based on the real world usage of the code here.
-
-
Thursday 28th January 2016 23:18 GMT Anonymous Coward
I've tried to get better but then in previous jobs I was working on code written by a dead man for a database that stopped being supported 10 years prior. (using asp and a foxpro db)
Oh how we laughed when the accounts system died again because 1gb databases aren't actually that big...
That and stored procedures are the Devils work (or at least that was the impression given that no data manipulation was ever done in sql until I started working on it).
-
-
-
Thursday 28th January 2016 15:39 GMT caffeine addict
The worst bit of impenetrable code I found recently was some 10 year old PHP that was mess of procedural code in classes, with meaningless variable names and recursive functions that sometimes took variables by reference, and sometimes didn't.
The comments block just contained an apology to anyone who came to investigate it. Signed by me.
I've stopped judging any code that's more than a year old...
Still, at least I wasn't responsible for the code that tried to connect to a server 3 times before giving up. But which auto-incremented the wrong number, causing a cascade of unresponsive servers DOSing each other...
-
Thursday 28th January 2016 15:48 GMT apepper
My "favourite" bug was in Z80 assembler; I'd written a subroutine which converted a string to upper case. Our strings had a two byte length followed by the actual characters, so the routine looked something like this (pseudo code).
toupper: ld len,(hl) ' get the length
inc hl
inc hl ' skip the length
toupper1:ld a,(hl)
cmp a,'a'
jlt isupper ' if not lower case
cmp a,'z'
jgt isupper ' not lower case
' must be lower case
sub a,('a'-'A') ' convert that character
ld (hl),a
inc hl
dec len
cmp len,0
jne toupper1 ' more to do...
ret
The routine worked fine until someone passed a zero length string to the routine; then because the code decremented the length before comparing it with 0 to see if we'd finished, the routine converted the entire 64k memory - including the code - to upper case. By chance, a lot of stuff carried on working, so it took a couple of hours to to realize what was happening.
-
Thursday 28th January 2016 16:36 GMT Phil O'Sophical
I remember something similar in a VMS Fortran program. VAXen had a block move instruction, somewhat similar in operation to the C memcpy() function. Someone (I think it might have been me, but I can't remember) got the source & destination addresses backwards. Instead of rotating a buffer by 4 bytes when that line was reached, it shifted the whole program address space *except* the buffer by 4 bytes. Neeedless to say the program crashed almost immediately, but the resultant stack trace was incomprehensible, since everything was 4 bytes off. It took ages to figure out what was happening.
-
Friday 29th January 2016 04:35 GMT Peter X
Re: Lower to uppercase
I appreciate that was probably very old code... but you do realise that changing case in ASCII is just a bitwise operation? You could probably speed up your old code ten-fold! :D
That said, I just did a Google and discovered people on stack exchange marvelling at such wonders. Makes me feel old!
-
Friday 29th January 2016 06:20 GMT richardcox13
Re: Lower to uppercase
> I appreciate that was probably very old code... but you do realise that changing case in ASCII is just a bitwise operation?
Only if it is truly ASCII: 7 bit encoding, nothing accented.
Once you need to deal with wider encodings or outside the USA then it breaks down.
Even if all the characters are unaccented it will not work (see Turkish I Problem).
-
Monday 1st February 2016 11:53 GMT dajames
Re: Lower to uppercase
I appreciate that was probably very old code... but you do realise that changing case in ASCII is just a bitwise operation? You could probably speed up your old code ten-fold! :D
If you know the input character is alphabetic you can force the case with the appropriate AND or OR instruction, but if your input can be any ASCII character and don't want to alter non-alpha characters you need to check that the input is in the alpha range. Once you've done that it makes no difference whether you use ADD/SUB or OR/AND to toggle the case bit.
-
Monday 18th April 2016 15:02 GMT apepper
Re: Lower to uppercase
Sad I know this, but it would be one clock cycle faster to use the AND as opposed to SUB to convert to upper case, we preferred to use the SUB as it made it more obvious. Similarly, we tended to use CMP 0 instead of AND A to check for A containing 0 although it was, again, 1 clock cycle faster. It was 34 years ago...
-
-
-
Monday 29th February 2016 18:12 GMT Alan W. Rateliff, II
I wrote an extremely simple screen blanker for the C64. The stupid thing would not fire and I suffered over it for a several hours, even re-writing it -- but not from scratch, as my impertinent youth advised me to re-use sections which I "knew" worked.
Turned out one of the sections which "worked" had a BEQ instead of a BNE, two completely different conditional outcomes. In my defense I was young and then learned a very valuable lesson about making assumptions during troubleshooting.
-
-
-
Thursday 28th January 2016 18:06 GMT itzman
Goto? What about longjmp()
Yep. one day I got to use setjmp() and longjmp().
I consider it very good coding style.
It was in a comms program, where the actual 'send a character and check coms still works' was nested ten subroutines deep. If comms failed there was nothing fr it but to shut the whole thing down and resend the message from square 1.
Sio te first thuinbg that
send message(int target, char * message) did was
if (error=setjmp(here)) return error;
then when my comms screwed up,.
longjmp(here, error); was my go to jail card..
Structured it ain't, but it makes for much easier to understand coding.
=======================
A weird one that had suchj a strange behaviours is worth mentioning.
A program I had written would crash. But only when the users were learning on it. Once they had learnt it was OK...
The cause? When they made an errors, the error handling forgot to close the file they were working on, and simply opened another one. and in those days DOS had a limited number of file handles that you set in CONFIG.SYS..
-
-
Friday 5th February 2016 11:51 GMT Sam Liddicott
Re: Goto? What about longjmp()
And don't capture a well defined set of any state.
Variables temporarily in a register (and pushed onto the stack) when longjmp occurs from some deeper function will have some stale value and not the value they seemed to hold when you called setjmp; so all variables you plan to use after longjmp should be declared volatile which is easy to forget.
If only all variables were evicted from registers before the call to setjmp - but what implementation does that?
Better to be quickest than right, apparently.
-
-
-
Friday 29th January 2016 08:02 GMT Voland's right hand
Apple's cut'n'paste blunder
Gotos are a way of life in C.
The error there is not the goto, not the double goto, but the lack of brackets around the if-ed operand. That is what is asking for a clusterf*** and what I have seen clusterf*** so often it is not even funny.
I usually prohibit it as "unacceptable coding style" internally and bounce any code which uses it at review. Bracket it, so it is clear what you are doing. End of story.
-
Saturday 30th January 2016 01:10 GMT Mike 16
Re: Apple's cut'n'paste blunder
I would agree that using braces for every conditional is a very effective defense. However, as a (former) Linux kernel programmer (drivers), I was informed that those braces are _forbidden_ if the body consists of a single statement. Not that I think Apple is using Linux, but the programmer may have developed that habit in a previous job.
-
Thursday 11th February 2016 10:52 GMT Kristian Walsh
Re: Apple's cut'n'paste blunder
Not that I think Apple is using Linux, but the programmer may have developed that habit in a previous job.
Odd.. My dim recollection of the old Apple C coding guidelines was that you were supposed to use braces after every conditional statement, regardless of how many statements it contained. Apple's Swift language copper-fastens this rule by requiring braces around conditional blocks, so the spirit of Codebert is still alive somewhere.
As a bonus example of "belt but no braces", I once tracked a bug to this seemingly-innocuous "line" of (not my) code:
if (state==-1) *result=2; return 0;
(stuff like this still isn't a good enough reason to attach semantics to whitespace, mind you...)
-
-
Monday 1st February 2016 19:59 GMT Anonymous Coward
Re: Apple's cut'n'paste blunder
Goto's are NOT a way of life with C.
You do not need them, they aren't necessary. See here (I know its old but still relevant)
https://files.ifi.uzh.ch/rerg/arvo/courses/kvse/uebungen/Dijkstra_Goto.pdf
I have managed to avoid ever using a goto in C in the last 32 years of being paid to write C programs. I still get paid remarkably well for putting C programs together as the young whipper snappers today know nothing of the "One True Language" and think they have to code in Java.
-
-
Wednesday 3rd February 2016 01:25 GMT el_oscuro
GOTO in assembly
When I was just starting in the 80's, I had to learn assembly because the crappy basic was too slow for video games and couldn't handle input correctly anyway. You would see goto everywhere in basic, and I carried that to assembly. JMP is your friend.. or not. You see, some of my subroutines had exit paths with JMP instead of RET. Of course, after playing my game for awhile, the machine would randomly go tits up when the stack overflowed. Took me awhile to run down that nasty little bug...
-
Wednesday 3rd February 2016 10:09 GMT Peter Gathercole
Re: GOTO in assembly
For non-structured basics, where the IF statement could only condition a single following statement, ELSEs were not available, and before procedures and when functions were so primitive they were basically useless, and the only conditional loop was FOR...NEXT, using gotos was the only way you could write code.
It took versions like GW Basic and BBC Basic (plus various versions on Mini-computers) to bring it into a relatively modern era.
People forget how simple Dartmouth and Basic-80/MBasic were!
-
-
-
Thursday 28th January 2016 15:57 GMT John Robson
rm -rf /etc /bin /usr
I managed to run the above, as root, on a solaris development server...
To be fair I did tell my boss that I shouldn't be doing that dev work on a development server, but on a test machine - but they'd run out of test machines...
The work? chroot jail manipulation...
The intended command: rm -rf etc bin usr
Which would have cleared up the chroot jail I didn't need any more...
The consequences?
A rather hasty test of the backups - or a reinstall, I genuinely can't remember any more (15+ years ago)
What I do remember was hitting return, then thinking "That's taking a bit longer than normal.... Oh Shit! Ctrl-C, Ctrl-C, Ctrl-C.. Aaaarrrgggghhhh. Fuck, Bother"