diff options
author | Simon Werbeck <simon.werbeck@gmail.com> | 2014-07-06 19:18:16 +0200 |
---|---|---|
committer | Luca Bruno <luca.bruno@immobiliare.it> | 2014-07-07 14:27:02 +0200 |
commit | 7b6ee1be1e6b958a71911a6d5f5040e385a96a84 (patch) | |
tree | 9d45d6a001888b648c04d4860d7024798b47b7a7 /vala/valasemanticanalyzer.vala | |
parent | 42e78850e9c870e103e5ffcc11db43e8c93a5b84 (diff) | |
download | vala-7b6ee1be1e6b958a71911a6d5f5040e385a96a84.tar.gz |
Detect format string errors when instancing errors
Fixes bug 732530
Diffstat (limited to 'vala/valasemanticanalyzer.vala')
-rw-r--r-- | vala/valasemanticanalyzer.vala | 178 |
1 files changed, 151 insertions, 27 deletions
diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala index 97dad79bf..0cdd8787f 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; |