[vala] Detect format string errors when instancing errors



commit 7b6ee1be1e6b958a71911a6d5f5040e385a96a84
Author: Simon Werbeck <simon werbeck gmail com>
Date:   Sun Jul 6 19:18:16 2014 +0200

    Detect format string errors when instancing errors
    
    Fixes bug 732530

 vala/valamethodcall.vala               |  115 +--------------------
 vala/valaobjectcreationexpression.vala |   16 +++
 vala/valasemanticanalyzer.vala         |  178 +++++++++++++++++++++++++++-----
 3 files changed, 168 insertions(+), 141 deletions(-)
---
diff --git a/vala/valamethodcall.vala b/vala/valamethodcall.vala
index 077131c..efce548 100644
--- a/vala/valamethodcall.vala
+++ b/vala/valamethodcall.vala
@@ -443,120 +443,7 @@ public class Vala.MethodCall : Expression {
                        }
                        if (format_literal != null) {
                                string format = format_literal.eval ();
-
-                               bool unsupported_format = false;
-
-                               weak string format_it = format;
-                               unichar c = format_it.get_char ();
-                               while (c != '\0') {
-                                       if (c != '%') {
-                                               format_it = format_it.next_char ();
-                                               c = format_it.get_char ();
-                                               continue;
-                                       }
-
-                                       format_it = format_it.next_char ();
-                                       c = format_it.get_char ();
-                                       // flags
-                                       while (c == '#' || c == '0' || c == '-' || c == ' ' || c == '+') {
-                                               format_it = format_it.next_char ();
-                                               c = format_it.get_char ();
-                                       }
-                                       // field width
-                                       while (c >= '0' && c <= '9') {
-                                               format_it = format_it.next_char ();
-                                               c = format_it.get_char ();
-                                       }
-                                       // precision
-                                       if (c == '.') {
-                                               format_it = format_it.next_char ();
-                                               c = format_it.get_char ();
-                                               while (c >= '0' && c <= '9') {
-                                                       format_it = format_it.next_char ();
-                                                       c = format_it.get_char ();
-                                               }
-                                       }
-                                       // length modifier
-                                       int length = 0;
-                                       if (c == 'h') {
-                                               length = -1;
-                                               format_it = format_it.next_char ();
-                                               c = format_it.get_char ();
-                                               if (c == 'h') {
-                                                       length = -2;
-                                                       format_it = format_it.next_char ();
-                                                       c = format_it.get_char ();
-                                               }
-                                       } else if (c == 'l') {
-                                               length = 1;
-                                               format_it = format_it.next_char ();
-                                               c = format_it.get_char ();
-                                       } else if (c == 'z') {
-                                               length = 2;
-                                               format_it = format_it.next_char ();
-                                               c = format_it.get_char ();
-                                       }
-                                       // conversion specifier
-                                       DataType param_type = null;
-                                       if (c == 'd' || c == 'i' || c == 'c') {
-                                               // integer
-                                               if (length == -2) {
-                                                       param_type = context.analyzer.int8_type;
-                                               } else if (length == -1) {
-                                                       param_type = context.analyzer.short_type;
-                                               } else if (length == 0) {
-                                                       param_type = context.analyzer.int_type;
-                                               } else if (length == 1) {
-                                                       param_type = context.analyzer.long_type;
-                                               } else if (length == 2) {
-                                                       param_type = context.analyzer.ssize_t_type;
-                                               }
-                                       } else if (c == 'o' || c == 'u' || c == 'x' || c == 'X') {
-                                               // unsigned integer
-                                               if (length == -2) {
-                                                       param_type = context.analyzer.uchar_type;
-                                               } else if (length == -1) {
-                                                       param_type = context.analyzer.ushort_type;
-                                               } else if (length == 0) {
-                                                       param_type = context.analyzer.uint_type;
-                                               } else if (length == 1) {
-                                                       param_type = context.analyzer.ulong_type;
-                                               } else if (length == 2) {
-                                                       param_type = context.analyzer.size_t_type;
-                                               }
-                                       } else if (c == 'e' || c == 'E' || c == 'f' || c == 'F'
-                                                  || c == 'g' || c == 'G' || c == 'a' || c == 'A') {
-                                               // double
-                                               param_type = context.analyzer.double_type;
-                                       } else if (c == 's') {
-                                               // string
-                                               param_type = context.analyzer.string_type;
-                                       } else if (c == 'p') {
-                                               // pointer
-                                               param_type = new PointerType (new VoidType ());
-                                       } else if (c == '%') {
-                                               // literal %
-                                       } else {
-                                               unsupported_format = true;
-                                               break;
-                                       }
-                                       if (c != '\0') {
-                                               format_it = format_it.next_char ();
-                                               c = format_it.get_char ();
-                                       }
-                                       if (param_type != null) {
-                                               if (arg_it.next ()) {
-                                                       Expression arg = arg_it.get ();
-
-                                                       arg.target_type = param_type;
-                                               } else {
-                                                       Report.error (source_reference, "Too few arguments 
for specified format");
-                                                       return false;
-                                               }
-                                       }
-                               }
-                               if (!unsupported_format && arg_it.next ()) {
-                                       Report.error (source_reference, "Too many arguments for specified 
format");
+                               if (!context.analyzer.check_print_format (format, arg_it, source_reference)) {
                                        return false;
                                }
                        }
diff --git a/vala/valaobjectcreationexpression.vala b/vala/valaobjectcreationexpression.vala
index 939b8a6..e64b852 100644
--- a/vala/valaobjectcreationexpression.vala
+++ b/vala/valaobjectcreationexpression.vala
@@ -396,6 +396,22 @@ public class Vala.ObjectCreationExpression : Expression {
                                        error = true;
                                        Report.error (source_reference, "Invalid type for argument 1");
                                }
+
+                               var format_literal = ex as StringLiteral;
+                               if (format_literal != null) {
+                                       var format = format_literal.eval ();
+                                       if (!context.analyzer.check_print_format (format, arg_it, 
source_reference)) {
+                                               error = true;
+                                               return false;
+                                       }
+                               }
+
+                               arg_it = get_argument_list ().iterator ();
+                               arg_it.next ();
+                               if (!context.analyzer.check_variadic_arguments (arg_it, 1, source_reference)) 
{
+                                       error = true;
+                                       return false;
+                               }
                        }
                }
 
diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala
index 97dad79..0cdd878 100644
--- a/vala/valasemanticanalyzer.vala
+++ b/vala/valasemanticanalyzer.vala
@@ -446,33 +446,9 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                        }
                }
 
