[vala/wip/issue/1061: 3/4] Force usage of temporary variables for "tainted" member accesses




commit cb1828cfc5273aca752de9b39a77e0cd53305e61
Author: Rico Tzschichholz <ricotz ubuntu com>
Date:   Thu Aug 13 19:05:49 2020 +0200

    Force usage of temporary variables for "tainted" member accesses
    
    This is required to handle the side effect of postfix- and unary-
    increment/decrement expressions.
    
    Regression of 32ffc862417be39d42a1b8eeb3d0748b3e138aff
    and b9035aaf17a9a97a070812a8ee83251fd3893b1e
    
    Fixes https://gitlab.gnome.org/GNOME/vala/issues/1061

 codegen/valaccodebasemodule.vala         |  2 +-
 codegen/valaccodememberaccessmodule.vala | 25 +++++++++++--------
 vala/valacodegenerator.vala              |  6 ++---
 vala/valamemberaccess.vala               | 42 ++++++++++++++++++++++++++++++++
 4 files changed, 61 insertions(+), 14 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 1021c6f69..1720340ce 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -4413,7 +4413,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
 
        public abstract TargetValue get_field_cvalue (Field field, TargetValue? instance);
 
-       public abstract TargetValue load_variable (Variable variable, TargetValue value);
+       public abstract TargetValue load_variable (Variable variable, TargetValue value, Expression? expr = 
null);
 
        public abstract TargetValue load_this_parameter (TypeSymbol sym);
 
diff --git a/codegen/valaccodememberaccessmodule.vala b/codegen/valaccodememberaccessmodule.vala
index 1cec90ac6..f46ea9dfd 100644
--- a/codegen/valaccodememberaccessmodule.vala
+++ b/codegen/valaccodememberaccessmodule.vala
@@ -134,7 +134,7 @@ public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
                        if (expr.lvalue) {
                                expr.target_value = get_field_cvalue (field, expr.inner != null ? 
expr.inner.target_value : null);
                        } else {
-                               expr.target_value = load_field (field, expr.inner != null ? 
expr.inner.target_value : null);
+                               expr.target_value = load_field (field, expr.inner != null ? 
expr.inner.target_value : null, expr);
                        }
                } else if (expr.symbol_reference is EnumValue) {
                        var ev = (EnumValue) expr.symbol_reference;
@@ -389,7 +389,7 @@ public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
                                if (expr.lvalue) {
                                        expr.target_value = get_local_cvalue (local);
                                } else {
-                                       expr.target_value = load_local (local);
+                                       expr.target_value = load_local (local, expr);
                                }
                        }
                } else if (expr.symbol_reference is Parameter) {
@@ -397,7 +397,7 @@ public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
                        if (expr.lvalue) {
                                expr.target_value = get_parameter_cvalue (param);
                        } else {
-                               expr.target_value = load_parameter (param);
+                               expr.target_value = load_parameter (param, expr);
                        }
                }
        }
@@ -732,7 +732,7 @@ public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
                return result;
        }
 
