From: Rico Tzschichholz Date: Thu, 13 Aug 2020 17:05:49 +0000 (+0200) Subject: Force usage of temporary variables for "tainted" member accesses X-Git-Tag: 0.40.24~24 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5f9fccc891280246d7af1f9866de723f4ec2f490;p=thirdparty%2Fvala.git 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 --- diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala index 46fb30773..a58caef9d 100644 --- a/codegen/valaccodebasemodule.vala +++ b/codegen/valaccodebasemodule.vala @@ -4249,7 +4249,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 4bc19baf7..56c27bf89 100644 --- a/codegen/valaccodememberaccessmodule.vala +++ b/codegen/valaccodememberaccessmodule.vala @@ -117,7 +117,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; @@ -345,7 +345,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) { @@ -353,7 +353,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); } } } @@ -699,7 +699,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; @@ -767,6 +767,11 @@ public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule { // except for structs that are always passed by reference 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 @@ -782,13 +787,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" */ @@ -798,7 +803,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 869e0282c..56d669c65 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. */ @@ -932,6 +937,11 @@ public class Vala.MemberAccess : Expression { } } + // Provide some extra information for the code generator + if (!tainted_access) { + tainted_access = is_tainted (); + } + return !error; } @@ -1015,4 +1025,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 || node is ObjectCreationExpression) { + 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; + } }