|
|
Subscribe / Log in / New account

The Story So Far...

The Story So Far...

Posted Dec 28, 2014 22:56 UTC (Sun) by nix (subscriber, #2304)
In reply to: The Story So Far... by ldo
Parent article: The "too small to fail" memory-allocation rule

The problem in the kernel is not an inability to be sure that cleanups will execute. With the goto exception-handling technique, unless you omit a goto, they always execute, and if your cleanups are executed in the normal path (i.e. there is no return before the goto label) they will execute even if you omit a goto. This is *exactly the same* as in your technique.

The problem in the kernel is an inability to be sure that what those code paths do on error is even sane. They will execute if triggered, but because of this "too small to fail* rule, many of them have never executed, even when the system is out of memory.

Your digression on an idiosyncratic (and IMNHSO needlessly verbose and unreadable) technique to replace gotos is not relevant to this problem so cannot solve it.

To me, the technique appears similar to the panic that strikes people who started with one-return languages like Pascal when they are faced with languages that allow multiple returns. Yes, if carelessly used this can lead to unreadable spaghetti, but that doesn't mean the right answer is to ban it! It's amazing how many of my functions these days reduce to

int err = -1;

if (do-nothing-fastpath-test)
    return 0; /* early */

stuff that allocates memory or does other things needing cleanup in both success and failure cases
if (error check)
   goto cleanup_stuff;

stuff that doesn't need cleanup but can fail
if (error check)
   goto cleanup_stuff;

more stuff
if (error check)
   goto cleanup_more_stuff;

...

err = 0; /* success */

cleanup_more_stuff:
undo 'more stuff'

cleanup_stuff:
undo 'stuff'

return err;
It is clear that in this code -- other than in the early-fast-exit case -- the cleanups will always execute. You don't have to have a 'return' before them! The normal flow of control passes smoothly through them at all times: it's just that the cleanups can skip some of that flow (the parts relating to things they did that don't need cleanup, and where the cleanup is not something like free() that is harmless to do on something that was never allocated).

Notice how little code error handling includes here -- I've replaced the actual work with pseudocode, but even in the real code the error unwinding is *two lines per check*, one an unavoidable conditional, plus optional extra work in those conditionals to do error-specific stuff first. The cleanup is no extra code: it's just a couple of goto labels, and if you miss one of them out or somehow manage to do some cleanup at a too-deeply-nested level you get a nice easy-to-spot syntax error.

This is ever so much neater than your false-loops approach and involves much less spurious nesting. It's linear in the normal case, just like the actual code flow, with branches only in exceptional conditions, while your code makes *loops* look like the normal condition, even though those loops actually never happen. Plus, spurious break and continue are both correctly diagnosed as syntax errors: in your approach, they cause a silent and erroneous change in control flow, as if an error had happened. It is much easier to mistakenly type or transpose 'break' outside e.g. a switch than it is to accidentally type 'goto some_cleanup'!

In my view it is you who has manifestly failed to understand the merits of our approach, which is quite clearly beneficial on every metric I can see other than the unthinking one which assigns an infinite automatic negative value to any use of 'goto' regardless, even uses which only jump forward in control flow to the end of a function and are thus precisely equivalent to a block with a cleanup in it and then a return. Spaghetti code this is not! It is much less spaghetti than yours.

Note: I came from a Pascal background and was at first violently anti-goto *and* anti-multiple-returns. When I look at my code from those long-ago days the contorted control flow is almost unreadable. Almost all the time a nice linear flow is preferable. Save loops for things that can actually *loop* at least once -- and for the while (0) macro trick.


to post comments

The Story So Far...

Posted Dec 29, 2014 0:41 UTC (Mon) by vonbrand (guest, #4458) [Link]

That is exactly the point: With the Linux goto usage the normal code path is linear and clear for all to see, failure exceptional code paths are kept apart, for separate analysis (which they require, as "normal situation" isn't guaranteed in them).

The Story So Far...

Posted Dec 29, 2014 4:20 UTC (Mon) by viro (subscriber, #7872) [Link] (1 responses)

TBH, my impression is that ldo either has never bothered to read any of the relevant papers (Dijkstra, Hoare, etc.) *or* has confused the proofs that goto doesn't add any expressive power (e.g. compared to mutual (tail) recursion) with the discussions of the reasons why goto often leads to brittle code that is hard to reason about. And these are very different things - by the very nature of such proofs, feeding them a hard-to-analyse ball of spaghetti yields an equally hard to analyse goto-free equivalent, so they actually demonstrate both that goto can be avoided *and* that avoiding goto doesn't guarantee avoiding the problems usually associated with it.

BTW, from the control flow graph decomposition POV, break is an atrocity almost equal to multiple returns (and if you add break <number of levels>
a-la sh(1), it becomes _worse_ than multiple returns). Not to mention its inconsistency between if() and switch(), etc.

Frankly, this sort of attitude is best cured by careful reading of the standard papers circa late 60s--early 70s *plus* sorting through the usual fare on lambda-lifting, supercombinators and related stuff (circa early 80s) *plus* that on the monads sensu Peyton-Jones et.al. Attitude re goto-phobia, that is - "my code is perfect, whaddya mean, idiosyncrasies?" one is cured only by sufficiently convincing LART...

Re: ldo either has never bothered to read any of the relevant papers

Posted Dec 30, 2014 20:57 UTC (Tue) by ldo (guest, #40946) [Link]

Or maybe you never bothered to look at my code?

Feel free to try any of the error-recovery-within-loop cases. That is where the rubber hits the road, and where all the goto-ists have come a cropper.


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds