Java: Inline models as data expected output as comments in the java files and add a test.

This commit is contained in:
Michael Nebel
2024-05-06 11:01:23 +02:00
parent 6815bcaa80
commit 7cb8a6c52f
14 changed files with 439 additions and 393 deletions

View File

@@ -0,0 +1,2 @@
unexpectedSummary
expectedSummary

View File

@@ -0,0 +1,11 @@
import java
import utils.modelgenerator.internal.CaptureSummaryFlowQuery
import TestUtilities.InlineMadTest
module InlineMadTestConfig implements InlineMadTestConfigSig {
string getComment() { result = any(Javadoc doc).getChild(0).toString() }
string getCapturedSummary() { result = captureFlow(_) }
}
import InlineMadTest<InlineMadTestConfig>

View File

@@ -2,29 +2,31 @@ package p;
public final class Factory {
private String value;
private String value;
private int intValue;
private int intValue;
public static Factory create(String value, int foo) {
return new Factory(value, foo);
}
// MaD=p;Factory;false;create;(String,int);;Argument[0];ReturnValue;taint;df-generated
public static Factory create(String value, int foo) {
return new Factory(value, foo);
}
public static Factory create(String value) {
return new Factory(value, 0);
}
// MaD=p;Factory;false;create;(String);;Argument[0];ReturnValue;taint;df-generated
public static Factory create(String value) {
return new Factory(value, 0);
}
private Factory(String value, int intValue) {
this.value = value;
this.intValue = intValue;
}
private Factory(String value, int intValue) {
this.value = value;
this.intValue = intValue;
}
public String getValue() {
return value;
}
// MaD=p;Factory;false;getValue;();;Argument[this];ReturnValue;taint;df-generated
public String getValue() {
return value;
}
public int getIntValue() {
return intValue;
}
}
public int getIntValue() {
return intValue;
}
}

View File

@@ -2,14 +2,14 @@ package p;
public final class FinalClass {
private static final String C = "constant";
private static final String C = "constant";
public String returnsInput(String input) {
return input;
}
// MaD=p;FinalClass;false;returnsInput;(String);;Argument[0];ReturnValue;taint;df-generated
public String returnsInput(String input) {
return input;
}
public String returnsConstant() {
return C;
}
}
public String returnsConstant() {
return C;
}
}

View File

@@ -2,14 +2,14 @@ package p;
public final class FluentAPI {
public FluentAPI returnsThis(String input) {
return this;
}
// MaD=p;FluentAPI;false;returnsThis;(String);;Argument[this];ReturnValue;value;df-generated
public FluentAPI returnsThis(String input) {
return this;
}
public class Inner {
public FluentAPI notThis(String input) {
return FluentAPI.this;
}
public class Inner {
public FluentAPI notThis(String input) {
return FluentAPI.this;
}
}
}
}

View File

@@ -2,25 +2,28 @@ package p;
public final class ImmutablePojo {
private final String value;
private final String value;
private final long x;
private final long x;
public ImmutablePojo(String value, int x) {
this.value = value;
this.x = x;
}
// MaD=p;ImmutablePojo;false;ImmutablePojo;(String,int);;Argument[0];Argument[this];taint;df-generated
public ImmutablePojo(String value, int x) {
this.value = value;
this.x = x;
}
public String getValue() {
return value;
}
// MaD=p;ImmutablePojo;false;getValue;();;Argument[this];ReturnValue;taint;df-generated
public String getValue() {
return value;
}
public long getX() {
return x;
}
public long getX() {
return x;
}
public String or(String defaultValue) {
return value != null ? value : defaultValue;
}
}
// MaD=p;ImmutablePojo;false;or;(String);;Argument[0];ReturnValue;taint;df-generated
// MaD=p;ImmutablePojo;false;or;(String);;Argument[this];ReturnValue;taint;df-generated
public String or(String defaultValue) {
return value != null ? value : defaultValue;
}
}

View File

