Skip to content

Commit 37d30c9

Browse files
committed
Rework the __block jump-checking section, including a justification of
why this bug can go uncaught. llvm-svn: 124790
1 parent 55199a6 commit 37d30c9

File tree

1 file changed

+28
-27
lines changed

1 file changed

+28
-27
lines changed

clang/www/compatibility.html

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -199,50 +199,51 @@ <h3 id="lvalue-cast">Lvalue casts</h3>
199199
<h3 id="blocks-in-protected-scope">Jumps to within <tt>__block</tt> variable scope</h3>
200200
<!-- ======================================================================= -->
201201

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>
212207

213208
<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;
217211

218-
__block int x;
219-
x = 1;
220-
return x;
212+
__block int result;
213+
run_specially_somehow(^{ result = c->state; });
214+
return result;
221215

222216
error:
223-
x = 0;
224-
return x;
217+
fprintf(stderr, "error while fetching object state");
218+
return -1;
225219
}
226220
</pre>
227221

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>
231227

232228
<pre>
233229
t.c:3:5: error: goto into protected scope
234230
goto error;
235231
^
236232
t.c:5:15: note: jump bypasses setup of __block variable
237-
__block int x;
233+
__block int result;
238234
^
239235
</pre>
240236

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>
246247

247248
<!-- ======================================================================= -->
248249
<h3 id="block-variable-initialization">Non-initialization of <tt>__block</tt>

0 commit comments

Comments
 (0)