From a5701db3fafe5fd47201188f067f148e2e9bdfeb Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 17 Aug 2020 15:01:48 +0200 Subject: [PATCH 1/2] Java: Support String.formatted in the format string queries. --- java/ql/src/semmle/code/java/StringFormat.qll | 12 ++++++++++-- java/ql/test/query-tests/StringFormat/A.java | 5 +++++ .../StringFormat/MissingFormatArg.expected | 1 + .../StringFormat/UnusedFormatArg.expected | 1 + java/ql/test/query-tests/StringFormat/options | 1 + 5 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 java/ql/test/query-tests/StringFormat/options diff --git a/java/ql/src/semmle/code/java/StringFormat.qll b/java/ql/src/semmle/code/java/StringFormat.qll index fac84c5c8af0..69e6d4b056e5 100644 --- a/java/ql/src/semmle/code/java/StringFormat.qll +++ b/java/ql/src/semmle/code/java/StringFormat.qll @@ -22,6 +22,7 @@ class StringFormatMethod extends FormatMethod { StringFormatMethod() { ( this.hasName("format") or + this.hasName("formatted") or this.hasName("printf") or this.hasName("readLine") or this.hasName("readPassword") @@ -38,6 +39,8 @@ class StringFormatMethod extends FormatMethod { override int getFormatStringIndex() { result = 0 and this.getSignature() = "format(java.lang.String,java.lang.Object[])" or + result = -1 and this.getSignature() = "formatted(java.lang.Object[])" + or result = 0 and this.getSignature() = "printf(java.lang.String,java.lang.Object[])" or result = 1 and @@ -91,6 +94,11 @@ class FmtSyntax extends TFmtSyntax { predicate isLogger() { this = TFmtLogger() } } +private Expr getArgumentOrQualifier(Call c, int i) { + result = c.getArgument(i) or + result = c.getQualifier() and i = -1 +} + /** * Holds if `c` wraps a call to a `StringFormatMethod`, such that `fmtix` is * the index of the format string argument to `c` and the following and final @@ -111,7 +119,7 @@ private predicate formatWrapper(Callable c, int fmtix, FmtSyntax syntax) { or fmtcall.getCallee().(LoggerFormatMethod).getFormatStringIndex() = i and syntax = TFmtLogger() ) and - fmtcall.getArgument(i) = fmt.getAnAccess() and + getArgumentOrQualifier(fmtcall, i) = fmt.getAnAccess() and fmtcall.getArgument(i + 1) = args.getAnAccess() ) } @@ -155,7 +163,7 @@ class FormattingCall extends Call { } /** Gets the argument to this call in the position of the format string */ - Expr getFormatArgument() { result = this.getArgument(this.getFormatStringIndex()) } + Expr getFormatArgument() { result = getArgumentOrQualifier(this, this.getFormatStringIndex()) } /** Gets an argument to be formatted. */ Expr getAnArgumentToBeFormatted() { diff --git a/java/ql/test/query-tests/StringFormat/A.java b/java/ql/test/query-tests/StringFormat/A.java index 31cba68a622d..ff87290bcc9d 100644 --- a/java/ql/test/query-tests/StringFormat/A.java +++ b/java/ql/test/query-tests/StringFormat/A.java @@ -85,4 +85,9 @@ void g(boolean b, int i) { String.format("%s%s", a2); // ok String.format("%s", a2); // unused } + + void formatted() { + "%s%s".formatted(""); // missing + "%s".formatted("", ""); // unused + } } diff --git a/java/ql/test/query-tests/StringFormat/MissingFormatArg.expected b/java/ql/test/query-tests/StringFormat/MissingFormatArg.expected index c88a74338cf2..fe2e76dd8fa4 100644 --- a/java/ql/test/query-tests/StringFormat/MissingFormatArg.expected +++ b/java/ql/test/query-tests/StringFormat/MissingFormatArg.expected @@ -17,3 +17,4 @@ | A.java:74:5:74:47 | format(...) | This format call refers to 2 argument(s) but only supplies 1 argument(s). | | A.java:79:5:79:31 | format(...) | This format call refers to 3 argument(s) but only supplies 2 argument(s). | | A.java:84:5:84:31 | format(...) | This format call refers to 3 argument(s) but only supplies 2 argument(s). | +| A.java:90:5:90:24 | formatted(...) | This format call refers to 2 argument(s) but only supplies 1 argument(s). | diff --git a/java/ql/test/query-tests/StringFormat/UnusedFormatArg.expected b/java/ql/test/query-tests/StringFormat/UnusedFormatArg.expected index 2cbe4cc2eb1a..b301df54abfe 100644 --- a/java/ql/test/query-tests/StringFormat/UnusedFormatArg.expected +++ b/java/ql/test/query-tests/StringFormat/UnusedFormatArg.expected @@ -9,3 +9,4 @@ | A.java:76:5:76:57 | format(...) | This format call refers to 2 argument(s) but supplies 3 argument(s). | | A.java:81:5:81:27 | format(...) | This format call refers to 1 argument(s) but supplies 2 argument(s). | | A.java:86:5:86:27 | format(...) | This format call refers to 1 argument(s) but supplies 2 argument(s). | +| A.java:91:5:91:26 | formatted(...) | This format call refers to 1 argument(s) but supplies 2 argument(s). | diff --git a/java/ql/test/query-tests/StringFormat/options b/java/ql/test/query-tests/StringFormat/options new file mode 100644 index 000000000000..266b0eadc5e0 --- /dev/null +++ b/java/ql/test/query-tests/StringFormat/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args --enable-preview -source 14 -target 14 From 28578fd5721b4ccae192d21efdcd723091ad6743 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 19 Aug 2020 13:12:24 +0200 Subject: [PATCH 2/2] Java: Autoformat. --- java/ql/src/semmle/code/java/StringFormat.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/StringFormat.qll b/java/ql/src/semmle/code/java/StringFormat.qll index 69e6d4b056e5..6ac122b58d82 100644 --- a/java/ql/src/semmle/code/java/StringFormat.qll +++ b/java/ql/src/semmle/code/java/StringFormat.qll @@ -95,7 +95,8 @@ class FmtSyntax extends TFmtSyntax { } private Expr getArgumentOrQualifier(Call c, int i) { - result = c.getArgument(i) or + result = c.getArgument(i) + or result = c.getQualifier() and i = -1 }