<div dir="ltr">On 27 November 2013 12:44, Paul Berry <span dir="ltr"><<a href="mailto:stereotype441@gmail.com" target="_blank">stereotype441@gmail.com</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">The compiler back-ends (i965's fs_visitor and brw_visitor,<br>
ir_to_mesa_visitor, and glsl_to_tgsi_visitor) assume that when<br>
ir_loop::counter is non-null, it points to a fresh ir_variable that<br>
should be used as the loop counter (as opposed to an ir_variable that<br>
exists elsewhere in the instruction stream).<br>
<br>
However, previous to this patch:<br>
<br>
(1) loop_control_visitor did not create a new variable for<br>
ir_loop::counter; instead it re-used the existing ir_variable.<br>
This caused the loop counter to be double-incremented (once<br>
explicitly by the body of the loop, and once implicitly by<br>
ir_loop::increment).<br>
<br>
(2) ir_clone did not clone ir_loop::counter properly, resulting in the<br>
cloned ir_loop pointing to the source ir_loop's counter.<br>
<br>
(3) ir_hierarchical_visitor did not visit ir_loop::counter, resulting<br>
in the ir_variable being missed by reparenting.<br>
<br>
Additionally, most optimization passes (e.g. loop unrolling) assume<br>
that the variable mentioned by ir_loop::counter is not accessed in the<br>
body of the loop (an assumption which (1) violates).<br>
<br>
The combination of these factors caused a perfect storm in which the<br>
code worked properly nearly all of the time: for loops that got<br>
unrolled, (1) would introduce a double-increment, but loop unrolling<br>
would fail to notice it (since it assumes that ir_loop::counter is not<br>
accessed in the body of the loop), so it would unroll the loop the<br>
correct number of times. For loops that didn't get unrolled, (1)<br>
would introduce a double-increment, but then later when the IR was<br>
cloned for linking, (2) would prevent the loop counter from being<br>
cloned properly, so it would look to further analysis stages like an<br>
independent variable (and hence the double-increment would stop<br>
occurring). At the end of linking, (3) would prevent the loop counter<br>
from being reparented, so it would still belong to the shader object<br>
rather than the linked program object. Provided that the client<br>
program didn't delete the shader object, the memory would never get<br>
reclaimed, and so the shader would function properly.<br>
<br>
However, for loops that didn't get unrolled, if the client program did<br>
delete the shader object, and the memory belonging to the loop counter<br>
got re-used, this could cause a use-after-free bug, leading to a<br>
crash.<br>
<br>
This patch fixes loop_control_visitor, ir_clone, and<br>
ir_hierarchical_visitor to treat ir_loop::counter the same way the<br>
back-ends treat it: as a freshly allocated ir_variable that needs to<br>
be visited and cloned independently of other ir_variables.<br>
<br>
Bugzilla: <a href="https://bugs.freedesktop.org/show_bug.cgi?id=72026" target="_blank">https://bugs.freedesktop.org/show_bug.cgi?id=72026</a><br></blockquote><div><br></div><div>Note: this change is just invasive enough that it probably shouldn't be picked over to stable before the 10.0 release. But I recommend picking it over to stable after the 10.0 release.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
---<br>
src/glsl/ir_clone.cpp | 3 ++-<br>
src/glsl/ir_hv_accept.cpp | 6 ++++++<br>
src/glsl/loop_controls.cpp | 2 +-<br>
3 files changed, 9 insertions(+), 2 deletions(-)<br>
<br>
diff --git a/src/glsl/ir_clone.cpp b/src/glsl/ir_clone.cpp<br>
index 40ed33a..8f57499 100644<br>
--- a/src/glsl/ir_clone.cpp<br>
+++ b/src/glsl/ir_clone.cpp<br>
@@ -163,7 +163,8 @@ ir_loop::clone(void *mem_ctx, struct hash_table *ht) const<br>
new_loop->to = this->to->clone(mem_ctx, ht);<br>
if (this->increment)<br>
new_loop->increment = this->increment->clone(mem_ctx, ht);<br>
- new_loop->counter = counter;<br>
+ if (this->counter)<br>
+ new_loop->counter = this->counter->clone(mem_ctx, ht);<br>
<br>
foreach_iter(exec_list_iterator, iter, this->body_instructions) {<br>
ir_instruction *ir = (ir_instruction *)iter.get();<br>
diff --git a/src/glsl/ir_hv_accept.cpp b/src/glsl/ir_hv_accept.cpp<br>
index 941b25e..a0fe3b9 100644<br>
--- a/src/glsl/ir_hv_accept.cpp<br>
+++ b/src/glsl/ir_hv_accept.cpp<br>
@@ -87,6 +87,12 @@ ir_loop::accept(ir_hierarchical_visitor *v)<br>
if (s != visit_continue)<br>
return (s == visit_continue_with_parent) ? visit_continue : s;<br>
<br>
+ if (this->counter) {<br>
+ s = this->counter->accept(v);<br>
+ if (s != visit_continue)<br>
+ return (s == visit_continue_with_parent) ? visit_continue : s;<br>
+ }<br>
+<br>
s = visit_list_elements(v, &this->body_instructions);<br>
if (s == visit_stop)<br>
return s;<br>
diff --git a/src/glsl/loop_controls.cpp b/src/glsl/loop_controls.cpp<br>
index 2648193..0eb103f 100644<br>
--- a/src/glsl/loop_controls.cpp<br>
+++ b/src/glsl/loop_controls.cpp<br>
@@ -254,7 +254,7 @@ loop_control_visitor::visit_leave(ir_loop *ir)<br>
ir->from = init->clone(ir, NULL);<br>
ir->to = limit->clone(ir, NULL);<br>
ir->increment = lv->increment->clone(ir, NULL);<br>
- ir->counter = lv->var;<br>
+ ir->counter = lv->var->clone(ir, NULL);<br>
ir->cmp = cmp;<br>
<br>
max_iterations = iterations;<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.8.4.2<br>
<br>
</font></span></blockquote></div><br></div></div>