From 504b369f8de741241e0304f7801c84aca3ed922e Mon Sep 17 00:00:00 2001
From: John McCall
Clang disallows jumps into the scope of a __block variable, similar -to the manner in which both GCC and Clang disallow jumps into the scope of -variables which have user defined constructors (in C++).
- -Variables marked with __block require special runtime initialization -before they can be used. A jump into the scope of a __block variable -would bypass this initialization and therefore the variable cannot safely be -used.
- -For example, consider the following code fragment:
+Clang disallows jumps into the scope of a __block +variable. Variables marked with __block require special +runtime initialization. A jump into the scope of a __block +variable bypasses this initialization, leaving the variable's metadata +in an invalid state. Consider the following code fragment:
-int f0(int c) { - if (c) - goto error; +int fetch_object_state(struct MyObject *c) { + if (!c->active) goto error; - __block int x; - x = 1; - return x; + __block int result; + run_specially_somehow(^{ result = c->state; }); + return result; error: - x = 0; - return x; + fprintf(stderr, "error while fetching object state"); + return -1; }-
GCC accepts this code, but it will crash at runtime along the error path, -because the runtime setup for the storage backing the x variable will -not have been initialized. Clang rejects this code with a hard error:
+GCC accepts this code, but it produces code that will usually crash
+when result
goes out of scope if the jump is taken. (It's
+possible for this bug to go undetected because it often won't crash if
+the stack is fresh, i.e. still zeroed.) Therefore, Clang rejects this
+code with a hard error:
t.c:3:5: error: goto into protected scope goto error; ^ t.c:5:15: note: jump bypasses setup of __block variable - __block int x; + __block int result; ^-
Some instances of this construct may be safe if the variable is never used -after the jump target, however the protected scope checker does not check the -uses of the variable, only the scopes in which it is visible. You should rewrite -your code to put the __block variables in a scope which is only visible -where they are used.
+The fix is to rewrite the code to not require jumping into a +__block variable's scope, e.g. by limiting that scope:
+ ++ { + __block int result; + run_specially_somehow(^{ result = c->state; }); + return result; + } +