]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
Detect format string errors when instancing errors
authorSimon Werbeck <simon.werbeck@gmail.com>
Sun, 6 Jul 2014 17:18:16 +0000 (19:18 +0200)
committerLuca Bruno <luca.bruno@immobiliare.it>
Mon, 7 Jul 2014 12:27:02 +0000 (14:27 +0200)
Fixes bug 732530

vala/valamethodcall.vala
vala/valaobjectcreationexpression.vala
vala/valasemanticanalyzer.vala

index 077131cc28060fbdbb732a878b7bf14e198e3204..efce5483a184af1a3dc1fb0fe597c9d989f6f2d8 100644 (file)
@@ -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;
                                }
                        }
index 939b8a65cdd9f8a73758233dda7e7cf4e98a82cc..e64b85244a64268b0fa290d51a562c305bf51751 100644 (file)
@@ -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;
+                               }
                        }
                }
 
index 97dad79bf232d6ac92a131c5f41476e63581d487..0cdd8787f893741a17f7c6ec2a1eedc1d0061b7a 100644 (file)
@@ -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;