@@ -1,21 +1,22 @@
package p;
public class InnerClasses {
class IgnoreMe {
public String no(String input) {
return input;
}
}
public class CaptureMe {
public String yesCm(String input) {
return input;
}
}
public String yes(String input) {
return input;
class IgnoreMe {
public String no(String input) {
return input;
}
}
public class CaptureMe {
// MaD=p;InnerClasses$CaptureMe;true;yesCm;(String);;Argument[0];ReturnValue;taint;df-generated
public String yesCm(String input) {
return input;
}
}
// MaD=p;InnerClasses;true;yes;(String);;Argument[0];ReturnValue;taint;df-generated
public String yes(String input) {
return input;
}
}

View File

@@ -2,36 +2,39 @@ package p;
public final class InnerHolder {
private class Context {
private String value;
private class Context {
private String value;
Context(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
private Context context = null;
private StringBuilder sb = new StringBuilder();
public void setContext(String value) {
context = new Context(value);
}
public void explicitSetContext(String value) {
this.context = new Context(value);
}
public void append(String value) {
sb.append(value);
Context(String value) {
this.value = value;
}
public String getValue() {
return context.getValue();
return value;
}
}
}
private Context context = null;
private StringBuilder sb = new StringBuilder();
// MaD=p;InnerHolder;false;setContext;(String);;Argument[0];Argument[this];taint;df-generated
public void setContext(String value) {
context = new Context(value);
}
// MaD=p;InnerHolder;false;explicitSetContext;(String);;Argument[0];Argument[this];taint;df-generated
public void explicitSetContext(String value) {
this.context = new Context(value);
}
// MaD=p;InnerHolder;false;append;(String);;Argument[0];Argument[this];taint;df-generated
public void append(String value) {
sb.append(value);
}
// MaD=p;InnerHolder;false;getValue;();;Argument[this];ReturnValue;taint;df-generated
public String getValue() {
return context.getValue();
}
}

View File

@@ -4,115 +4,122 @@ import java.util.Arrays;
import java.util.Objects;
public final class Joiner {
private final String prefix;
private final String delimiter;
private final String suffix;
private String[] elts;
private int size;
private int len;
private String emptyValue;
public Joiner(CharSequence delimiter) {
this(delimiter, "", "");
}
private final String prefix;
private final String delimiter;
private final String suffix;
private String[] elts;
private int size;
private int len;
private String emptyValue;
public Joiner(CharSequence delimiter,
CharSequence prefix,
CharSequence suffix) {
Objects.requireNonNull(prefix, "The prefix must not be null");
Objects.requireNonNull(delimiter, "The delimiter must not be null");
Objects.requireNonNull(suffix, "The suffix must not be null");
this.prefix = prefix.toString();
this.delimiter = delimiter.toString();
this.suffix = suffix.toString();
checkAddLength(0, 0);
}
// MaD=p;Joiner;false;Joiner;(CharSequence);;Argument[0];Argument[this];taint;df-generated
public Joiner(CharSequence delimiter) {
this(delimiter, "", "");
}
public Joiner setEmptyValue(CharSequence emptyValue) {
this.emptyValue = Objects.requireNonNull(emptyValue,
"The empty value must not be null").toString();
return this;
}
// MaD=p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[0];Argument[this];taint;df-generated
// MaD=p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[1];Argument[this];taint;df-generated
// MaD=p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[2];Argument[this];taint;df-generated
public Joiner(CharSequence delimiter, CharSequence prefix, CharSequence suffix) {
Objects.requireNonNull(prefix, "The prefix must not be null");
Objects.requireNonNull(delimiter, "The delimiter must not be null");
Objects.requireNonNull(suffix, "The suffix must not be null");
this.prefix = prefix.toString();
this.delimiter = delimiter.toString();
this.suffix = suffix.toString();
checkAddLength(0, 0);
}
private static int getChars(String s, char[] chars, int start) {
int len = s.length();
s.getChars(0, len, chars, start);
return len;
}
// MaD=p;Joiner;false;setEmptyValue;(CharSequence);;Argument[0];Argument[this];taint;df-generated
// MaD=p;Joiner;false;setEmptyValue;(CharSequence);;Argument[this];ReturnValue;value;df-generated
public Joiner setEmptyValue(CharSequence emptyValue) {
this.emptyValue =
Objects.requireNonNull(emptyValue, "The empty value must not be null").toString();
return this;
}
@Override
public String toString() {
final String[] elts = this.elts;
if (elts == null && emptyValue != null) {
return emptyValue;
}
final int size = this.size;
final int addLen = prefix.length() + suffix.length();
if (addLen == 0) {
compactElts();
return size == 0 ? "" : elts[0];
}
final String delimiter = this.delimiter;
final char[] chars = new char[len + addLen];
int k = getChars(prefix, chars, 0);
if (size > 0) {
k += getChars(elts[0], chars, k);
for (int i = 1; i < size; i++) {
k += getChars(delimiter, chars, k);
k += getChars(elts[i], chars, k);
}
}
k += getChars(suffix, chars, k);
return new String(chars);
}
private static int getChars(String s, char[] chars, int start) {
int len = s.length();
s.getChars(0, len, chars, start);
return len;
}
public Joiner add(CharSequence newElement) {
final String elt = String.valueOf(newElement);
if (elts == null) {
elts = new String[8];
} else {
if (size == elts.length)
elts = Arrays.copyOf(elts, 2 * size);
len = checkAddLength(len, delimiter.length());
}
len = checkAddLength(len, elt.length());
elts[size++] = elt;
return this;
@Override
public String toString() {
final String[] elts = this.elts;
if (elts == null && emptyValue != null) {
return emptyValue;
}
final int size = this.size;
final int addLen = prefix.length() + suffix.length();
if (addLen == 0) {
compactElts();
return size == 0 ? "" : elts[0];
}
final String delimiter = this.delimiter;
final char[] chars = new char[len + addLen];
int k = getChars(prefix, chars, 0);
if (size > 0) {
k += getChars(elts[0], chars, k);
for (int i = 1; i < size; i++) {
k += getChars(delimiter, chars, k);
k += getChars(elts[i], chars, k);
}
}
k += getChars(suffix, chars, k);
return new String(chars);
}
private int checkAddLength(int oldLen, int inc) {
long newLen = (long)oldLen + (long)inc;
long tmpLen = newLen + (long)prefix.length() + (long)suffix.length();
if (tmpLen != (int)tmpLen) {
throw new OutOfMemoryError("Requested array size exceeds VM limit");
}
return (int)newLen;
// MaD=p;Joiner;false;add;(CharSequence);;Argument[this];ReturnValue;value;df-generated
public Joiner add(CharSequence newElement) {
final String elt = String.valueOf(newElement);
if (elts == null) {
elts = new String[8];
} else {
if (size == elts.length) elts = Arrays.copyOf(elts, 2 * size);
len = checkAddLength(len, delimiter.length());
}
len = checkAddLength(len, elt.length());
elts[size++] = elt;
return this;
}
public Joiner merge(Joiner other) {
Objects.requireNonNull(other);
if (other.elts == null) {
return this;
}
other.compactElts();
return add(other.elts[0]);
private int checkAddLength(int oldLen, int inc) {
long newLen = (long) oldLen + (long) inc;
long tmpLen = newLen + (long) prefix.length() + (long) suffix.length();
if (tmpLen != (int) tmpLen) {
throw new OutOfMemoryError("Requested array size exceeds VM limit");
}
return (int) newLen;
}
private void compactElts() {
if (size > 1) {
final char[] chars = new char[len];
int i = 1, k = getChars(elts[0], chars, 0);
do {
k += getChars(delimiter, chars, k);
k += getChars(elts[i], chars, k);
elts[i] = null;
} while (++i < size);
size = 1;
elts[0] = new String(chars);
}
// MaD=p;Joiner;false;merge;(Joiner);;Argument[this];ReturnValue;value;df-generated
public Joiner merge(Joiner other) {
Objects.requireNonNull(other);
if (other.elts == null) {
return this;
}
other.compactElts();
return add(other.elts[0]);
}
public int length() {
return (size == 0 && emptyValue != null) ? emptyValue.length() :
len + prefix.length() + suffix.length();
private void compactElts() {
if (size > 1) {
final char[] chars = new char[len];
int i = 1, k = getChars(elts[0], chars, 0);
do {
k += getChars(delimiter, chars, k);
k += getChars(elts[i], chars, k);
elts[i] = null;
} while (++i < size);
size = 1;
elts[0] = new String(chars);
}
}
}
public int length() {
return (size == 0 && emptyValue != null)
? emptyValue.length()
: len + prefix.length() + suffix.length();
}
}

View File

@@ -2,22 +2,23 @@ package p;
class MultipleImpl2 {
// Multiple implementations of the same interface.
// This is used to test that we only generate a summary model and
// not neutral summary model for `IInterface.m`.
public interface IInterface {
Object m(Object value);
}
// Multiple implementations of the same interface.
// This is used to test that we only generate a summary model and
// not neutral summary model for `IInterface.m`.
public interface IInterface {
// MaD=p;MultipleImpl2$IInterface;true;m;(Object);;Argument[0];ReturnValue;taint;df-generated
Object m(Object value);
}
public class Impl1 implements IInterface {
public Object m(Object value) {
return null;
}
public class Impl1 implements IInterface {
public Object m(Object value) {
return null;
}
}
public class Impl2 implements IInterface {
public Object m(Object value) {
return value;
}
public class Impl2 implements IInterface {
public Object m(Object value) {
return value;
}
}
}

View File

@@ -4,35 +4,38 @@ import java.util.concurrent.Callable;
public class MultipleImpls {
public static interface Strategy {
String doSomething(String value);
public static interface Strategy {
// MaD=p;MultipleImpls$Strategy;true;doSomething;(String);;Argument[0];Argument[this];taint;df-generated
// MaD=p;MultipleImpls$Strategy;true;doSomething;(String);;Argument[0];ReturnValue;taint;df-generated
String doSomething(String value);
}
public static class Strat1 implements Strategy {
public String doSomething(String value) {
return value;
}
}
// implements in different library should not count as impl
public static class Strat3 implements Callable<String> {
@Override
public String call() throws Exception {
return null;
}
}
public static class Strat2 implements Strategy {
private String foo;
public String doSomething(String value) {
this.foo = value;
return "none";
}
public static class Strat1 implements Strategy {
public String doSomething(String value) {
return value;
}
}
// implements in different library should not count as impl
public static class Strat3 implements Callable<String> {
@Override
public String call() throws Exception {
return null;
}
}
public static class Strat2 implements Strategy {
private String foo;
public String doSomething(String value) {
this.foo = value;
return "none";
}
public String getValue() {
return this.foo;
}
// MaD=p;MultipleImpls$Strat2;true;getValue;();;Argument[this];ReturnValue;taint;df-generated
public String getValue() {
return this.foo;
}
}
}

View File

@@ -1,64 +1,71 @@
package p;
import java.util.Iterator;
import java.util.List;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
public class ParamFlow {
public String returnsInput(String input) {
return input;
}
// MaD=p;ParamFlow;true;returnsInput;(String);;Argument[0];ReturnValue;taint;df-generated
public String returnsInput(String input) {
return input;
}
public int ignorePrimitiveReturnValue(String input) {
return input.length();
}
public int ignorePrimitiveReturnValue(String input) {
return input.length();
}
public String returnMultipleParameters(String one, String two) {
if (System.currentTimeMillis() > 100) {
return two;
}
return one;
// MaD=p;ParamFlow;true;returnMultipleParameters;(String,String);;Argument[0];ReturnValue;taint;df-generated
// MaD=p;ParamFlow;true;returnMultipleParameters;(String,String);;Argument[1];ReturnValue;taint;df-generated
public String returnMultipleParameters(String one, String two) {
if (System.currentTimeMillis() > 100) {
return two;
}
return one;
}
public String returnArrayElement(String[] input) {
return input[0];
}
// MaD=p;ParamFlow;true;returnArrayElement;(String[]);;Argument[0].ArrayElement;ReturnValue;taint;df-generated
public String returnArrayElement(String[] input) {
return input[0];
}
public String returnVarArgElement(String... input) {
return input[0];
}
// MaD=p;ParamFlow;true;returnVarArgElement;(String[]);;Argument[0].ArrayElement;ReturnValue;taint;df-generated
public String returnVarArgElement(String... input) {
return input[0];
}
public String returnCollectionElement(List<String> input) {
return input.get(0);
}
// MaD=p;ParamFlow;true;returnCollectionElement;(List);;Argument[0].Element;ReturnValue;taint;df-generated
public String returnCollectionElement(List<String> input) {
return input.get(0);
}
public String returnIteratorElement(Iterator<String> input) {
return input.next();
}
// MaD=p;ParamFlow;true;returnIteratorElement;(Iterator);;Argument[0].Element;ReturnValue;taint;df-generated
public String returnIteratorElement(Iterator<String> input) {
return input.next();
}
public String returnIterableElement(Iterable<String> input) {
return input.iterator().next();
}
// MaD=p;ParamFlow;true;returnIterableElement;(Iterable);;Argument[0].Element;ReturnValue;taint;df-generated
public String returnIterableElement(Iterable<String> input) {
return input.iterator().next();
}
public Class<?> mapType(Class<?> input) {
return input;
}
public Class<?> mapType(Class<?> input) {
return input;
}
public void writeChunked(byte[] data, OutputStream output)
throws IOException {
output.write(data, 0, data.length);
}
public void writeChunked(char[] data, OutputStream output)
throws IOException {
output.write(String.valueOf(data).getBytes(), 0, data.length);
}
// MaD=p;ParamFlow;true;writeChunked;(byte[],OutputStream);;Argument[0];Argument[1];taint;df-generated
public void writeChunked(byte[] data, OutputStream output) throws IOException {
output.write(data, 0, data.length);
}
public void addTo(String data, List<String> target) {
target.add(data);
}
// MaD=p;ParamFlow;true;writeChunked;(char[],OutputStream);;Argument[0];Argument[1];taint;df-generated
public void writeChunked(char[] data, OutputStream output) throws IOException {
output.write(String.valueOf(data).getBytes(), 0, data.length);
}
}
// MaD=p;ParamFlow;true;addTo;(String,List);;Argument[0];Argument[1].Element;taint;df-generated
public void addTo(String data, List<String> target) {
target.add(data);
}
}

View File

@@ -8,91 +8,97 @@ import java.util.List;
public final class Pojo {
private class Holder {
private String value;
Holder(String value) {
this.value = value;
}
int length() {
return value.length();
}
}
private class Holder {
private String value;
private int intValue = 2;
private byte[] byteArray = new byte[] {1, 2, 3} ;
private float[] floatArray = new float[] {1, 2, 3} ;
private char[] charArray = new char[] {'a', 'b', 'c'} ;
private List<Character> charList = Arrays.asList('a', 'b', 'c');
private Byte[] byteObjectArray = new Byte[] { 1, 2, 3 };
public String getValue() {
return value;
Holder(String value) {
this.value = value;
}
public void setValue(String value) {
this.value = value;
int length() {
return value.length();
}
}
public int doNotSetValue(String value) {
Holder h = new Holder(value);
return h.length();
}
private String value;
public int getIntValue() {
return intValue;
}
private int intValue = 2;
public Integer getBoxedValue() {
return Integer.valueOf(intValue);
}
private byte[] byteArray = new byte[] {1, 2, 3};
private float[] floatArray = new float[] {1, 2, 3};
private char[] charArray = new char[] {'a', 'b', 'c'};
private List<Character> charList = Arrays.asList('a', 'b', 'c');
private Byte[] byteObjectArray = new Byte[] {1, 2, 3};
public int[] getPrimitiveArray() {
return new int[] { intValue };
}
// MaD=p;Pojo;false;getValue;();;Argument[this];ReturnValue;taint;df-generated
public String getValue() {
return value;
}
public char[] getCharArray() {
return charArray;
}
// MaD=p;Pojo;false;setValue;(String);;Argument[0];Argument[this];taint;df-generated
public void setValue(String value) {
this.value = value;
}
public byte[] getByteArray() {
return byteArray;
}
public float[] getFloatArray() {
return floatArray;
}
public int doNotSetValue(String value) {
Holder h = new Holder(value);
return h.length();
}
public Integer[] getBoxedArray() {
return new Integer[] { Integer.valueOf(intValue) };
}
public Collection<Integer> getBoxedCollection() {
return List.of(Integer.valueOf(intValue));
}
public int getIntValue() {
return intValue;
}
public List<Character> getBoxedChars() {
return charList;
}
public Integer getBoxedValue() {
return Integer.valueOf(intValue);
}
public Byte[] getBoxedBytes() {
return byteObjectArray;
}
public BigInteger getBigInt() {
return BigInteger.valueOf(intValue);
}
public int[] getPrimitiveArray() {
return new int[] {intValue};
}
public BigDecimal getBigDecimal() {
return new BigDecimal(value);
}
// MaD=p;Pojo;false;getCharArray;();;Argument[this];ReturnValue;taint;df-generated
public char[] getCharArray() {
return charArray;
}
public void fillIn(List<String> target) {
target.add(value);
}
// MaD=p;Pojo;false;getByteArray;();;Argument[this];ReturnValue;taint;df-generated
public byte[] getByteArray() {
return byteArray;
}
}
public float[] getFloatArray() {
return floatArray;
}
public Integer[] getBoxedArray() {
return new Integer[] {Integer.valueOf(intValue)};
}
public Collection<Integer> getBoxedCollection() {
return List.of(Integer.valueOf(intValue));
}
// MaD=p;Pojo;false;getBoxedChars;();;Argument[this];ReturnValue;taint;df-generated
public List<Character> getBoxedChars() {
return charList;
}
// MaD=p;Pojo;false;getBoxedBytes;();;Argument[this];ReturnValue;taint;df-generated
public Byte[] getBoxedBytes() {
return byteObjectArray;
}
public BigInteger getBigInt() {
return BigInteger.valueOf(intValue);
}
public BigDecimal getBigDecimal() {
return new BigDecimal(value);
}
// MaD=p;Pojo;false;fillIn;(List);;Argument[this];Argument[0].Element;taint;df-generated
public void fillIn(List<String> target) {
target.add(value);
}
}

View File

@@ -7,55 +7,55 @@ import java.io.OutputStream;
public class PrivateFlowViaPublicInterface {
static class RandomPojo {
public File someFile = new File("someFile");
}
public static interface SPI {
OutputStream openStream() throws IOException;
static class RandomPojo {
public File someFile = new File("someFile");
}
default OutputStream openStreamNone() throws IOException {
return null;
};
public static interface SPI {
// MaD=p;PrivateFlowViaPublicInterface$SPI;true;openStream;();;Argument[this];ReturnValue;taint;df-generated
OutputStream openStream() throws IOException;
default OutputStream openStreamNone() throws IOException {
return null;
}
;
}
private static final class PrivateImplWithSink implements SPI {
private File file;
public PrivateImplWithSink(File file) {
this.file = file;
}
private static final class PrivateImplWithSink implements SPI {
private File file;
public PrivateImplWithSink(File file) {
this.file = file;
}
@Override
public OutputStream openStream() throws IOException {
return new FileOutputStream(file);
}
@Override
public OutputStream openStream() throws IOException {
return new FileOutputStream(file);
}
private static final class PrivateImplWithRandomField implements SPI {
}
public PrivateImplWithRandomField(File file) {
}
private static final class PrivateImplWithRandomField implements SPI {
@Override
public OutputStream openStream() throws IOException {
return null;
}
@Override
public OutputStream openStreamNone() throws IOException {
return new FileOutputStream(new RandomPojo().someFile);
}
public PrivateImplWithRandomField(File file) {}
@Override
public OutputStream openStream() throws IOException {
return null;
}
public static SPI createAnSPI(File file) {
return new PrivateImplWithSink(file);
}
public static SPI createAnSPIWithoutTrackingFile(File file) {
return new PrivateImplWithRandomField(file);
@Override
public OutputStream openStreamNone() throws IOException {
return new FileOutputStream(new RandomPojo().someFile);
}
}
}
// MaD=p;PrivateFlowViaPublicInterface;true;createAnSPI;(File);;Argument[0];ReturnValue;taint;df-generated
public static SPI createAnSPI(File file) {
return new PrivateImplWithSink(file);
}
public static SPI createAnSPIWithoutTrackingFile(File file) {
return new PrivateImplWithRandomField(file);
}
}