@@ -199,50 +199,51 @@ <h3 id="lvalue-cast">Lvalue casts</h3>
199
199
< h3 id ="blocks-in-protected-scope "> Jumps to within < tt > __block</ tt > variable scope</ h3 >
200
200
<!-- ======================================================================= -->
201
201
202
- < p > Clang disallows jumps into the scope of a < tt > __block</ tt > variable, similar
203
- to the manner in which both GCC and Clang disallow jumps into the scope of
204
- variables which have user defined constructors (in C++).</ p >
205
-
206
- < p > Variables marked with < tt > __block</ tt > require special runtime initialization
207
- before they can be used. A jump into the scope of a < tt > __block</ tt > variable
208
- would bypass this initialization and therefore the variable cannot safely be
209
- used.</ p >
210
-
211
- < p > For example, consider the following code fragment:</ p >
202
+ < p > Clang disallows jumps into the scope of a < tt > __block</ tt >
203
+ variable. Variables marked with < tt > __block</ tt > require special
204
+ runtime initialization. A jump into the scope of a < tt > __block</ tt >
205
+ variable bypasses this initialization, leaving the variable's metadata
206
+ in an invalid state. Consider the following code fragment:</ p >
212
207
213
208
< pre >
214
- int f0(int c) {
215
- if (c)
216
- goto error;
209
+ int fetch_object_state(struct MyObject *c) {
210
+ if (!c-> active) goto error;
217
211
218
- __block int x ;
219
- x = 1 ;
220
- return x ;
212
+ __block int result ;
213
+ run_specially_somehow(^{ result = c- > state; }) ;
214
+ return result ;
221
215
222
216
error:
223
- x = 0 ;
224
- return x ;
217
+ fprintf(stderr, "error while fetching object state") ;
218
+ return -1 ;
225
219
}
226
220
</ pre >
227
221
228
- < p > GCC accepts this code, but it will crash at runtime along the error path,
229
- because the runtime setup for the storage backing the < tt > x</ tt > variable will
230
- not have been initialized. Clang rejects this code with a hard error:</ p >
222
+ < p > GCC accepts this code, but it produces code that will usually crash
223
+ when < code > result</ code > goes out of scope if the jump is taken. (It's
224
+ possible for this bug to go undetected because it often won't crash if
225
+ the stack is fresh, i.e. still zeroed.) Therefore, Clang rejects this
226
+ code with a hard error:</ p >
231
227
232
228
< pre >
233
229
t.c:3:5: error: goto into protected scope
234
230
goto error;
235
231
^
236
232
t.c:5:15: note: jump bypasses setup of __block variable
237
- __block int x ;
233
+ __block int result ;
238
234
^
239
235
</ pre >
240
236
241
- < p > Some instances of this construct may be safe if the variable is never used
242
- after the jump target, however the protected scope checker does not check the
243
- uses of the variable, only the scopes in which it is visible. You should rewrite
244
- your code to put the < tt > __block</ tt > variables in a scope which is only visible
245
- where they are used.</ p >
237
+ < p > The fix is to rewrite the code to not require jumping into a
238
+ < tt > __block</ tt > variable's scope, e.g. by limiting that scope:</ p >
239
+
240
+ < pre >
241
+ {
242
+ __block int result;
243
+ run_specially_somehow(^{ result = c-> state; });
244
+ return result;
245
+ }
246
+ </ pre >
246
247
247
248
<!-- ======================================================================= -->
248
249
< h3 id ="block-variable-initialization "> Non-initialization of < tt > __block</ tt >
0 commit comments