-       public override TargetValue load_variable (Variable variable, TargetValue value) {
+       public override TargetValue load_variable (Variable variable, TargetValue value, Expression? expr = 
null) {
                var result = (GLibValue) value;
                var array_type = result.value_type as ArrayType;
                var delegate_type = result.value_type as DelegateType;
@@ -804,6 +804,11 @@ public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
                        // no need to an extra copy of variables that are stack allocated simple types
                        use_temp = false;
                }
+               // our implementation of postfix-expressions require temporary variables
+               if (expr is MemberAccess && ((MemberAccess) expr).tainted_access) {
+                       use_temp = true;
+               }
+
                var local = variable as LocalVariable;
                if (local != null && local.name[0] == '.') {
                        // already a temporary variable generated internally
@@ -819,13 +824,13 @@ public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
        }
 
        /* Returns unowned access to the given local variable */
-       public override TargetValue load_local (LocalVariable local) {
-               return load_variable (local, get_local_cvalue (local));
+       public override TargetValue load_local (LocalVariable local, Expression? expr = null) {
+               return load_variable (local, get_local_cvalue (local), expr);
        }
 
        /* Returns unowned access to the given parameter */
-       public override TargetValue load_parameter (Parameter param) {
-               return load_variable (param, get_parameter_cvalue (param));
+       public override TargetValue load_parameter (Parameter param, Expression? expr = null) {
+               return load_variable (param, get_parameter_cvalue (param), expr);
        }
 
        /* Convenience method returning access to "this" */
@@ -835,7 +840,7 @@ public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
        }
 
        /* Returns unowned access to the given field */
-       public override TargetValue load_field (Field field, TargetValue? instance) {
-               return load_variable (field, get_field_cvalue (field, instance));
+       public override TargetValue load_field (Field field, TargetValue? instance, Expression? expr = null) {
+               return load_variable (field, get_field_cvalue (field, instance), expr);
        }
 }
diff --git a/vala/valacodegenerator.vala b/vala/valacodegenerator.vala
index cea0db8f6..9452b49a3 100644
--- a/vala/valacodegenerator.vala
+++ b/vala/valacodegenerator.vala
@@ -32,15 +32,15 @@ public abstract class Vala.CodeGenerator : CodeVisitor {
        public virtual void emit (CodeContext context) {
        }
 
-       public abstract TargetValue load_local (LocalVariable local);
+       public abstract TargetValue load_local (LocalVariable local, Expression? expr = null);
 
        public abstract void store_local (LocalVariable local, TargetValue value, bool initializer, 
SourceReference? source_reference = null);
 
-       public abstract TargetValue load_parameter (Parameter param);
+       public abstract TargetValue load_parameter (Parameter param, Expression? expr = null);
 
        public abstract void store_parameter (Parameter param, TargetValue value, bool capturing_parameter = 
false, SourceReference? source_reference = null);
 
-       public abstract TargetValue load_field (Field field, TargetValue? instance);
+       public abstract TargetValue load_field (Field field, TargetValue? instance, Expression? expr = null);
 
        public abstract void store_field (Field field, TargetValue? instance, TargetValue value, 
SourceReference? source_reference = null);
 }
diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala
index d61e2f3fe..ae8c65bdb 100644
--- a/vala/valamemberaccess.vala
+++ b/vala/valamemberaccess.vala
@@ -57,6 +57,11 @@ public class Vala.MemberAccess : Expression {
         */
        public bool prototype_access { get; set; }
 
+       /**
+        * Requires indirect access due to possible side-effects of parent expression.
+        */
+       public bool tainted_access { get; set; }
+
        /**
         * Specifies whether the member is used for object creation.
         */
@@ -992,6 +997,11 @@ public class Vala.MemberAccess : Expression {
                        value_type.check (context);
                }
 
+               // Provide some extra information for the code generator
+               if (!tainted_access) {
+                       tainted_access = is_tainted ();
+               }
+
                return !error;
        }
 
@@ -1075,4 +1085,36 @@ public class Vala.MemberAccess : Expression {
                        collection.add (param);
                }
        }
+
+       bool is_tainted () {
+               unowned CodeNode node = this;
+               if (node.parent_node is MemberAccess) {
+                       return false;
+               }
+
+               while (node.parent_node is Expression) {
+                       node = node.parent_node;
+                       if (node is Assignment || node is MethodCall) {
+                               break;
+                       }
+               }
+
+               bool found = false;
+               var traverse = new TraverseVisitor ((n) => {
+                       if (n is PostfixExpression) {
+                               found = true;
+                               return TraverseStatus.STOP;
+                       } else if (n is UnaryExpression) {
+                               unowned UnaryExpression e = (UnaryExpression) n;
+                               if (e.operator == UnaryOperator.INCREMENT || e.operator == 
UnaryOperator.DECREMENT) {
+                                       found = true;
+                                       return TraverseStatus.STOP;
+                               }
+                       }
+                       return TraverseStatus.CONTINUE;
+               });
+               node.accept (traverse);
+
+               return found;
+       }
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]