Finally!

| No Comments

I tend to follow a standard idiom when writing C functions which allocate resources. At the top, I define a variable for each resource, and initialize it to a sentinel value meaning that it’s not yet active, and another for the function’s return value. At the bottom, I define a label end, where I release all of the resources which still seem live, and return the right result. If something goes wrong partway through, I set the return value to indicate the problem, and goto end. Easy.

But it means that the code to release a thing isn’t near where it’s defined or allocated.

I had a brainwave the other day, and wrote a macro.

#define FINALLY(body) \
  __extension__ __inline__ TMP(finally_fn) \
    (const int __attribute__((unused)) *hunoz) { body } \
  int __attribute__((unused, cleanup(TMP(finally_fn)))) \
    TMP(finally_var)

The TMP macro decorates an identifier so that it’s (more or less) private to the macro invocation. Now I can say something like

void *p = 0; FINALLY({ free(p); });

and I can use return as usual for an early exit. Yay. (Apparently I’m not the only person who’s thought of this.)

This macro has two problems.

  • Firstly, it uses nested functions, so it only works with GCC. Clang doesn’t support these, presumably because there’s no good way to implement a pointer to a nested function.

  • Secondly, the syntax is ugly, involving parentheses and a final semicolon.

I can’t figure out a way to solve both problems at the same time.

Solving the former is tricky. I can’t see any way to do this using actual standard C. There’s a proposal to add Golang-ish defer to C but this (a) isn’t part of the language yet, and (b) is deeply wrongheaded — most particularly, the proposal’s authors don’t think it’s a terrible idea to perform all of the deferred actions at exit time. Apparently, they think it’s really important to clean the floors before demolishing the building.

If we can’t do this in a standard way, then maybe we can at least make this work with Clang. The best approach I’ve seen is this StackMumble answer which (ab?)uses Clang’s support for Objective C-ish blocks.

static __inline__ void _finally__runblk(void (^*blk)(void))
  { (*blk)(); }
#define FINALLY(body) \
  void __attribute__((unused, cleanup(_finally__runblk))) \
    (^TMP(finally_blk))(void) = ^{ body }

Yikes! Now just add -fblocks -lBlocksRuntime to the compiler command line and you’re done.

This is nowhere near as good as the GCC version. GCC generates identical machine code for FINALLY and goto end code, except for internal label names, so it’s obviously doing everything right. Clang introduces a whole lot of extra machinery which it apparently can’t see its way through optimizing away, so cleanup becomes rather less efficient. Oh, well. I’m not going to lose much sleep if Clang ends up looking second-class here.

I can also see a way to eliminate the parentheses: essentially, you just put the function body last. In GCC, this means we need a forward-declaration of a nested function, and that needs a trick to express, because if you just say it normally, it looks like a local declaration of a static or external function. The trick is to say auto here, because… no, I’ve got nothing.

#define FINALLY \
  __extension__ auto void TMP(finally_fn)(const int *); \
  int __attribute__((unused, cleanup(TMP(finally_fn))))
    TMP(finally_var); \
  __extension__ __inline__ void TMP(finally_fn) \
    (const int __attribute__((unused)) *hunoz)

Yay!

void *p = 0; FINALLY { free(p); }

Can we do the same with the Clang version? Yes… almost.

#define FINALLY \
  void __attribute__((unused, cleanup(_finally__runblk))) \
    (^TMP(finally_blk))(void) = ^

Alas, here we need

void *p = 0; FINALLY { free(p); };

with the final ;. This is acceptable to GCC under C99 rules, but not with C90 rules, which is a shame because I actually like having a function’s variables all declared in one block at the top.

Suggestions welcome.

Leave a comment