glsl: Fix assert fails when assignment expressions are in array sizes.
authorKenneth Graunke <kenneth@whitecape.org>
Sat, 12 Nov 2016 19:27:17 +0000 (11:27 -0800)
committerKenneth Graunke <kenneth@whitecape.org>
Sun, 13 Nov 2016 06:08:15 +0000 (22:08 -0800)
Karol Herbst's fuzzing efforts discovered that we would hit the
following assert:

   assert(dummy_instructions.is_empty());

when processing an illegal array size expression of

   float[(1=1)?1:1] t;

In do_assignment, we realized we needed an rvalue for (1 = 1), and
generated a temporary variable and assignment from the RHS.  We've
already flagged an error (non-lvalue in assignment), and return a bogus
value as the rvalue.  But process_array_size sees the bogus value, which
happened to be a constant expression, and rightly assumes that
processing a constant expression shouldn't have generated any code.
instructions.

To handle this, make do_assignment not generate any temps or assignments
when it's already raised an error - just return an error value directly.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98694
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Timothy Arceri <timothy.arceri@collabora.com>
src/compiler/glsl/ast_to_hir.cpp

index 24067b6ac0c5eadacfe3923209b9f9147f41a387..9b8678c04aae227cc8b6a42375759739164d39ad 100644 (file)
@@ -1001,17 +1001,20 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state,
     * i = j += 1;
     */
    if (needs_rvalue) {
-      ir_variable *var = new(ctx) ir_variable(rhs->type, "assignment_tmp",
-                                              ir_var_temporary);
-      instructions->push_tail(var);
-      instructions->push_tail(assign(var, rhs));
-
+      ir_rvalue *rvalue;
       if (!error_emitted) {
-         ir_dereference_variable *deref_var = new(ctx) ir_dereference_variable(var);
+         ir_variable *var = new(ctx) ir_variable(rhs->type, "assignment_tmp",
+                                                 ir_var_temporary);
+         instructions->push_tail(var);
+         instructions->push_tail(assign(var, rhs));
+
+         ir_dereference_variable *deref_var =
+            new(ctx) ir_dereference_variable(var);
          instructions->push_tail(new(ctx) ir_assignment(lhs, deref_var));
+         rvalue = new(ctx) ir_dereference_variable(var);
+      } else {
+         rvalue = ir_rvalue::error_value(ctx);
       }
-      ir_rvalue *rvalue = new(ctx) ir_dereference_variable(var);
-
       *out_rvalue = rvalue;
    } else {
       if (!error_emitted)