- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
You mean this: http://www.worldreligions.ca/blog/news/2006/10/gurus-cat.html
Admin
Admin
At least he thought of the children.
Admin
Admin
Holy Crap! Back in the bad old days when you didn't have a decent editor that would show you that kind of thing, that would be just freakin' evil. He deserved a serious smack upside the head.
Admin
MrHen: If the status is to be used as a unix exit code, it's correct to use 0 to mean success and non-zero to mean failure.
You guys keep talking about the compiler barfing... I don't even use C so I had no good excuse for not actually trying it :-)
I used gcc 4. If you don't pass -Werror, you get a warning but it produces an executable just fine. Which segfaults, of course :-) Now, pared down to nothing but the dead code:
#include <stdlib.h>
typedef char Node;
void traverseGroup( Node *peer, Node *parent, Node *children[], int n ) { free( peer ); free( parent ); free( children ); free( n ); }
int main() { Node *peer = "milton"; Node *parent = "bob"; Node *children[2] = {"michael bolton", "samir"}; int n = 2;
}
pw@sweetums $ gcc wtf.c wtf.c: In function 'traverseGroup': wtf.c:11: warning: passing argument 1 of 'free' makes pointer from integer without a cast
pw@sweetums $ ./a.out Segmentation fault
But hey, that's easily fixed, we can get rid of that annoying warning by changing just one line:
There, problem solved!
pw@sweetums C $ rm -f a.out pw@sweetums C $ gcc -Werror wtf.c pw@sweetums C $ ./a.out Segmentation fault
In fact, we never get as far as free(n), it segfaults on the call to free(peer).
Moral of the story: -Wall and -Werror are your friends.
The other moral of the story: Even your best friend can't stop you from being a f***ing idiot.
Admin
Admin
Or, for that matter, once.
Admin
If it were up to me, I'd set the pragma to allow unused arguments, or just not name them (type, but not name).
Then I'd go find out why the call was designed with unused arguments, and beat some sense into the people maintaining it.
Admin
The thing I like is that they have the operands to == reversed, so they obviously have programmers who care about code quality and have maybe even read a few books on the subject. Yet somehow, they managed to avoid having the compiler warn them about dead code, or chose to ignore those warnings.
Admin
I'm no professional, but wouldn't the obvious way to make the compiler shut up be either commenting out the declaration of the unused variable, or even deleting it altogether if it's not going to be used?
Those compilers have become so smart these days, that "using" the variable after a return statement will just result in "dead code" warning at a sufficient warning level.
By the way, what kind of a data structure are we dealing with in the first place. How come parent and children have separate pointers that can be accessed and freed independently? How can parent be freed before children (assuming they are somehow related). And wouldn't it normally be a parent's responsibility (and purpose) to know where the children are?
Admin
Oy! OK, I'm not going to point fingers, but some people have forgotten their C pointers.
Node aNode; Node nodeArray[] = { /* whatever */ };
&aNode is a Node* nodeArray is a Node* &nodeArray is a Node** &nodeArray[0] == nodeArray, and they're both Node*
Admin
Finger pointer! Hah, I kill myself
captcha: alarm. Always disable
Admin
This is all just a trick so that when they are debugging, they can move the PC down to the unreachable code, slap some values in the variables, and use the debug step function to free up whatever they need, then reset the PC back into the main logic of the function. Continue.
Actually, I think the compiler warning threads are probably a better bet.
Thank goodness the IDEs I have been using the last 8 years allow you to type arbitrary code whenever and wherever you want it. Highlight, right click, "Execute".
Whippersnappers just don't know what it was like in the old days. Okay, I have to admit it, I missed using punch cards in school by one year.
Admin
Nooo that code was wrong!
It should be
free ( freddie_mercury );
Because, he wants to BREAK FREEEEE!!!
Hm... somehow I remember my data structure class. I still remember those dudes that free()d the root element from an AVL tree. Oops!!!
Admin
If you have unused local variables, delete them.
If you have unused function arguments, remove them if that makes sense, otherwise do this:
int useless_function(int useful_arg, int /* useless_arg */) { return useful_arg+1; }
And the compiler will be happy. And no ugly hacks.
Admin
Ooooooooohhhhhhhhhhhhh - back way when the early C compilers in SUNOS 4.1: one could dance samba on the keyboard whilst running vi, save the resulting file with .c -extension and it would compile .... sometimes you'd get a warning, though.
So this is maybe really code ...
Admin
Ah, I guess he was also a master of some of the techniques listed here: http://thc.org/root/phun/unmaintain.html ? :)
Namely, the "Camouflage" section.
Admin
Did you check the size of the code base with all comments stripped ? Might have had something there.
Even with syntax highlighting: the example is almost evil and surely grossly negligent.
IMHO, comments are like speeches at family functions - unimportant for most of the rest of humanity and the shorter the better.
I usually omit them - they mar the beauty of pure code.
Admin
The convention comes from Unix, where a process could return any of a number of error codes. Zero is a convenient standard for "no error", and since main() is the developer's entry point in most cases, main() usually follows the same standards.
The confusion comes when you start defining functions that create objects. Now its more convenient to return zero as failure (null pointer) and non-zero as success (pointer to object) -- especially in languages where the runtime provides an exception handling mechanism so that error codes aren't needed anyway.
This is why we name constants...instead of "if (ret_value)..." we say "if (ret_value==kSuccess)" or something similar.
Admin
If they were trying to free the local variables, they should have passed pointers to them. As in: free( &peer ); free( &n );
Free() is not the same as the delete operator.
Admin
Interestingly, fork() works the same way -- though I've never been able to find out what each of the error codes means... I always just run fork() in a while loop until it returns zero.
Admin
Let's say the developer wasn't clueless about how to properly free up memory allocations and how not to create dead code, and say he coded this function to work exactly as he intended. He would have created a function named "traverseGroup" (which walks a tree presumably) that has the SIDE EFFECT of deallocating the tree it just traversed. That's a big WTF right there!
Admin
ouch, that's just evil
Admin
i.e. casting can be done between any types, even between pointers and non-pointers. Whether the results are in any way useful is highly unportable and sometimes undefined - pointers and ints aren't necessarily the same size, after all - but syntactically and grammatically it's perfectly fine. (In contrast, languages like Lisp and Ruby are dynamically and strongly typed; variables can hold any type but one type can't be cast to another.)
The main problem with the original code is indeed free(n), of course. Again it's syntactically valid, although the compiler would likely issue a warning about passing free() an argument of the wrong type. But it's semantically suspect, because except in really pathological cases, n will not happen to correspond to a memory address that was allocated by malloc(). That's a sure-fire way to get a segfault (or the equivalent on the system at hand).
Admin
Almost all C compilers will flag this as a warning. It's allowed in straight C though.
So the programmer also exhibits the common mistake of ignoring compiler warnings.
Admin
I should add, free(&n) won't work either. n is allocated on the stack, not the heap. The only valid arguments to free() are addresses previously allocated with malloc(), and neither &n nor (probably) n fit the bill.
I think the most probable explanation is an inexperienced programmer who didn't quite understand what it means to "free your memory".
Admin
um... actually, fork returns the child PID to the parent process and 0 to the child process. running it in a loop would lead to infinite spawning. probably not something you want.
Admin
No, it is not.
Admin
Oh, man, what's your hangup? You're bummin' my trip. Like, you're too heavy. Lighten up. Tune in, turn on, drop out. Stop being a shill for The Man. Peace.
Admin
Admin
The real WTF is that the function has two exit points, and he only cleans up after the second exit point.
Admin
This crashes because you're trying to free statically allocated memory. More specifically, you're trying to free memory not given to you by malloc/calloc/realloc, which is an error on your part. Now, despite all of the WTFs in the article, we don't specifically know he's doing this particular one (congratulations, you've managed to add one). Once you fix this, then you can proceed to the undefined behavior of trying to free(n).
Admin
It's also not a rule for "C". The rule applies to any language that has dynamic allocation - including C++ (though some C++ code can bypass this by inefficiently copying data as its passed around). Any exceptions have to be well documented.
Admin
I'd rather have a free(sub)...
Admin
Admin
Not a good idea. Our beards might catch on fire.
Admin
Also, the "var = var" style does not always work; such as when var is a constant. Even the syntactically correct "var;" statement doesn't always remove the "unused parameter" warning. I've had compilers complain if I leave off a parameter name, so that technique doesn't always work either.
There isn't a portable solution to get rid of the warnings. The tedious solution is to change the compiler options (thus pushing the problem off to whoever maintains the build systems).
Admin
Thank you, Captain Obvious! (wow, never thought I'd have a completely valid reason for saying that!) ;)
Admin
That one's all over the place: http://www.google.com/codesearch?q=%22free%28dom%29%22&hl=en&btnG=Search+Code
Admin
Admin
In C++, yes...
But I'm afraid that is pure C, with as many errors and warnings disabled as possible (what are they good for anyway?).
free(n) will just push the value of n on the stack and call free. Who cares if it's a pointer at all? If this code was ever live, it should have caused quite a number of segfaults or aborts.
Typically, yes, unless ints and pointers aren't the same length, in which case even funnier things can happen. (with funny as in "this smells funny")
Admin
I'm sorry, I posted the wrong thing and now I can't delete it. :-(
Admin
free(YourMind);
free(Hat);
free(Coke_With_Your_Burger);
etc.. ;-)
Admin
free(lunch);
Error: No such thing.
Admin
My eyes, they burn!
Admin
I had to read that comment twice to catch that (the first time through I thought you were complaining about his "very long comment"). What a bastard!
Admin
Blah. This is why no one uses C any more.
Admin
Admin
Ummmm. Why not just remove the unused variables ... or comment them out if they are associated with commented out code that you might re-instate (don't like it but some people use it for testing) ... or put them in a #ifdef block if you have some platform specific code #ifdefed elsewhere. I can't see any reason just to keep them.
Edit: Oops - I was thinking you were discussing local variables. Teach me to look at this site so late.