Bug In the GnuTLS Library Leaves Many OSs and Apps At Risk
New submitter williamyf writes "According to this article at Ars Technica, '[A] bug in the GnuTLS library makes it trivial for attackers to bypass secure sockets layer (SSL) and Transport Layer Security (TLS) protections available on websites that depend on the open source package. Initial estimates included in Internet discussions such as this one indicate that more than 200 different operating systems or applications rely on GnuTLS to implement crucial SSL and TLS operations, but it wouldn't be surprising if the actual number is much higher. Web applications, e-mail programs, and other code that use the library are vulnerable to exploits that allow attackers monitoring connections to silently decode encrypted traffic passing between end users and servers.' The coding error may have been present since 2005."
Posting to undo moderation.
"Open Source Software is more secure because the code can be reviewed."
That's why this bug has existed since 2005. gg, guys. Thumbs up.
...who has been surreptitiously using GPL'd code in their proprietary stacks...
Thank god it is in gnuTLS that is not used by any applications serious about security. Just checked, only printer drivers seems affected in my Debian installation.
Just waiting for Microsoft's "Goto Fail" bug to surface. It may be too early to thank Snowden, but I'm starting to think I will have to at some point.
From February 16 2008: Howard Chu of OpenLDAP: GnuTLS Considered Harmful
Looking across more of their APIs, I see that the code makes liberal use of strlen and strcat, when it needs to be using counted-length data blobs everywhere. In short, the code is fundamentally broken; most of its external and internal APIs are incapable of passing binary data without mangling it. The code is completely unsafe for handling binary data, and yet the nature of TLS processing is almost entirely dependent on secure handling of binary data.
Incredible that GnuTLS is used anywhere at all. It's just mind boggling.
I have always been critical about that conventional wisdom of "With enough eyeballs, all bugs are shallow".
I contend that is inacurate. With enough QUALIFIED AND MOTIVATED eyes, all bugs are shallow, and sometimes, some FOSS project lack enough Qualified eyes.
This bug, the KDE one, or even the Metafile bug in windows (and more importantly in WINE) among many others, show that many eyes are not enough.
Again one needs MOTIVATED AND QUALIFIED eyes AAAAAND good QA and test cases.
Cheers
*** Suerte a todos y Feliz dia!
It has gnu in the name. RMS is easily confused for the guy with the beard that people follow with religious vigor.
The bug requires a carefully-crafted certificate. That certificate will verify as valid and trusted when it should not be. The connection will still be secure, it will just be with an untrusted person.
So basically it allows a very dedicated attacker to forge a cert and become a MitM attack.
We all know governments have done this for years. It is widely known that root CA certificates have been violated by spy agencies. A few searches on Google will show bunches of news stories where attackers (all types, government attackers, ID theft attackers, etc) have made fake certificates, abused the CA model, and engaged in similar MitM attacks to what this allows.
SSL/TLS communications are just as secure as they always were. If you have personally verified and trusted the certificates the attack wouldn't work, it is only when your trust model allows a cert that you don't personally trust to be used in authentication, and even then it still allows a secure connection but to a wrongly-trusted individual.
The flaw is the trust model and using a cert that you don't personally trust to be valid, which is a well-known issue.
//TODO: Think of witty sig statement
No the issue was with conditionals and braces. The same issue would have happened even if it were two return statements .
I'm not sure if only "many eyes make bugs shallow" is enough, but that also professional, thorough code audits (like OpenBSD does) are needed to produce the most secure open source software. Any comments?
"given enough eyeballs, all bugs are shallow"
Apple had their goto bug in TLS for about 18 months before they spotted it.
GnuTLS and therefore Linux has had their goto bug in TLS since 2005 (9 years) and it's only been spotted now as a result of the bow wave from Apple's disclosure.
First, and yet another OSS-releated security risk :(
At least they are rare enough that it is news worthy. As compared to Windows where new exploits hardly ever get any attention because they are so frilling common as to be passé.
---Saying gnome 3 is better than windows 8 not so much a compliment as it is damning with light praise.
No the issue was with conditionals and braces. The same issue would have happened even if it were two return statements .
And a return statement before the end of a function is essentially a goto. A language that takes the step to rule out gotos should also not allow early returns.
Testing is hard. The tools you have make it even harder.
How do you build a bad certificate? Fuck, using the openssl tools is hard enough. Does anyone who uses them really understand WTF is happening? I know I don't - I just follow the instructions.
How would you go about building a bogus cert? Beats me. I'm pretty sure you can't do it with the standard tools. And who the heck is going to write their own cert building tools?
And yet, this stuff is at the core of transport security.
Both these bugs are caused by people using 'goto' like morons. Using 'goto' should start throwing compile-time errors to start forcing people off this relic of flow control.
Problem there is that it would break very old programs that just need recompiled and thus require a rewrite. A better way would be to have it disabled in the compiler by default so you have to enable a flag to override it so you are aware that it is there.
---Saying gnome 3 is better than windows 8 not so much a compliment as it is damning with light praise.
Next, you'll be coming for my trigraphs and pointers. My precious.
Hot on the heels of Apple's SSL/TLS implementation "flaw" across all stacks, and the Snowden revelations of NSA infiltration for weakening crypto?
You don't have to be wearing Tin Foil, just to become a little suspicious...
"Flyin' in just a sweet place,
Never been known to fail..."
Yeah, force people to write a big pile of nested bracket spaghetti and manually back their way out of every case. Make them introduce a bunch of otherwise useless flag variables and extra conditional statements to keep track of it all.
The best part of it all: When all that extra obfuscation causes bugs, it would be harder to pin the root cause on a simplistic generalization like "goto === bad".
This is why you should always roll your own SSL scripts in php like the guy at Magic the Gathering Online Exchange did.
Some drink at the fountain of knowledge. Others just gargle.
An awful lot of stuff links to it. Browsers, flash, everything that dials out uses it on xubuntu. Are you saying that they are linking to it, but not using it? Or are they linking to it and then its using a wrapper to openssl.
xubuntu appears to depend largely on the package that "everybody knows is shit".
This does not make me happy.
Because if they were, the headline would have been zOMG mac and iOS not safe !!!!!!!11!!!!
Yeah, force people to write a big pile of nested bracket spaghetti...
1. "nested brackets" (blocks) are by definition not spaghetti. Spaghetti is exclusively the result of gotos and their control equivalents (like the early return).
2. Nested blocks are refactorable into smaller functions. That's the way to cut them down to size, not to use gotos.
I mean really! People still trying to argue with structured code in 2014! You'd think it was still the 1980s.
This bug wasn't found from being open source. Those "many eyes" missed this bug for nearly a decade. Security testing tools uncovered incorrect validation behavior in the compiled library, just like they would with a closed source library. The only difference is that the public can see the incorrect code and correct it immediately; that is what you should be citing as an advantage of open source.
The OpenSSL license is not compatible with the GNU General Public License.
Does Objective-C allow early returns?
One thing I found interesting about the comments on Ars Technica about this article is that all comments regarding the (apparent) fallacy of open source allowing quick detection and turnaround of bugs tends to get very highly positively moderated, whereas the ones that argue that closed source software tends to limit the detection of such bugs and encourages sweeping detected bugs under the rug as much as possible get negatively modded or labelled "controversial".
One person even said this:
Said comment was modded quite well. Yes, things like this get a lot of attention and look bad for the open-source movement, but keep in mind that open-source/free software is fully transparent. No-one can hide the details with FOSS, something that is far easier to do with closed source software. That level of transparency make it appear as though open-source has more bugs for longer. No-one outside of Microsoft and very select partners are able to audit Windows or Office. And yet the closed-source software is more secure?
It boggles the mind a tech site like Ars Technica can be so pro-closed source and anti-open source despite what I'd assume to be populated with geeks who should know better.
Account abandoned. I can't fucking spell for shit and Slashdot doesn't even allow time-limited edits of posts. Plus you'
Is everyone racing to change their passwords?
Nested blocks are refactorable into smaller functions.
And the program eats the function/method/message call overhead, the overhead of passing all local variables as arguments, and the overhead of constructing and destroying an object through which to return multiple values from each function call.
Wow, have you ever actually written production code? Just wow.
There's nothing cleaner than
if (input1 == null) {
return ERROR("input1 was NULL");
}
if (input2 == null) {
return ERROR("input2 was NULL");
}
if (input2 == null) {
return ERROR("input3 was NULL");
}
Substitute "throw new ERROR(..)" or "goto :error" depending on what kind of code your writing, it's the same thing any way you do it.
Nesting three levels deep before you even start to write real code? Garbage.
Socialism: a lie told by totalitarians and believed by fools.
Try to remove that library, and you find that most of the critical software depends on it.
May it also be, the "coding error" was not an error at all, but a deliberately introduced bug? Government agencies always wanted to read our — and each other's — communications. Sometimes even for legitimate reasons...
In Soviet Washington the swamp drains you.
So when Apple's proprietary encryption software suffered a problem, Apple users could do nothing but wait for Apple to deliver a fix; there's nobody else that are allowed to fix Apple's proprietary software but Apple. And when that fix ostensibly arrived, Apple users had to hope it wasn't bundled with some malware too (as is often in proprietary software).
This bug was caught during an audit—"The vulnerability was discovered during an audit of GnuTLS for Red Hat.". Nobody but the proprietor can audit proprietary software. But with free software, users have the freedom to audit the code they run, patch that code, and run their patched code; users can choose to fix bugs themselves or get someone else to fix bugs for them. And users don't have to always trust the same people to do work on their behalf. Users can also choose to wait for a fix to be distributed, and then they can choose to check that fix to make sure it doesn't contain malware. For all we know some users have long spotted and fixed this bug in GNUTLS. Since all complex software has bugs bugs are unavoidable. We're better off depending on people we choose to trust. Software freedom is better for its own sake.
Digital Citizen
1. "nested brackets" (blocks) are by definition not spaghetti.
I called it spaghetti because the resulting mass of brackets looks just like a big steaming dish of spaghetti, and the extraneous control statements are almost as annoying as gotos to more than a single "error" label.
Nested blocks are refactorable into smaller functions. That's the way to cut them down to size, not to use gotos.
Some are, some not so much. Many situations call for a long list of sequential checks, which can be cleanly and clearly coded as a bunch of if .... return statements. If you put each case in a function you still have the following problems:
- If you do it the obvious way, you still need a deeply nested if-then chain. You haven't solved the problem.
- If you put each check within a function and daisy-chain them, you get creepy action-at-a-distance. It's not clear to the reader that you made a whole bunch of functions that should only be called from one place, and that they must be daisy chained.
I mean really! People still trying to argue with structured code in 2014! You'd think it was still the 1980s.
You seem hung up on definitions. If you narrowly define structured code as code that lacks return, break, continue and exception statements (which can all be used to break out of your "structured" sandbox), then plenty of people would argue with it in 2014.
The main problem with early exits is using them in C. But C is such an unsafe language in general, that's really the least of your worries. Other languages provide nice features like automatic destructors and "with" statements that make early exits perfectly reasonable.
try removing that package from your system.
On mine, it warned about *a lot* of software that have it as an indirect dependency.
It's a fork of a 15yo fork of Red Hat.
Proper C-style code depends heavily on the "goto :cleanup" pattern. You either write all exception-safe, all the time (not in C, obviously), or every function "allocates at the top and frees at the bottom".
Socialism: a lie told by totalitarians and believed by fools.
BTW, that code still returns from the middle, which is the pattern under discussion.
Seriously, it's quite common in production code to need to deal with bad input cleanly at the top of every function;
void Foo(int *low, int *high, char *name)
{
if (low == NULL)
{
return ERROR_PARM1;
}
if (high == NULL)
{
return ERROR_PARM2;
}
if (*low > *high)
{
return ERROR_PARMS;
}
if (name == NULL)
{
return ERROR_PARM3;
}
That's the single most common pattern in all the code I've seen, whether it's return, throw, or goto :cleanup, you have to do something uniformly for bad input, and one way or another that "something" is "give up now, don't enter the real logic".
Socialism: a lie told by totalitarians and believed by fools.
The GPL has an exemption for linking with libraries that are part of the operating system.
OpenSSL is not part of the "system libraries" on all platforms. Programs would have to have some sort of shim layer to use either OpenSSL on platforms with it or something else on platforms without it. If you distribute a client-side application designed for POSIX-like systems, most people aren't going to be willing to switch to a Mac or install Linux or FreeBSD in VirtualBox just to run it. (Windows is still preinstalled on the vast majority of desktop PCs sold in industrialized English-speaking countries.) And if you just distribute a VM with the operating system and your application pre-installed, you lose the ability to take advantage of the "system libraries" exception in the GPL.
Also, there are libraries which mimic OpenSSL's API, at least the most prominent parts. For example, NSS, CyaSSL, etc.
CyaSSL is GPL, and NSS is MPL/GPL disjunction. I imagine NSS has plenty of trained eyeballs looking at it because of its use in the Firefox browser and Firefox OS. But I'd never heard of CyaSSL before today, which casts doubt on how many trained eyeballs have been looking at CyaSSL.
And at the end of the day, no open source SSL library gets hammered the way OpenSSL does, especially server-side.
Would you say NSS gets hammered client-side?
Can still work perfectly fine in C++ code if the types are subclasses.
Yes this is the usual way of doing it. I usually see people using goto clauses when they have to cleanup some resource on the error handling part of the code. e.g. deallocating memory or closing up files. I prefer to use a helper function for that and replicating the cleanup function call each time. Some times the cleanup code isn't the same. Using goto labels isn't any better than calling a function in terms of programming complexity.
Fail.
His code checked input 2 twice.
Sure, but the reason for goto :clanup specifically is "ease of code review". You want to make it easy to demonstrate that every open has a matching close, every alloc has a matching free, and so on. WHen the code base end up with 1000 allocs and 999 frees, the faster and easier you can spot the matching bookends, the better.
I've actually used an oddball pattern where Foo() is nothing but the error checking, allocs, and frees, and in the middle it calls _Foo(...) which can then return from the middle. But I can't get away with the in "real" code because it's all about what people are used to seeing, and in a team effort that's reasonable.
Socialism: a lie told by totalitarians and believed by fools.
Damn Hurd mentality.
1. "nested brackets" (blocks) are by definition not spaghetti. Spaghetti is exclusively the result of gotos and their control equivalents (like the early return).
Bullshit. One of the projects at my last job had a single function in C++ that was over 50 printed pages. 5-deep nested loops, not even counting conditionals. On a 1280p resolution monitor, 8pt font, 4 space-tabbing and properly indented code, the start of the deepest nested blocks were 4/5s or more across the screen. A lot of the crap was due to avoiding goto's. That is spaghetti. By using a few judicial goto's, I was able to reduce the code by a third alone. Goto's are not evil. Like any language construct, they can be abused. Just because one famous guy wrote a paper Go To Considered Harmful doesn't make it scripture. You might want to read "Considered Harmful" Essays Considered Harmful. Just because *you* don't understand when to properly use a construct doesn't make the construct evil or wrong.
You also have a bug. Strings imply 3 inputs, but you check "input2" against NULL twice. So, you have unreachable code and the compiler would likely eliminate the 3rd conditional.
It also makes the case for using at least a minimum of C++ over bare C just for the RAII capabilities constructors/destructors afford you. Even if you don't want to take advantage of templates, the expanded (but limited) library.
So can we all get on the bandwagon with Fedora and start using NSS instead?
http://fedoraproject.org/wiki/...
ASIDE: Your point is mute [look up "moot" before attempting correction. 8-) ]. Enough is enough, and any less is not enough. That's the definition of enough.
Consider: "If you eat enough pudding you'll die"... the only test case is to keep eating pudding till you die. If you stop before you die you didn't eat enough. 8-)
Now the point that all eyeballs are not equal is fine and obvious. It only takes one metaphorical eyeball, connected to the correct brain, to find a bug. So one is enough if the rest of the configuration is suitable, and an infinite number are not enough if they lack the context.
The real difference between FOSS and others is not the quality of the eyeballs but the opportunity for the correctly quipped eyeball to fall on the relevant bit. In closed source applications the right post-eyeball configuration would have to first be part of the set of allowed eyeballs, and it would likely have to be actively paid to look for the bug directly or indirectly since the limited herd of eyeballs all have their assignments.
Pretending that the better solution (FOSS IMHO) is unworkable because it's demonstrably imperfect ignores the fact that the far less functional (NON FOSS IMHO) has a demonstrably worse track record. That comparason and derision is just "false dichotomy" and kind of an example of, perhaps, why you aren't the set of eyeballs in charge.
In non-FOSS circumstances virtually all eyeballs lack the context to find and fix problems because they lack access to the source.
So your argument fails because it implicitly argues against exposure, or argues that exposure isn't enough if the right people aren't looking. The failure isn't one of fact but of position. You offer no counter proposal. You are pissing on the model that exists but offering no alternative. In short you are engaged in venting of some sort but you are apparently not one of the set of eyeballs ready to offer solutions.
Innocent people shouldn't be forced to pay for inferior software development.
--"Code Complete" Microsoft Press
Snowden:
(v) Adding a bit of code, hardware, or operation you know you shoudln't because an authority requires you do so.
"Hey honey, I'll be late for dinner, I have to snowden the latest release of firefox."
(n) the sneaky bit of intrusive technology
"Hey what's this bit?" "Shhh, that's the snowden."
I know he was the wistleblower, but we should enshrine his deed and the knowledge that this is happening using his name in memoriam.
Innocent people shouldn't be forced to pay for inferior software development.
--"Code Complete" Microsoft Press
Nice to share with me......
People should remember that "Go To Considered Harmful" was written in the times of FORTRAN, when GO TO and a DO-LOOP where the only ways to do control flow. A simple if / else / endif required two GO TOs. So at that time, programmers _had_ to use GO TO in a harmful way. Nowadays they don't.
... } while (0); with break statements in the right places. It's equivalent to using goto in a structured way, and it compiles as C++ code.
C++ makes using goto very hard. The replacement pattern: do {
The poster that you replied to mistakenly believed that using "goto" was the problem. It wasn't. The problem was code of the form
ÂÂÂÂif (condition)
ÂÂÂÂÂÂÂÂstatement;
ÂÂÂÂÂÂÂÂstatement;
which was duplicating a line of code by mistake, and which would be a problem with almost any statement - statement is executed conditionally once and then executed unconditionally. Whether it is "goto fail;" (which is very appropriate) or "i++;" doesn't make much difference. The strange characters are supposed to be non-breaking space characters. Slashdot character handling is so fucked up.
Gtk links to it for some reason, so any distro XFCE of Gnome based would likely have trouble removing it.
First, and yet another OSS-releated security risk :(
At least they are rare enough that it is news worthy. As compared to Windows where new exploits hardly ever get any attention because they are so frilling common as to be passé.
Well, Slashdot seems to report on every vulnerability popping up on my Apple watchlist (often more than once), but not on all popping up on the RedHat watchlist. Draw your own conclusions from what you just said.
Of course news about a fake are Fake News.
First, and yet another OSS-releated security risk :(
At least they are rare enough that it is news worthy. As compared to Windows where new exploits hardly ever get any attention because they are so frilling common as to be passé.
Well, Slashdot seems to report on every vulnerability popping up on my Apple watchlist (often more than once), but not on all popping up on the RedHat watchlist. Draw your own conclusions from what you just said.
Forgot to mention: Apple's TSL-bug was also open source.
Of course news about a fake are Fake News.
On a 1280p resolution monitor, 8pt font, 4 space-tabbing and properly indented code, the start of the deepest nested blocks were 4/5s or more across the screen.
Sorry to be pedantic, but why would you give only the number of vertical lines (1280)? Since 2276x1280 is such an unusual resolution (I can only assume 16:9 when using the ???p notation), it would be clearer to give the number of pixels in both directions. Another piece of info missing is the DPI, without which one can't relate "pt" to pixels. [at least we know it's a progressive scan monitor, thank god you don't have to code on an interlaced display]
Since all machine code is potentially brittle, the argument for using "safety aware languages" is itself brittle. For instance, Ada is safe because it doesn't allow deallocation unless you use ada.unchecked_deallocation(), or in the alternate, build nothing on the heap, or just hope that the Ada implementation has garbage collection, or..., or... etc.
_Someone_ has to do the work to protect whatever the brittleness is at issue.
For years I have used "struct Buffer { char * start, char * end};" instead of just char * string. (thing.end-thing.begin) is faster than strlen() and the constraints are always present. I've got a library full of simple bits that make this work (a wrapper around write(2) and read(2) for example).
Bad code can be written in any language. Java is safe? Well kind of, until you start making circles of referencds and losing them. sounds harmless unles there is a task and open socket in that circular reference and you've left a link back to some structure so that the socket is now able to access some nonsense.
The best tools in the worst hands are far worse than the worst tools in the best hands. Yelling for tools is a specious argument. Someone has to do the work, and that someone may well bone the job.
Innocent people shouldn't be forced to pay for inferior software development.
--"Code Complete" Microsoft Press
The linux kernel is full of gotos. Assembly is bereft blocks and that sort of structure. So "goto" isn't the source of all evil.
Consier this example of the linux goto paradigm below. When taking locks and establsihing component preconditions you can write an optimal routine that does the stepwise creation, and includes the non-conditional cleanup. Then skipping the cleanup if all the parts succede. The example below is trivial, but when it comes to preserving locking orders it solves a hard problem very simply. And if you check out the generated code its very efficent. More so if you hint the compiler that the success case is most likely for each conditional.
So take the simple example and imagine you are building something complex like a network request with data and metadata buffers and the actual request structure itself et al... as the number of parts grow the number of bizarre else conditions you have to use to do stepwise cleanup become bothersome repetitions of code. Its even worse if it's part1 _or_ part2 along with part3 etc. Complexity and repetition of phrases in the elses is plenty of reason to use goto.
complex_thing * hard_thing() {
complex_thing * retval = 0;
thing_pt1 * pt1 = 0;
thing_pt2 * pt2 = 0;
if (pt1 = generate_first()) {
if (pt2 = generate_last(pt1)) {
if (retval = generate_final(pt1,pt2)) {
goto success;
}
}
}
if (pt2) cleanup_last(pt2);
if (pt1) cleanup_first(pt1);
success:
return retval;
}
Simply put, there are times when a well-placed goto with a clear purpose and precondition can simplify code and accelerate execution.
Do I use a lot of gotos? no. Probably six C/C++ gotos in the last fifteen years. But when they are the correct tool to use, they can be magical.
Innocent people shouldn't be forced to pay for inferior software development.
--"Code Complete" Microsoft Press
Where are my mod points, when I need them...
Hell, the issue would have happened if there were no gotos in use, and instead both statements were method calls - the unintended method call would still have happened.
Ok! Ok! I must have, I must have put a decimal point in the wrong place or something. Shit. I always do that. I always mess up some mundane detail.
Sorry, you don't use the right command to see the reverse dependencies.
Try this:
apt-cache rdepends libgnutls26
I will not post the result here, because it's 494 lines long on my system:
apt-cache rdepends libgnutls26 | wc -l
494
Using GnuTLS avoids the licensing issues that can arise from employing the more common OpenSSL package. For this reason, certain packages such as OpenLDAP are compiled with support for GnuTLS instead of OpenSSL in recent releases of Ubuntu.
In fact, on one of my Ubuntu 13.10 systems I ran ldd on /usr/bin/* and /bin/*, and found many many binaries that link in GnuTLS.
"Ahh! I see you're in that indeterminate Schrodinger state where - oh, uh
Is that really seriously a question?
Yes. In comments to various articles, you might be surprised at how many people ask questions like this: "Why are people still using HTTP at all instead of self-signed HTTPS?" Then they go on about something called "key continuity management", where seeing the same certificate as on the last visit means that no new MITM has been introduced, but that doesn't help if you're MITM'd from day one. The "Perspectives" project uses route diversity to root out MITMs, but that doesn't help if the MITM is on the server's upstream.
Seem to remember an update to gnutls for this problem! http://www.ubuntu.com/usn/usn-... USN-1752-1: GnuTLS vulnerability and a standard update fixes it! Whoopty doo! Kind of why I like that Ubuntu doesn't wait for an arbitrary day of the month to issue updates and patches!
Wow, have you ever actually written production code? Just wow.
More than 30 years of it. And the code you show is common, but that doesn't make it ideal. Big Macs are common, and easy food for the lazy, but that doesn't make it good food,
The problem with it is that it gets buried in a sizeable function, then a bit of code that is needed in every case is added before the final return. It seems to work, and may even pass superficial testing, because the bug only shows under error conditions.
This is a common bug that all too often gets into shipping software. (But not mine).
Substitute "throw new ERROR(..)" or "goto :error" depending on what kind of code your writing, it's the same thing any way you do it.
No, it's entirely different, because there is a "finally" section that ensures that "always needs to run" code really does get run. This is the correct way to do it. Exceptions are a real control structure, not a misuse of a goto equivalent.
Of course you may argue that the former pattern is needed for languages such as C that don't support exceptions. But then that would be a comprehension error on your part, as this part of the discussion was about "A language that takes the step to rule out gotos".
I called it spaghetti because the resulting mass of brackets looks just like a big steaming dish of spaghetti, and the extraneous control statements are almost as annoying as gotos to more than a single "error" label.
Humpty Dumpty said "When I use a word, it means just what I choose it to meanâ"neither more nor less." The rest of us try to stick with the established uses of words and phrases.
The term "spaghetti code" was coined as the antonym of "structured code". Deeply nested but nevertheless structured code is not spaghetti code.
Some are, some not so much. Many situations call for a long list of sequential checks, which can be cleanly and clearly coded as a bunch of if .... return statements.
Here's one refactoring for the situation you describe, that results in more even benefits than just removing the gotos/returns:
http://www.drdobbs.com/archite...
You seem hung up on definitions. If you narrowly define structured code as code that lacks return, break, continue and exception statements (which can all be used to break out of your "structured" sandbox)
Exceptions aren't really unstructured. Whilst they result in execution stopping at a line in the middle of a block, they do so using an explicit built into the language block structure, that defines exactly which section of code may do so.
The main problem with early exits is using them in C.
Right, but this section of the discussion was under the condition: "if you are taking the step to remove gotos from a language...". Yes, C is old fashioned, and it's lack of exceptions calls for emulating them with gotos or early returns. But that's not the topic.
Sure, but the reason for goto :clanup specifically is "ease of code review". You want to make it easy to demonstrate that every open has a matching close, every alloc has a matching free, and so on. WHen the code base end up with 1000 allocs and 999 frees, the faster and easier you can spot the matching bookends, the better.
And the falseness of that argument is demonstrated by the fact that it's exactly this pattern that has disguised the bugs in the TLS code for Apple for 18 months and GnuTLS for 9 years. The simplicity is superficial. In fact the goto is a huge source of bugs that are not apparent in code reviews.
If the code was written in a structured form these bugs would likely not have happened, or would at least have been more obvious in code review.
Bullshit. One of the projects at my last job had a single function in C++ that was over 50 printed pages. 5-deep nested loops, not even counting conditionals
I don't care. "spaghetti code" was coined as an antonym to "structured code". Deeply nested but otherwise structured code may be on need of refactoring, but it is not spaghetti, by definition.
You might want to read "Considered Harmful" Essays Considered Harmful.
Which says absolutely nothing about gotos. Thats a classic strawman, since you are the one that brought up "considered harmful" not me.
Just because *you* don't understand when to properly use a construct doesn't make the construct evil or wrong.
I was programming before the term "structured programming" even came into general use. When all we had was gotos. I learned structured coding and later OOP as they developed. That's how long I've been doing this stuff. There's no lack of understanding on this end of the exchange. And that part of your argument was an ad-hominem.
Strawman and ad-homoinem in the same post. Classic poor argumentation,
Huh? How so?
What would that look like though. You keep asserting philosophy that's not backed by anything practical. If you have 97 levels of indention, nothing is obvious.
You test 6 things up front, and you'll bail if any of them fail. Are you indented 6 levels now to avoid goto/return? You allocate 6 more things, and must clean them up, but later allocations might fail - indented 6 more levels? You perform 10 operations in the body of the code, and want to skip to cleanup on any error - 10 more levels of indention? No one could follow that crap.
I suspect you just have an aversion specifically to the "goto" keyword, and do something equivalent to it to avoid 22 levels of indention. Microsoft C has the amusing __try, __finally, and __leave for this, but __leave is just a macro for goto, and __finally just a macro for the tag. Would that make you happy? Wrapping goto in a macro so you don't see it any more?
Socialism: a lie told by totalitarians and believed by fools.
What would that look like though. You keep asserting philosophy that's not backed by anything practical. If you have 97 levels of indention, nothing is obvious.
In other answers to you I've already given you two practical alternatives. Exceptions, and a way to refactor nested ifs.
Microsoft C has
I've also pointed out that this sub-discussion is predicated on what you would do with a language that was eschewing the goto. Such a structured language would already have the necessary structures, so the question of what to do with legacy languages such as C is irrelevant. That C is a bad tool with which you have to emulate some control structures with gotos is no defense of gotos in modern languages.
As I understand it, Objective-C is a strict superset of C, and hence anything allowed in C is allowed in Objective-C. (This differs from C++, in that some C programs can be invalid, or valid and produce different output, in C++).
"When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
Here's one refactoring for the situation you describe, that results in more even benefits than just removing the gotos/returns:
By adding extra useless variables, as I originally pointed out. And introducing a sea of "&&"s. I guess at least it looks more like a bowl of pretzels than a dish of spaghetti.
Whilst they result in execution stopping at a line in the middle of a block, they do so using an explicit built into the language block structure, that defines exactly which section of code may do so.
In a language like C++, unless there's a "try" block within the function, they are exactly the same as a "return" as far as that function is concerned, and can be invoked from the same places. I don't see why you think that that's acceptable if return isn't.
If you look at the FAQs for the Go language, the designers explain why they think exceptions suck in general, and why they largely replaced them with multiple return values. So not everyone shares your enthusiasm for exceptions, which are really just a kind of "return" statement on steroids.
Oh, we may be saying the same things then. That's fine. But people are still going to write kernel code in C, and it's still going to have gotos, and that's still not a big problem (using goto only correctly is far down the list of things you have to consistently get right to write kernel code).
Socialism: a lie told by totalitarians and believed by fools.
BTW, I think "finally" sections realy are just the same as the "goto: cleanup" target: a branch to explicit cleanup code, fraught with peril. However, there are better ways to write exception-safe code where you never explicitly clean up/free/close stuff and instead let the stack unwind handle it all for you (more than just RAII: scoped objects). Until you make it to where there's no "matching close for every open" anywhere, you're just moving the problem around, not solving it.
Socialism: a lie told by totalitarians and believed by fools.
No problem. It was over 50 printed pages at 80 lines per page (some wrapped). Last time I bothered to check, it was a bit over 3000 lines, without wrapping. Yes, I tried to refactor, but that was a loosing battle given the resources and pressures at the time.
do {...} while(0); is unnecessary since C++03, (maybe even 98). You can just use {...} to accomplish the same thing. goto's still have there place, and they still have their pitfalls. But, a good compiler will warn you about the most of them (such as jumping over initialization/destruction).
Strawman my ass, you only quote half the sentence and take it out of context. If you actually read the link, it talks about such strongly worded "considered harmful" essays are usually taken basically as scripture, and such feature, whatever it is, should never be used. Sure, Dijkstra was writing about Fortran, but he was influential enough that the philosophy carried over to other languages. "Don't ever use this".
In regards to defining spaghetti code, try google for a change:
Spaghetti code is a pejorative term for source code that has a complex and tangled control structure, especially one using many GOTOs, exceptions, threads, or other "unstructured" branching constructs.
(emphasis mine). Spaghetti code doesn't necessitate goto's, but I'll grant poor use can lead to it. Using goto doesn't mean spaghetti code.
I don't care how long you've been programming or what order you learned different idioms as they developed/were available, it doesn't make you right.
I'm not advocating prolific use of goto's, but they have their place, and when used correctly, they can lead to more readable, and, perhaps, more efficient code. But never use it (with no evidence, examples)? If you want a strawman argument, that is it.
BTW, I think "finally" sections realy are just the same as the "goto: cleanup" target: a branch to explicit cleanup code, fraught with peril.
No they are not. Goto requires that the programmer writes that line each time there is a different path that maybe taken through the possibly failing code. Finally ensures that once the exception block has been entered, the finally block must follow.
However, there are better ways to write exception-safe code where you never explicitly clean up/free/close stuff and instead let the stack unwind handle it all for you
Sure. That's another way of avoiding goto. Symbian was written before C++ got exceptions, and uses a cleanup stack for that purpose.
Until you make it to where there's no "matching close for every open" anywhere, you're just moving the problem around, not solving it.
Which is why you don't manually code it with gotos. Of all the ways of dealing with these problems, goto is the worst.
Strawman my ass, you only quote half the sentence and take it out of context. If you actually read the link, it talks about such strongly worded "considered harmful" essays are usually taken basically as scripture, and such feature, whatever it is, should never be used. Sure, Dijkstra was writing about Fortran, but he was influential enough that the philosophy carried over to other languages. "Don't ever use this".
And if I'd quoted Dijkstra, or said "thou shalt not use gotos" in a scriptural way, then you'd have a point. But I didn't do those any more than I said "gotos considered harmful". All of these things were raised by you, then dismissed buy you. And that's exactly what a strawman is.
In regards to defining spaghetti code, try google for a change:
Your definition comes from Wikipedia, and it comes without a specific citation. Now, take a look at the references at the bottom. The oldest one is 1977. From the book: "Structured programming for the COBOL programmer: design, documentation, coding, testing." Elsewhere the artcle points out: "author Paul Noll uses the terms spaghetti code and rat's nest as synonyms to describe poorly structured source code."
As I say, spaghetti code is the antonym to structured code. Always was. Deeply nested structured code is not spaghetti. A russian doll might be a suitable metaphor, but a plate of spaghetti is not. There is no structure in spaghetti.
I don't care how long you've been programming or what order you learned different idioms as they developed/were available, it doesn't make you right.
It doesn't make me right in and of itself. However that memory back to the days when structured code was still a topical issue is why I know for sure what spaghetti code is. And that's why I'm telling you. If you can find an earlier reference than 1977 that confirms your understanding, then you can say I'm wrong. Otherwise I'm right.
But never use it (with no evidence, examples)?
What's the point of examples? It's an absolute fact that you cannot dispute that every piece of code that uses a goto can be rewritten using proper control structures. I personally have not used a goto since the 1980s. And my career has included work on a commercial operating system, in which gotos were forbidden at all levels above the kernel. And that was conceived with C++ in the days before it even had exceptions.
(You might ask why gotos were permitted at the kernel level. And the answer is that the kernel engineers mixed assembly and C, and tended to think in assembler first, even if they then wrote in C. If questioned they would say that the goto was more efficient. And in those days of poor compiler optimisations they may have been right. But that argument generally doesn't apply with modern optimising compilers.)
By adding extra useless variables
In the days of optimising compilers, local variables typically have no cost, and they tend to self-document the code. To defend gotos whilst attacking extra local variables is irrational.
And introducing a sea of "&&"s.
At first blush, that does seem to make the code look more complicated. But in reality it doesn't. As the text explains it's easier to see when a block will be executed if the conditionals are explicitly in the single containing if statement, than if it is implicit through nesting or worse through possible earlier gotos.
And in practice you don't just use this pattern to refactor to the extreme. It's more a mixture of this with refactoring into smaller functions, and accepting that one level of nesting is OK.
In a language like C++, unless there's a "try" block within the function, they are exactly the same as a "return" as far as that function is concerned, and can be invoked from the same places. I don't see why you think that that's acceptable if return isn't.
That's a valid point, however functions that may throw exceptions are usually designed and documented as such. Whereas early returns are just slipped in on a whim of the programmer, and are often missed by maintainers, causing bugs.
If you look at the FAQs for the Go language, the designers explain why they think exceptions suck in general, and why they largely replaced them with multiple return values. So not everyone shares your enthusiasm for exceptions, which are really just a kind of "return" statement on steroids.
I'm not particularly enthusiastic about exceptions. I've actually used cleanup stacks and error codes more often myself, I simply brought up exceptions as one of the more structured mechanisms for avoiding gotos and their equivalents.
For sure kernel code is the one place where I still see lots of gotos. And I accept that the limitations of C and the need to maximally optimise may justify that. Though I wonder how much the optimisation argument still applies with modern compilers.
It's purely cultural. So much of what "makes you good at C code" goes away once you embrace automatic cleanup; coders would suddenly find a big chunk of what they do daily to be valueless. Plus, the ability to get the cleanup block right is a shibboleth for the harder problems you have to constantly juggle (e.g., page faults and priority inversion) while writing kernel code - people who want to use C++ are seen as too mentally undisciplined to write a driver. Cultural change is very slow.
Socialism: a lie told by totalitarians and believed by fools.
Strawman my ass, you only quote half the sentence and take it out of context. If you actually read the link, it talks about such strongly worded "considered harmful" essays are usually taken basically as scripture, and such feature, whatever it is, should never be used. Sure, Dijkstra was writing about Fortran, but he was influential enough that the philosophy carried over to other languages. "Don't ever use this".
And if I'd quoted Dijkstra, or said "thou shalt not use gotos" in a scriptural way, then you'd have a point. But I didn't do those any more than I said "gotos considered harmful". All of these things were raised by you, then dismissed buy you. And that's exactly what a strawman is.
In regards to defining spaghetti code, try google for a change:
Your definition comes from Wikipedia, and it comes without a specific citation. Now, take a look at the references at the bottom. The oldest one is 1977. From the book: "Structured programming for the COBOL programmer: design, documentation, coding, testing." Elsewhere the artcle points out: "author Paul Noll uses the terms spaghetti code and rat's nest as synonyms to describe poorly structured source code."
As I say, spaghetti code is the antonym to structured code. Always was. Deeply nested structured code is not spaghetti. A russian doll might be a suitable metaphor, but a plate of spaghetti is not. There is no structure in spaghetti.
I don't care how long you've been programming or what order you learned different idioms as they developed/were available, it doesn't make you right.
It doesn't make me right in and of itself. However that memory back to the days when structured code was still a topical issue is why I know for sure what spaghetti code is. And that's why I'm telling you. If you can find an earlier reference than 1977 that confirms your understanding, then you can say I'm wrong. Otherwise I'm right.
But never use it (with no evidence, examples)?
What's the point of examples? It's an absolute fact that you cannot dispute that every piece of code that uses a goto can be rewritten using proper control structures. I personally have not used a goto since the 1980s. And my career has included work on a commercial operating system, in which gotos were forbidden at all levels above the kernel. And that was conceived with C++ in the days before it even had exceptions.
(You might ask why gotos were permitted at the kernel level. And the answer is that the kernel engineers mixed assembly and C, and tended to think in assembler first, even if they then wrote in C. If questioned they would say that the goto was more efficient. And in those days of poor compiler optimisations they may have been right. But that argument generally doesn't apply with modern optimising compilers.)
What's the point of examples? It's an absolute fact that you cannot dispute that every piece of code that uses a goto can be rewritten using proper control structures. I personally have not used a goto since the 1980s.
What's the point of examples? The point of examples is to prove your point, to convince. You have not done so with me. You seem to think that I'm advocating liberal use of goto's. I'm not. I'm merely stating that they have their time and place and a blanket abolishment is unnecessary and unwise. Also, I'll call you on your "proper control structures". In C-like languages, control structures like "break" and "continue" are glorified goto's. 'switch' statements are glorified if-else chains that compiler can usually optimize very well. You want to talk strawman arguments, your sole argument is "goto is evil". Put up or shut up.
If I asserted that 'for' loops were evil, and unnecessary, because every 'for' loop could be written with an equivalent while loop doesn't make 'for' loops wrong; you'd think me mad. Maybe I just didn't drink enough Koo
Also, I'll call you on your "proper control structures". In C-like languages, control structures like "break" and "continue" are glorified goto's. 'switch' statements are glorified if-else chains that compiler can usually optimize very well.
I agree. This all started with me pointing out that an early return is effectively a goto. And so are break and continue.
And the C switch construct with it's run-on between cases unless you explicitly break - that's possibly the most horribly broken control structure in any language. Yes, it too is effectively gotos. But that's a fuck up in C, not a general problem with selection control structures. In other languages selection control structures are a proper structured programming construct.
The point of examples is to prove your point, to convince. You have not done so with me.
On Slashdot, few people are ever convinced of anything. Experience tells me that you are convinced enough of your rightness, examples aren't going to change your mind. I'm happy enough to state my opinion, and not really care whether you agree.
And to summarise my opinion - gotos are used only with languages that have poor control structures, especially C. My opening statement was about a language that eschewed the goto. Such a language would also not have early returns (not breaks nor continues). But it would have a full set of control structures that make gotos entirely unnecessary.
Personally I haven't made use of an explicit goto since the 1980s (other than in asm). And only used goto equivalents such as break where the deficiencies of the language have necessitated it.