From c2a2a3a676783956dc3aa2d27e0b481f7d567771 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Fri, 29 Oct 2021 13:23:47 -0400 Subject: [PATCH 1/3] Java: Model java.util.Optional lambda methods Signed-off-by: Jonathan Leitschuh --- .../2021-10-29-optional-lambda-flow.md | 2 + .../semmle/code/java/frameworks/Optional.qll | 11 +++- .../optional/FunctionalTest.java | 58 +++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 java/change-notes/2021-10-29-optional-lambda-flow.md create mode 100644 java/ql/test/library-tests/optional/FunctionalTest.java diff --git a/java/change-notes/2021-10-29-optional-lambda-flow.md b/java/change-notes/2021-10-29-optional-lambda-flow.md new file mode 100644 index 000000000000..caf10cdc9959 --- /dev/null +++ b/java/change-notes/2021-10-29-optional-lambda-flow.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Added data flow models for lambda methods on `java.util.Optional`. diff --git a/java/ql/lib/semmle/code/java/frameworks/Optional.qll b/java/ql/lib/semmle/code/java/frameworks/Optional.qll index 9747de229ea8..411c7c83e24a 100644 --- a/java/ql/lib/semmle/code/java/frameworks/Optional.qll +++ b/java/ql/lib/semmle/code/java/frameworks/Optional.qll @@ -15,7 +15,16 @@ private class OptionalModel extends SummaryModelCsv { "java.util;Optional;false;orElse;;;Argument[0];ReturnValue;value", "java.util;Optional;false;orElseGet;;;Element of Argument[-1];ReturnValue;value", "java.util;Optional;false;orElseThrow;;;Element of Argument[-1];ReturnValue;value", - "java.util;Optional;false;stream;;;Element of Argument[-1];Element of ReturnValue;value" + "java.util;Optional;false;stream;;;Element of Argument[-1];Element of ReturnValue;value", + "java.util;Optional;false;ifPresent;;;Element of Argument[-1];Parameter[0] of Argument[0];value", + "java.util;Optional;false;ifPresentOrElse;;;Element of Argument[-1];Parameter[0] of Argument[0];value", + "java.util;Optional;false;map;;;Element of Argument[-1];Parameter[0] of Argument[0];value", + "java.util;Optional;false;map;;;ReturnValue of Argument[0];Element of ReturnValue;value", + "java.util;Optional;false;flatMap;;;Element of Argument[-1];Parameter[0] of Argument[0];value", + "java.util;Optional;false;flatMap;;;ReturnValue of Argument[0];ReturnValue;value", + "java.util;Optional;false;filter;;;Element of Argument[-1];Parameter[0] of Argument[0];value", + "java.util;Optional;false;or;;;ReturnValue of Argument[0];ReturnValue;value", + "java.util;Optional;false;orElseGet;;;ReturnValue of Argument[0];ReturnValue;value" ] } } diff --git a/java/ql/test/library-tests/optional/FunctionalTest.java b/java/ql/test/library-tests/optional/FunctionalTest.java new file mode 100644 index 000000000000..334ec0004518 --- /dev/null +++ b/java/ql/test/library-tests/optional/FunctionalTest.java @@ -0,0 +1,58 @@ +import java.util.Optional; + +public class FunctionalTest { + String source() { + return null; + } + + void sink(Object o) { + } + + void test() { + Optional o = Optional.of(source()); + o.ifPresent(v -> { + sink(v); // $hasValueFlow + }); + o.ifPresentOrElse(v -> { + sink(v); // $hasValueFlow + }, () -> { + // no-op + }); + o.map(v -> { + sink(v); // $hasValueFlow + return v; + }).ifPresent(v -> { + sink(v); // $hasValueFlow + }); + o.flatMap(v -> { + sink(v); // $hasValueFlow + return Optional.of(v); + }).ifPresent(v -> { + sink(v); // $hasValueFlow + }); + o.flatMap(v -> { + sink(v); // $hasValueFlow + return Optional.of("safe"); + }).ifPresent(v -> { + sink(v); // no value flow + }); + o.filter(v -> { + sink(v); // $hasValueFlow + return true; + }).ifPresent(v -> { + sink(v); // $hasValueFlow + }); + Optional.of("safe").map(v -> { + sink(v); // no value flow + return v; + }).or(() -> o).ifPresent(v -> { + sink(v); // $hasValueFlow + }); + Optional safe = Optional.of("safe"); + o.or(() -> safe).ifPresent(v -> { + sink(v); // $hasValueFlow + }); + String value = safe.orElseGet(() -> source()); + sink(value); // $hasValueFlow + } +} From 9ff426cf234108c7a244fd6929d4abee66481ba5 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 1 Nov 2021 10:59:03 +0000 Subject: [PATCH 2/3] Sort Optional models --- .../semmle/code/java/frameworks/Optional.qll | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/java/ql/lib/semmle/code/java/frameworks/Optional.qll b/java/ql/lib/semmle/code/java/frameworks/Optional.qll index 411c7c83e24a..425442499927 100644 --- a/java/ql/lib/semmle/code/java/frameworks/Optional.qll +++ b/java/ql/lib/semmle/code/java/frameworks/Optional.qll @@ -7,24 +7,24 @@ private class OptionalModel extends SummaryModelCsv { s = [ "java.util;Optional;false;filter;;;Element of Argument[-1];Element of ReturnValue;value", + "java.util;Optional;false;filter;;;Element of Argument[-1];Parameter[0] of Argument[0];value", + "java.util;Optional;false;flatMap;;;Element of Argument[-1];Parameter[0] of Argument[0];value", + "java.util;Optional;false;flatMap;;;ReturnValue of Argument[0];ReturnValue;value", "java.util;Optional;false;get;;;Element of Argument[-1];ReturnValue;value", + "java.util;Optional;false;ifPresent;;;Element of Argument[-1];Parameter[0] of Argument[0];value", + "java.util;Optional;false;ifPresentOrElse;;;Element of Argument[-1];Parameter[0] of Argument[0];value", + "java.util;Optional;false;map;;;Element of Argument[-1];Parameter[0] of Argument[0];value", + "java.util;Optional;false;map;;;ReturnValue of Argument[0];Element of ReturnValue;value", "java.util;Optional;false;of;;;Argument[0];Element of ReturnValue;value", "java.util;Optional;false;ofNullable;;;Argument[0];Element of ReturnValue;value", "java.util;Optional;false;or;;;Element of Argument[-1];Element of ReturnValue;value", + "java.util;Optional;false;or;;;ReturnValue of Argument[0];ReturnValue;value", "java.util;Optional;false;orElse;;;Element of Argument[-1];ReturnValue;value", "java.util;Optional;false;orElse;;;Argument[0];ReturnValue;value", "java.util;Optional;false;orElseGet;;;Element of Argument[-1];ReturnValue;value", + "java.util;Optional;false;orElseGet;;;ReturnValue of Argument[0];ReturnValue;value" "java.util;Optional;false;orElseThrow;;;Element of Argument[-1];ReturnValue;value", "java.util;Optional;false;stream;;;Element of Argument[-1];Element of ReturnValue;value", - "java.util;Optional;false;ifPresent;;;Element of Argument[-1];Parameter[0] of Argument[0];value", - "java.util;Optional;false;ifPresentOrElse;;;Element of Argument[-1];Parameter[0] of Argument[0];value", - "java.util;Optional;false;map;;;Element of Argument[-1];Parameter[0] of Argument[0];value", - "java.util;Optional;false;map;;;ReturnValue of Argument[0];Element of ReturnValue;value", - "java.util;Optional;false;flatMap;;;Element of Argument[-1];Parameter[0] of Argument[0];value", - "java.util;Optional;false;flatMap;;;ReturnValue of Argument[0];ReturnValue;value", - "java.util;Optional;false;filter;;;Element of Argument[-1];Parameter[0] of Argument[0];value", - "java.util;Optional;false;or;;;ReturnValue of Argument[0];ReturnValue;value", - "java.util;Optional;false;orElseGet;;;ReturnValue of Argument[0];ReturnValue;value" ] } } From b59f6665a292065262ca60ec74ea8538fade0271 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 1 Nov 2021 11:02:58 +0000 Subject: [PATCH 3/3] Fix punctuation --- java/ql/lib/semmle/code/java/frameworks/Optional.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/lib/semmle/code/java/frameworks/Optional.qll b/java/ql/lib/semmle/code/java/frameworks/Optional.qll index 425442499927..7e7baf157d8c 100644 --- a/java/ql/lib/semmle/code/java/frameworks/Optional.qll +++ b/java/ql/lib/semmle/code/java/frameworks/Optional.qll @@ -22,9 +22,9 @@ private class OptionalModel extends SummaryModelCsv { "java.util;Optional;false;orElse;;;Element of Argument[-1];ReturnValue;value", "java.util;Optional;false;orElse;;;Argument[0];ReturnValue;value", "java.util;Optional;false;orElseGet;;;Element of Argument[-1];ReturnValue;value", - "java.util;Optional;false;orElseGet;;;ReturnValue of Argument[0];ReturnValue;value" + "java.util;Optional;false;orElseGet;;;ReturnValue of Argument[0];ReturnValue;value", "java.util;Optional;false;orElseThrow;;;Element of Argument[-1];ReturnValue;value", - "java.util;Optional;false;stream;;;Element of Argument[-1];Element of ReturnValue;value", + "java.util;Optional;false;stream;;;Element of Argument[-1];Element of ReturnValue;value" ] } }