summaryrefslogtreecommitdiff
path: root/vala/valasemanticanalyzer.vala
diff options
context:
space:
mode:
authorSimon Werbeck <simon.werbeck@gmail.com>2014-07-06 19:18:16 +0200
committerLuca Bruno <luca.bruno@immobiliare.it>2014-07-07 14:27:02 +0200
commit7b6ee1be1e6b958a71911a6d5f5040e385a96a84 (patch)
tree9d45d6a001888b648c04d4860d7024798b47b7a7 /vala/valasemanticanalyzer.vala
parent42e78850e9c870e103e5ffcc11db43e8c93a5b84 (diff)
downloadvala-7b6ee1be1e6b958a71911a6d5f5040e385a96a84.tar.gz
Detect format string errors when instancing errors
Fixes bug 732530
Diffstat (limited to 'vala/valasemanticanalyzer.vala')
-rw-r--r--vala/valasemanticanalyzer.vala178
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;