-               if (ellipsis) {
-                       while (arg_it != null && arg_it.next ()) {
-                               var arg = arg_it.get ();
-                               if (arg.error) {
-                                       // ignore inner error
-                                       expr.error = true;
-                                       return false;
-                               } else if (arg.value_type is SignalType) {
-                                       arg.error = true;
-                                       Report.error (arg.source_reference, "Cannot pass signals as 
arguments");
-                                       return false;
-                               } else if (arg.value_type == null) {
-                                       // disallow untyped arguments except for type inference of callbacks
-                                       if (!(arg.symbol_reference is Method)) {
-                                               expr.error = true;
-                                               Report.error (expr.source_reference, "Invalid type for 
argument %d".printf (i + 1));
-                                               return false;
-                                       }
-                               } else if (arg.target_type != null && !arg.value_type.compatible 
(arg.target_type)) {
-                                       // target_type known for printf arguments
-                                       expr.error = true;
-                                       Report.error (arg.source_reference, "Argument %d: Cannot convert from 
`%s' to `%s'".printf (i + 1, arg.value_type.to_string (), arg.target_type.to_string ()));
-                                       return false;
-                               }
-
-                               i++;
-                       }
+               if (ellipsis && !check_variadic_arguments (arg_it, i, expr.source_reference)) {
+                       expr.error = true;
+                       return false;
                } else if (!ellipsis && arg_it != null && arg_it.next ()) {
                        expr.error = true;
                        var m = mtype as MethodType;
@@ -595,6 +571,154 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                return true;
        }
 
+       public bool check_variadic_arguments (Iterator<Expression> arg_it, int i, SourceReference 
source_reference) {
+               while (arg_it != null && arg_it.next ()) {
+                       var arg = arg_it.get ();
+                       if (arg.error) {
+                               // ignore inner error
+                               return false;
+                       } else if (arg.value_type is SignalType) {
+                               arg.error = true;
+                               Report.error (arg.source_reference, "Cannot pass signals as arguments");
+                               return false;
+                       } else if (arg.value_type == null) {
+                               // disallow untyped arguments except for type inference of callbacks
+                               if (!(arg.symbol_reference is Method)) {
+                                       Report.error (source_reference, "Invalid type for argument %d".printf 
(i + 1));
+                                       return false;
+                               }
+                       } else if (arg.target_type != null && !arg.value_type.compatible (arg.target_type)) {
+                               // target_type known for printf arguments
+                               Report.error (arg.source_reference, "Argument %d: Cannot convert from `%s' to 
`%s'".printf (i + 1, arg.value_type.to_string (), arg.target_type.to_string ()));
+                               return false;
+                       }
+
+                       i++;
+               }
+
+               return true;
+       }
+
+       public bool check_print_format (string format, Iterator<Expression> arg_it, SourceReference 
source_reference) {
+               bool unsupported_format = false;
+
+               weak string format_it = format;
+               unichar c = format_it.get_char ();
+               while (c != '\0') {
+                       if (c != '%') {
+                               format_it = format_it.next_char ();
+                               c = format_it.get_char ();
+                               continue;
+                       }
+
+                       format_it = format_it.next_char ();
+                       c = format_it.get_char ();
+                       // flags
+                       while (c == '#' || c == '0' || c == '-' || c == ' ' || c == '+') {
+                               format_it = format_it.next_char ();
+                               c = format_it.get_char ();
+                       }
+                       // field width
+                       while (c >= '0' && c <= '9') {
+                               format_it = format_it.next_char ();
+                               c = format_it.get_char ();
+                       }
+                       // precision
+                       if (c == '.') {
+                               format_it = format_it.next_char ();
+                               c = format_it.get_char ();
+                               while (c >= '0' && c <= '9') {
+                                       format_it = format_it.next_char ();
+                                       c = format_it.get_char ();
+                               }
+                       }
+                       // length modifier
+                       int length = 0;
+                       if (c == 'h') {
+                               length = -1;
+                               format_it = format_it.next_char ();
+                               c = format_it.get_char ();
+                               if (c == 'h') {
+                                       length = -2;
+                                       format_it = format_it.next_char ();
+                                       c = format_it.get_char ();
+                               }
+                       } else if (c == 'l') {
+                               length = 1;
+                               format_it = format_it.next_char ();
+                               c = format_it.get_char ();
+                       } else if (c == 'z') {
+                               length = 2;
+                               format_it = format_it.next_char ();
+                               c = format_it.get_char ();
+                       }
+                       // conversion specifier
+                       DataType param_type = null;
+                       if (c == 'd' || c == 'i' || c == 'c') {
+                               // integer
+                               if (length == -2) {
+                                       param_type = context.analyzer.int8_type;
+                               } else if (length == -1) {
+                                       param_type = context.analyzer.short_type;
+                               } else if (length == 0) {
+                                       param_type = context.analyzer.int_type;
+                               } else if (length == 1) {
+                                       param_type = context.analyzer.long_type;
+                               } else if (length == 2) {
+                                       param_type = context.analyzer.ssize_t_type;
+                               }
+                       } else if (c == 'o' || c == 'u' || c == 'x' || c == 'X') {
+                               // unsigned integer
+                               if (length == -2) {
+                                       param_type = context.analyzer.uchar_type;
+                               } else if (length == -1) {
+                                       param_type = context.analyzer.ushort_type;
+                               } else if (length == 0) {
+                                       param_type = context.analyzer.uint_type;
+                               } else if (length == 1) {
+                                       param_type = context.analyzer.ulong_type;
+                               } else if (length == 2) {
+                                       param_type = context.analyzer.size_t_type;
+                               }
+                       } else if (c == 'e' || c == 'E' || c == 'f' || c == 'F'
+                                          || c == 'g' || c == 'G' || c == 'a' || c == 'A') {
+                               // double
+                               param_type = context.analyzer.double_type;
+                       } else if (c == 's') {
+                               // string
+                               param_type = context.analyzer.string_type;
+                       } else if (c == 'p') {
+                               // pointer
+                               param_type = new PointerType (new VoidType ());
+                       } else if (c == '%') {
+                               // literal %
+                       } else {
+                               unsupported_format = true;
+                               break;
+                       }
+                       if (c != '\0') {
+                               format_it = format_it.next_char ();
+                               c = format_it.get_char ();
+                       }
+                       if (param_type != null) {
+                               if (arg_it.next ()) {
+                                       Expression arg = arg_it.get ();
+
+                                       arg.target_type = param_type;
+                               } else {
+                                       Report.error (source_reference, "Too few arguments for specified 
format");
+                                       return false;
+                               }
+                       }
+               }
+               if (!unsupported_format && arg_it.next ()) {
+                       Report.error (source_reference, "Too many arguments for specified format");
+                       return false;
+               }
+
+               return true;
+       }
+
        private static DataType? get_instance_base_type (DataType instance_type, DataType base_type, CodeNode 
node_reference) {
                // construct a new type reference for the base type with correctly linked type arguments
                ReferenceType instance_base_type;


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