mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge branch 'main' into sj-patch-1
This commit is contained in:
21
.github/workflows/check-change-note.yml
vendored
Normal file
21
.github/workflows/check-change-note.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [labeled, unlabeled, opened, synchronize, reopened, ready_for_review]
|
||||
paths:
|
||||
- "*/ql/src/**/*.ql"
|
||||
- "*/ql/src/**/*.qll"
|
||||
- "!**/experimental/**"
|
||||
|
||||
jobs:
|
||||
check-change-note:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fail if no change note found. To fix, either add one, or add the `no-change-note-required` label.
|
||||
if: |
|
||||
github.event.pull_request.draft == false &&
|
||||
!contains(github.event.pull_request.labels.*.name, 'no-change-note-required')
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh api 'repos/${{github.repository}}/pulls/${{github.event.number}}/files' --paginate |
|
||||
jq 'any(.[].filename ; test("/change-notes/.*[.]md$"))' --exit-status
|
||||
4
.github/workflows/codeql-analysis.yml
vendored
4
.github/workflows/codeql-analysis.yml
vendored
@@ -5,10 +5,14 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- 'rc/*'
|
||||
paths:
|
||||
- 'csharp/**'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- 'rc/*'
|
||||
paths:
|
||||
- 'csharp/**'
|
||||
schedule:
|
||||
- cron: '0 9 * * 1'
|
||||
|
||||
|
||||
10
CODEOWNERS
10
CODEOWNERS
@@ -4,17 +4,9 @@
|
||||
/javascript/ @github/codeql-javascript
|
||||
/python/ @github/codeql-python
|
||||
|
||||
# Assign query help for docs review
|
||||
/cpp/**/*.qhelp @hubwriter
|
||||
/csharp/**/*.qhelp @jf205
|
||||
/java/**/*.qhelp @felicitymay
|
||||
/javascript/**/*.qhelp @mchammer01
|
||||
/python/**/*.qhelp @felicitymay
|
||||
/docs/language/ @shati-patel @jf205
|
||||
|
||||
# Exclude help for experimental queries from docs review
|
||||
/cpp/**/experimental/**/*.qhelp @github/codeql-c-analysis @xcorail
|
||||
/csharp/**/experimental/**/*.qhelp @github/codeql-csharp @xcorail
|
||||
/java/**/experimental/**/*.qhelp @github/codeql-java @xcorail
|
||||
/javascript/**/experimental/**/*.qhelp @github/codeql-javascript @xcorail
|
||||
/python/**/experimental/**/*.qhelp @github/codeql-python @xcorail
|
||||
/python/**/experimental/**/*.qhelp @github/codeql-python @xcorail
|
||||
@@ -8,6 +8,7 @@
|
||||
* @tags reliability
|
||||
* security
|
||||
* external/cwe/cwe-242
|
||||
* external/cwe/cwe-676
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
@@ -30,3 +30,6 @@ private import implementations.SmartPointer
|
||||
private import implementations.Sscanf
|
||||
private import implementations.Send
|
||||
private import implementations.Recv
|
||||
private import implementations.Accept
|
||||
private import implementations.Poll
|
||||
private import implementations.Select
|
||||
|
||||
56
cpp/ql/src/semmle/code/cpp/models/implementations/Accept.qll
Normal file
56
cpp/ql/src/semmle/code/cpp/models/implementations/Accept.qll
Normal file
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Provides implementation classes modeling `accept` and various similar
|
||||
* functions. See `semmle.code.cpp.models.Models` for usage information.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Function
|
||||
import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/**
|
||||
* The function `accept` and its assorted variants
|
||||
*/
|
||||
private class Accept extends ArrayFunction, AliasFunction, TaintFunction, SideEffectFunction {
|
||||
Accept() { this.hasGlobalName(["accept", "accept4", "WSAAccept"]) }
|
||||
|
||||
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
|
||||
bufParam = 1 and countParam = 2
|
||||
}
|
||||
|
||||
override predicate hasArrayInput(int bufParam) { bufParam = 1 }
|
||||
|
||||
override predicate hasArrayOutput(int bufParam) { bufParam = 1 }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { exists(this.getParameter(index)) }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate parameterIsAlwaysReturned(int index) { none() }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
(input.isParameter(0) or input.isParameterDeref(1)) and
|
||||
(output.isReturnValue() or output.isParameterDeref(1))
|
||||
}
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 1 and buffer = true and mustWrite = false
|
||||
or
|
||||
i = 2 and buffer = false and mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = 0 and buffer = true
|
||||
or
|
||||
i = 1 and buffer = false
|
||||
}
|
||||
|
||||
override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 }
|
||||
|
||||
// NOTE: We implement thse two predicates as none because we can't model the low-level changes made to
|
||||
// the structure pointed to by the file-descriptor argument.
|
||||
override predicate hasOnlySpecificReadSideEffects() { none() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { none() }
|
||||
}
|
||||
44
cpp/ql/src/semmle/code/cpp/models/implementations/Poll.qll
Normal file
44
cpp/ql/src/semmle/code/cpp/models/implementations/Poll.qll
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Provides implementation classes modeling `poll` and various similar
|
||||
* functions. See `semmle.code.cpp.models.Models` for usage information.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Function
|
||||
import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/**
|
||||
* The function `poll` and its assorted variants
|
||||
*/
|
||||
private class Poll extends ArrayFunction, AliasFunction, SideEffectFunction {
|
||||
Poll() { this.hasGlobalName(["poll", "ppoll", "WSAPoll"]) }
|
||||
|
||||
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
|
||||
bufParam = 0 and countParam = 1
|
||||
}
|
||||
|
||||
override predicate hasArrayInput(int bufParam) { bufParam = 0 }
|
||||
|
||||
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { exists(this.getParameter(index)) }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate parameterIsAlwaysReturned(int index) { none() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 0 and buffer = true and mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = 0 and buffer = true
|
||||
or
|
||||
this.hasGlobalName("ppoll") and i = [2, 3] and buffer = false
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
40
cpp/ql/src/semmle/code/cpp/models/implementations/Select.qll
Normal file
40
cpp/ql/src/semmle/code/cpp/models/implementations/Select.qll
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Provides implementation classes modeling `select` and various similar
|
||||
* functions. See `semmle.code.cpp.models.Models` for usage information.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Function
|
||||
import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/**
|
||||
* The function `select` and its assorted variants
|
||||
*/
|
||||
private class Select extends ArrayFunction, AliasFunction, SideEffectFunction {
|
||||
Select() { this.hasGlobalName(["select", "pselect"]) }
|
||||
|
||||
override predicate hasArrayWithUnknownSize(int bufParam) { bufParam = [1 .. 3] }
|
||||
|
||||
override predicate hasArrayInput(int bufParam) { bufParam = [1 .. 3] }
|
||||
|
||||
override predicate hasArrayOutput(int bufParam) { bufParam = [1 .. 3] }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { exists(this.getParameter(index)) }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate parameterIsAlwaysReturned(int index) { none() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = [1 .. 3] and buffer = true and mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = [1 .. 5] and buffer = true
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
24
cpp/ql/test/library-tests/dataflow/taint-tests/bsd.cpp
Normal file
24
cpp/ql/test/library-tests/dataflow/taint-tests/bsd.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
void sink(...);
|
||||
int source();
|
||||
|
||||
// --- accept ---
|
||||
|
||||
struct sockaddr {
|
||||
unsigned char length;
|
||||
int sa_family;
|
||||
char* sa_data;
|
||||
};
|
||||
|
||||
int accept(int, const sockaddr*, int*);
|
||||
|
||||
void sink(sockaddr);
|
||||
|
||||
void test_accept() {
|
||||
int s = source();
|
||||
sockaddr addr;
|
||||
int size = sizeof(sockaddr);
|
||||
int a = accept(s, &addr, &size);
|
||||
|
||||
sink(a); // $ ast=17:11 SPURIOUS: ast=18:12 MISSING: ir
|
||||
sink(addr); // $ ast MISSING: ir
|
||||
}
|
||||
@@ -135,6 +135,17 @@
|
||||
| arrayassignment.cpp:145:12:145:12 | 5 | arrayassignment.cpp:145:7:145:13 | access to array | TAINT |
|
||||
| arrayassignment.cpp:146:7:146:10 | arr3 | arrayassignment.cpp:146:7:146:13 | access to array | |
|
||||
| arrayassignment.cpp:146:12:146:12 | 5 | arrayassignment.cpp:146:7:146:13 | access to array | TAINT |
|
||||
| bsd.cpp:17:11:17:16 | call to source | bsd.cpp:20:18:20:18 | s | |
|
||||
| bsd.cpp:18:12:18:15 | addr | bsd.cpp:20:22:20:25 | addr | |
|
||||
| bsd.cpp:18:12:18:15 | addr | bsd.cpp:23:8:23:11 | addr | |
|
||||
| bsd.cpp:19:14:19:29 | sizeof(sockaddr) | bsd.cpp:20:29:20:32 | size | |
|
||||
| bsd.cpp:20:11:20:16 | call to accept | bsd.cpp:22:8:22:8 | a | |
|
||||
| bsd.cpp:20:18:20:18 | s | bsd.cpp:20:11:20:16 | call to accept | TAINT |
|
||||
| bsd.cpp:20:21:20:25 | & ... | bsd.cpp:20:11:20:16 | call to accept | TAINT |
|
||||
| bsd.cpp:20:22:20:25 | addr | bsd.cpp:20:11:20:16 | call to accept | TAINT |
|
||||
| bsd.cpp:20:22:20:25 | addr | bsd.cpp:20:21:20:25 | & ... | |
|
||||
| bsd.cpp:20:28:20:32 | ref arg & ... | bsd.cpp:20:29:20:32 | size [inner post update] | |
|
||||
| bsd.cpp:20:29:20:32 | size | bsd.cpp:20:28:20:32 | & ... | |
|
||||
| constructor_delegation.cpp:8:2:8:8 | this | constructor_delegation.cpp:8:20:8:24 | constructor init of field x [pre-this] | |
|
||||
| constructor_delegation.cpp:8:14:8:15 | _x | constructor_delegation.cpp:8:22:8:23 | _x | |
|
||||
| constructor_delegation.cpp:8:22:8:23 | _x | constructor_delegation.cpp:8:20:8:24 | constructor init of field x | TAINT |
|
||||
|
||||
4
csharp/change-notes/2021-02-12-with-expression.md
Normal file
4
csharp/change-notes/2021-02-12-with-expression.md
Normal file
@@ -0,0 +1,4 @@
|
||||
lgtm,codescanning
|
||||
* C# 9 `with` expressions are now extracted. Data flow support has been added to
|
||||
handle flow through `with` expressions and also from `record` constructor arguments
|
||||
to its properties.
|
||||
@@ -250,6 +250,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
case SyntaxKind.SuppressNullableWarningExpression:
|
||||
return PostfixUnary.Create(info.SetKind(ExprKind.SUPPRESS_NULLABLE_WARNING), ((PostfixUnaryExpressionSyntax)info.Node).Operand);
|
||||
|
||||
case SyntaxKind.WithExpression:
|
||||
return WithExpression.Create(info);
|
||||
|
||||
default:
|
||||
info.Context.ModelError(info.Node, $"Unhandled expression '{info.Node}' of kind '{info.Node.Kind()}'");
|
||||
return new Unknown(info);
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
protected Initializer(ExpressionNodeInfo info) : base(info) { }
|
||||
}
|
||||
|
||||
internal class ArrayInitializer : Expression<InitializerExpressionSyntax>
|
||||
internal class ArrayInitializer : Initializer
|
||||
{
|
||||
private ArrayInitializer(ExpressionNodeInfo info) : base(info.SetType(null).SetKind(ExprKind.ARRAY_INIT)) { }
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Extraction.Kinds;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
{
|
||||
internal class WithExpression : Expression<WithExpressionSyntax>
|
||||
{
|
||||
private WithExpression(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.WITH)) { }
|
||||
|
||||
public static Expression Create(ExpressionNodeInfo info) => new WithExpression(info).TryPopulate();
|
||||
|
||||
protected override void PopulateExpression(TextWriter trapFile)
|
||||
{
|
||||
Create(Context, Syntax.Expression, this, 0);
|
||||
|
||||
ObjectInitializer.Create(new ExpressionNodeInfo(Context, Syntax.Initializer, this, 1).SetType(Type));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,7 +124,7 @@ namespace Semmle.Extraction.Kinds
|
||||
AND_PATTERN = 127,
|
||||
OR_PATTERN = 128,
|
||||
FUNCTION_POINTER_INVOCATION = 129,
|
||||
|
||||
WITH = 130,
|
||||
DEFINE_SYMBOL = 999
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,6 +461,15 @@ class Operator extends Callable, Member, Attributable, @operator {
|
||||
override Parameter getRawParameter(int i) { result = getParameter(i) }
|
||||
}
|
||||
|
||||
/** A clone method on a record. */
|
||||
class RecordCloneMethod extends Method, DotNet::RecordCloneCallable {
|
||||
override Constructor getConstructor() {
|
||||
result = DotNet::RecordCloneCallable.super.getConstructor()
|
||||
}
|
||||
|
||||
override string toString() { result = Method.super.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined unary operator - an operator taking one operand.
|
||||
*
|
||||
|
||||
@@ -748,6 +748,9 @@ class Class extends RefType, @class_type {
|
||||
class Record extends Class {
|
||||
Record() { this.isRecord() }
|
||||
|
||||
/** Gets the clone method of this record. */
|
||||
RecordCloneMethod getCloneMethod() { result = this.getAMember() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Record" }
|
||||
}
|
||||
|
||||
|
||||
@@ -2416,3 +2416,22 @@ class StringValuesFlow extends LibraryTypeDataFlow, Struct {
|
||||
preservesValue = false
|
||||
}
|
||||
}
|
||||
|
||||
private class RecordConstructorFlow extends SummarizedCallable {
|
||||
RecordConstructorFlow() { this = any(Record r).getAMember().(Constructor) }
|
||||
|
||||
override predicate propagatesFlow(
|
||||
SummaryInput input, ContentList inputContents, SummaryOutput output, ContentList outputContents,
|
||||
boolean preservesValue
|
||||
) {
|
||||
exists(int i, Property p, string name |
|
||||
this.getParameter(i).getName() = name and
|
||||
this.getDeclaringType().getAMember(name) = p and
|
||||
input = SummaryInput::parameter(i) and
|
||||
inputContents = ContentList::empty() and
|
||||
output = SummaryOutput::return() and
|
||||
outputContents = ContentList::property(p) and
|
||||
preservesValue = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,9 +268,7 @@ predicate exprModulus(Expr e, Bound b, int val, int mod) {
|
||||
private predicate condExprBranchModulus(
|
||||
ConditionalExpr cond, boolean branch, Bound b, int val, int mod
|
||||
) {
|
||||
exprModulus(cond.getTrueExpr(), b, val, mod) and branch = true
|
||||
or
|
||||
exprModulus(cond.getFalseExpr(), b, val, mod) and branch = false
|
||||
exprModulus(cond.getBranchExpr(branch), b, val, mod)
|
||||
}
|
||||
|
||||
private predicate addModulus(Expr add, boolean isLeft, Bound b, int val, int mod) {
|
||||
|
||||
@@ -61,7 +61,7 @@ abstract class ControlFlowReachabilityConfiguration extends string {
|
||||
/**
|
||||
* Holds if `e1` and `e2` are expressions for which we want to find a
|
||||
* control-flow path that follows control flow successors (resp.
|
||||
* predecessors, as specified by `isSuccesor`) inside the syntactic scope
|
||||
* predecessors, as specified by `isSuccessor`) inside the syntactic scope
|
||||
* `scope`. The Boolean `exactScope` indicates whether a transitive child
|
||||
* of `scope` is allowed (`exactScope = false`).
|
||||
*/
|
||||
@@ -74,7 +74,7 @@ abstract class ControlFlowReachabilityConfiguration extends string {
|
||||
/**
|
||||
* Holds if `e` and `def` are elements for which we want to find a
|
||||
* control-flow path that follows control flow successors (resp.
|
||||
* predecessors, as specified by `isSuccesor`) inside the syntactic scope
|
||||
* predecessors, as specified by `isSuccessor`) inside the syntactic scope
|
||||
* `scope`. The Boolean `exactScope` indicates whether a transitive child
|
||||
* of `scope` is allowed (`exactScope = false`).
|
||||
*/
|
||||
|
||||
@@ -209,6 +209,17 @@ module LocalFlow {
|
||||
e1 = e2.(SwitchExpr).getACase().getBody() and
|
||||
scope = e2 and
|
||||
isSuccessor = true
|
||||
or
|
||||
exists(WithExpr we |
|
||||
scope = we and
|
||||
isSuccessor = true
|
||||
|
|
||||
e1 = we.getExpr() and
|
||||
e2 = we.getInitializer()
|
||||
or
|
||||
e1 = we.getInitializer() and
|
||||
e2 = we
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -451,10 +462,23 @@ private predicate fieldOrPropertyStore(Expr e, Content c, Expr src, Expr q, bool
|
||||
postUpdate = true
|
||||
)
|
||||
or
|
||||
// `with` expression initializer, `x with { f = src }`
|
||||
e =
|
||||
any(WithExpr we |
|
||||
exists(MemberInitializer mi |
|
||||
q = we and
|
||||
mi = we.getInitializer().getAMemberInitializer() and
|
||||
f = mi.getInitializedMember() and
|
||||
src = mi.getRValue() and
|
||||
postUpdate = false
|
||||
)
|
||||
)
|
||||
or
|
||||
// Object initializer, `new C() { f = src }`
|
||||
exists(MemberInitializer mi |
|
||||
e = q and
|
||||
mi = q.(ObjectInitializer).getAMemberInitializer() and
|
||||
q.getParent() instanceof ObjectCreation and
|
||||
f = mi.getInitializedMember() and
|
||||
src = mi.getRValue() and
|
||||
postUpdate = false
|
||||
@@ -792,6 +816,13 @@ private module Cached {
|
||||
input = SummaryInput::parameter(i) and
|
||||
n.(ArgumentNode).argumentOf(call, i)
|
||||
)
|
||||
or
|
||||
exists(WithExpr we, ObjectInitializer oi, FieldOrProperty f |
|
||||
oi = we.getInitializer() and
|
||||
n.asExpr() = oi and
|
||||
f = oi.getAMemberInitializer().getInitializedMember() and
|
||||
c = f.getContent()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -885,6 +916,8 @@ private module Cached {
|
||||
n instanceof SummaryNodeImpl
|
||||
or
|
||||
n instanceof ParamsArgumentNode
|
||||
or
|
||||
n.asExpr() = any(WithExpr we).getInitializer()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ abstract class ControlFlowReachabilityConfiguration extends string {
|
||||
/**
|
||||
* Holds if `e1` and `e2` are expressions for which we want to find a
|
||||
* control-flow path that follows control flow successors (resp.
|
||||
* predecessors, as specified by `isSuccesor`) inside the syntactic scope
|
||||
* predecessors, as specified by `isSuccessor`) inside the syntactic scope
|
||||
* `scope`. The Boolean `exactScope` indicates whether a transitive child
|
||||
* of `scope` is allowed (`exactScope = false`).
|
||||
*/
|
||||
@@ -74,7 +74,7 @@ abstract class ControlFlowReachabilityConfiguration extends string {
|
||||
/**
|
||||
* Holds if `e` and `def` are elements for which we want to find a
|
||||
* control-flow path that follows control flow successors (resp.
|
||||
* predecessors, as specified by `isSuccesor`) inside the syntactic scope
|
||||
* predecessors, as specified by `isSuccessor`) inside the syntactic scope
|
||||
* `scope`. The Boolean `exactScope` indicates whether a transitive child
|
||||
* of `scope` is allowed (`exactScope = false`).
|
||||
*/
|
||||
|
||||
@@ -415,5 +415,15 @@ module ExprNode {
|
||||
|
||||
/** Gets the "else" expression of this conditional expression. */
|
||||
ExprNode getFalseExpr() { hasChild(e, e.getElse(), this, result) }
|
||||
|
||||
/**
|
||||
* If `branch` is `true` gets the "then" expression, if `false` gets the
|
||||
* "else" expression of this conditional expression.
|
||||
*/
|
||||
ExprNode getBranchExpr(boolean branch) {
|
||||
branch = true and result = getTrueExpr()
|
||||
or
|
||||
branch = false and result = getFalseExpr()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1152,3 +1152,21 @@ class DefineSymbolExpr extends Expr, @define_symbol_expr {
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DefineSymbolExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `with` expression called on a record.
|
||||
*/
|
||||
class WithExpr extends Expr, @with_expr {
|
||||
/** Gets the object initializer of this `with` expression. */
|
||||
ObjectInitializer getInitializer() { result = this.getChild(1) }
|
||||
|
||||
/** Gets the expression on which this `with` is called. */
|
||||
Expr getExpr() { result = this.getChild(0) }
|
||||
|
||||
/** Gets the clone method of the `record` that is targetted by this `with` expression. */
|
||||
RecordCloneMethod getCloneMethod() { result = this.getExpr().getType().(Record).getCloneMethod() }
|
||||
|
||||
override string toString() { result = "... with { ... }" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "WithExpr" }
|
||||
}
|
||||
|
||||
@@ -91,3 +91,34 @@ abstract class Constructor extends Callable { }
|
||||
|
||||
/** A destructor/finalizer. */
|
||||
abstract class Destructor extends Callable { }
|
||||
|
||||
pragma[nomagic]
|
||||
private ValueOrRefType getARecordBaseType(ValueOrRefType t) {
|
||||
exists(Callable c |
|
||||
c.hasName("<Clone>$") and
|
||||
c.getNumberOfParameters() = 0 and
|
||||
t = c.getDeclaringType() and
|
||||
result = t
|
||||
)
|
||||
or
|
||||
result = getARecordBaseType(t).getABaseType()
|
||||
}
|
||||
|
||||
/** A clone method on a record. */
|
||||
class RecordCloneCallable extends Callable {
|
||||
RecordCloneCallable() {
|
||||
this.getDeclaringType() instanceof ValueOrRefType and
|
||||
this.hasName("<Clone>$") and
|
||||
this.getNumberOfParameters() = 0 and
|
||||
this.getReturnType() = getARecordBaseType(this.getDeclaringType()) and
|
||||
this.(Member).isPublic() and
|
||||
not this.(Member).isStatic()
|
||||
}
|
||||
|
||||
/** Gets the constructor that this clone method calls. */
|
||||
Constructor getConstructor() {
|
||||
result.getDeclaringType() = this.getDeclaringType() and
|
||||
result.getNumberOfParameters() = 1 and
|
||||
result.getParameter(0).getType() = this.getDeclaringType()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,16 +51,7 @@ class ValueOrRefType extends Type, @dotnet_valueorreftype {
|
||||
ValueOrRefType getABaseType() { none() }
|
||||
|
||||
/** Holds if this type is a `record`. */
|
||||
predicate isRecord() {
|
||||
exists(Callable c |
|
||||
c.getDeclaringType() = this and
|
||||
c.hasName("<Clone>$") and
|
||||
c.getNumberOfParameters() = 0 and
|
||||
c.getReturnType() = this.getABaseType*() and
|
||||
c.(Member).isPublic() and
|
||||
not c.(Member).isStatic()
|
||||
)
|
||||
}
|
||||
predicate isRecord() { exists(RecordCloneCallable c | c.getDeclaringType() = this) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1156,6 +1156,7 @@ case @expr.kind of
|
||||
| 127 = @and_pattern_expr
|
||||
| 128 = @or_pattern_expr
|
||||
| 129 = @function_pointer_invocation_expr
|
||||
| 130 = @with_expr
|
||||
/* Preprocessor */
|
||||
| 999 = @define_symbol_expr
|
||||
;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1020,61 +1020,158 @@ Record.cs:
|
||||
# 50| 0: [MethodCall] call to method ToString
|
||||
# 50| -1: [LocalVariableAccess] access to local variable s
|
||||
# 50| 1: [StringLiteral] " is a dog"
|
||||
# 54| [Class] Record1
|
||||
# 56| 5: [Method] M1
|
||||
# 56| -1: [TypeMention] Void
|
||||
# 57| 4: [BlockStmt] {...}
|
||||
# 58| 0: [LocalVariableDeclStmt] ... ...;
|
||||
# 58| 0: [LocalVariableDeclAndInitExpr] Person person = ...
|
||||
# 58| -1: [TypeMention] Person
|
||||
# 58| 0: [LocalVariableAccess] access to local variable person
|
||||
# 58| 1: [ObjectCreation] object creation of type Person
|
||||
# 58| -1: [TypeMention] Person
|
||||
# 58| 0: [StringLiteral] "Bill"
|
||||
# 58| 1: [StringLiteral] "Wagner"
|
||||
# 59| 1: [LocalVariableDeclStmt] ... ...;
|
||||
# 59| 0: [LocalVariableDeclAndInitExpr] Student student = ...
|
||||
# 59| -1: [TypeMention] Student
|
||||
# 59| 0: [LocalVariableAccess] access to local variable student
|
||||
# 59| 1: [ObjectCreation] object creation of type Student
|
||||
# 59| -1: [TypeMention] Student
|
||||
# 59| 0: [StringLiteral] "Bill"
|
||||
# 59| 1: [StringLiteral] "Wagner"
|
||||
# 59| 2: [IntLiteral] 11
|
||||
# 61| 2: [ExprStmt] ...;
|
||||
# 61| 0: [MethodCall] call to method WriteLine
|
||||
# 61| -1: [TypeAccess] access to type Console
|
||||
# 61| 0: [TypeMention] Console
|
||||
# 61| 0: [OperatorCall] call to operator ==
|
||||
# 61| 0: [LocalVariableAccess] access to local variable student
|
||||
# 61| 1: [LocalVariableAccess] access to local variable person
|
||||
# 64| 6: [Method] M2
|
||||
# 64| -1: [TypeMention] Void
|
||||
# 65| 4: [BlockStmt] {...}
|
||||
# 66| 0: [LocalVariableDeclStmt] ... ...;
|
||||
# 66| 0: [LocalVariableDeclAndInitExpr] Person1 person = ...
|
||||
# 66| -1: [TypeMention] Person1
|
||||
# 66| 0: [LocalVariableAccess] access to local variable person
|
||||
# 66| 1: [ObjectCreation] object creation of type Person1
|
||||
# 66| -1: [TypeMention] Person1
|
||||
# 66| 0: [StringLiteral] "Bill"
|
||||
# 66| 1: [StringLiteral] "Wagner"
|
||||
# 68| 1: [ExprStmt] ...;
|
||||
# 68| 0: [AssignExpr] ... = ...
|
||||
# 68| 0: [TupleExpr] (..., ...)
|
||||
# 68| 0: [LocalVariableDeclExpr] String first
|
||||
# 68| 1: [LocalVariableDeclExpr] String last
|
||||
# 68| 1: [LocalVariableAccess] access to local variable person
|
||||
# 69| 2: [ExprStmt] ...;
|
||||
# 69| 0: [MethodCall] call to method WriteLine
|
||||
# 69| -1: [TypeAccess] access to type Console
|
||||
# 69| 0: [TypeMention] Console
|
||||
# 69| 0: [LocalVariableAccess] access to local variable first
|
||||
# 70| 3: [ExprStmt] ...;
|
||||
# 70| 0: [MethodCall] call to method WriteLine
|
||||
# 70| -1: [TypeAccess] access to type Console
|
||||
# 70| 0: [TypeMention] Console
|
||||
# 70| 0: [LocalVariableAccess] access to local variable last
|
||||
# 54| [Record] R1
|
||||
# 54| 12: [NEOperator] !=
|
||||
#-----| 2: (Parameters)
|
||||
# 54| 0: [Parameter] r1
|
||||
# 54| 1: [Parameter] r2
|
||||
# 54| 13: [EQOperator] ==
|
||||
#-----| 2: (Parameters)
|
||||
# 54| 0: [Parameter] r1
|
||||
# 54| 1: [Parameter] r2
|
||||
# 54| 14: [Property] EqualityContract
|
||||
# 54| 3: [Getter] get_EqualityContract
|
||||
# 54| 15: [InstanceConstructor] R1
|
||||
#-----| 2: (Parameters)
|
||||
# 54| 0: [Parameter] A
|
||||
# 54| -1: [TypeMention] string
|
||||
# 54| 16: [Property] A
|
||||
# 54| 3: [Getter] get_A
|
||||
# 54| 4: [Setter] set_A
|
||||
#-----| 2: (Parameters)
|
||||
# 54| 0: [Parameter] value
|
||||
# 56| [Record] R2
|
||||
# 56| 13: [NEOperator] !=
|
||||
#-----| 2: (Parameters)
|
||||
# 56| 0: [Parameter] r1
|
||||
# 56| 1: [Parameter] r2
|
||||
# 56| 14: [EQOperator] ==
|
||||
#-----| 2: (Parameters)
|
||||
# 56| 0: [Parameter] r1
|
||||
# 56| 1: [Parameter] r2
|
||||
# 56| 15: [Property] EqualityContract
|
||||
# 56| 3: [Getter] get_EqualityContract
|
||||
# 56| 16: [InstanceConstructor] R2
|
||||
#-----| 2: (Parameters)
|
||||
# 56| 0: [Parameter] A
|
||||
# 56| -1: [TypeMention] string
|
||||
# 56| 1: [Parameter] B
|
||||
# 56| -1: [TypeMention] string
|
||||
# 56| 17: [Property] B
|
||||
# 56| 3: [Getter] get_B
|
||||
# 56| 4: [Setter] set_B
|
||||
#-----| 2: (Parameters)
|
||||
# 56| 0: [Parameter] value
|
||||
# 58| [Class] Record1
|
||||
# 60| 5: [Method] M1
|
||||
# 60| -1: [TypeMention] Void
|
||||
# 61| 4: [BlockStmt] {...}
|
||||
# 62| 0: [LocalVariableDeclStmt] ... ...;
|
||||
# 62| 0: [LocalVariableDeclAndInitExpr] Person person = ...
|
||||
# 62| -1: [TypeMention] Person
|
||||
# 62| 0: [LocalVariableAccess] access to local variable person
|
||||
# 62| 1: [ObjectCreation] object creation of type Person
|
||||
# 62| -1: [TypeMention] Person
|
||||
# 62| 0: [StringLiteral] "Bill"
|
||||
# 62| 1: [StringLiteral] "Wagner"
|
||||
# 63| 1: [LocalVariableDeclStmt] ... ...;
|
||||
# 63| 0: [LocalVariableDeclAndInitExpr] Student student = ...
|
||||
# 63| -1: [TypeMention] Student
|
||||
# 63| 0: [LocalVariableAccess] access to local variable student
|
||||
# 63| 1: [ObjectCreation] object creation of type Student
|
||||
# 63| -1: [TypeMention] Student
|
||||
# 63| 0: [StringLiteral] "Bill"
|
||||
# 63| 1: [StringLiteral] "Wagner"
|
||||
# 63| 2: [IntLiteral] 11
|
||||
# 65| 2: [ExprStmt] ...;
|
||||
# 65| 0: [MethodCall] call to method WriteLine
|
||||
# 65| -1: [TypeAccess] access to type Console
|
||||
# 65| 0: [TypeMention] Console
|
||||
# 65| 0: [OperatorCall] call to operator ==
|
||||
# 65| 0: [LocalVariableAccess] access to local variable student
|
||||
# 65| 1: [LocalVariableAccess] access to local variable person
|
||||
# 68| 6: [Method] M2
|
||||
# 68| -1: [TypeMention] Void
|
||||
# 69| 4: [BlockStmt] {...}
|
||||
# 70| 0: [LocalVariableDeclStmt] ... ...;
|
||||
# 70| 0: [LocalVariableDeclAndInitExpr] Person1 p1 = ...
|
||||
# 70| -1: [TypeMention] Person1
|
||||
# 70| 0: [LocalVariableAccess] access to local variable p1
|
||||
# 70| 1: [ObjectCreation] object creation of type Teacher1
|
||||
# 70| -1: [TypeMention] Teacher1
|
||||
# 70| 0: [StringLiteral] "Bill"
|
||||
# 70| 1: [StringLiteral] "Wagner"
|
||||
# 70| 2: [StringLiteral] "Math"
|
||||
# 72| 1: [ExprStmt] ...;
|
||||
# 72| 0: [AssignExpr] ... = ...
|
||||
# 72| 0: [TupleExpr] (..., ...)
|
||||
# 72| 0: [LocalVariableDeclExpr] String first
|
||||
# 72| 1: [LocalVariableDeclExpr] String last
|
||||
# 72| 1: [LocalVariableAccess] access to local variable p1
|
||||
# 73| 2: [ExprStmt] ...;
|
||||
# 73| 0: [MethodCall] call to method WriteLine
|
||||
# 73| -1: [TypeAccess] access to type Console
|
||||
# 73| 0: [TypeMention] Console
|
||||
# 73| 0: [LocalVariableAccess] access to local variable first
|
||||
# 75| 3: [LocalVariableDeclStmt] ... ...;
|
||||
# 75| 0: [LocalVariableDeclAndInitExpr] Person1 p2 = ...
|
||||
# 75| -1: [TypeMention] Person1
|
||||
# 75| 0: [LocalVariableAccess] access to local variable p2
|
||||
# 75| 1: [WithExpr] ... with { ... }
|
||||
# 75| 0: [LocalVariableAccess] access to local variable p1
|
||||
# 75| 1: [ObjectInitializer] { ..., ... }
|
||||
# 75| 0: [MemberInitializer] ... = ...
|
||||
# 75| 0: [PropertyCall] access to property FirstName
|
||||
# 75| 1: [StringLiteral] "Paul"
|
||||
# 76| 4: [LocalVariableDeclStmt] ... ...;
|
||||
# 76| 0: [LocalVariableDeclAndInitExpr] Teacher1 p3 = ...
|
||||
# 76| -1: [TypeMention] Teacher1
|
||||
# 76| 0: [LocalVariableAccess] access to local variable p3
|
||||
# 76| 1: [WithExpr] ... with { ... }
|
||||
# 76| 0: [CastExpr] (...) ...
|
||||
# 76| 0: [TypeAccess] access to type Teacher1
|
||||
# 76| 0: [TypeMention] Teacher1
|
||||
# 76| 1: [LocalVariableAccess] access to local variable p1
|
||||
# 76| 1: [ObjectInitializer] { ..., ... }
|
||||
# 76| 0: [MemberInitializer] ... = ...
|
||||
# 76| 0: [PropertyCall] access to property FirstName
|
||||
# 76| 1: [StringLiteral] "Paul"
|
||||
# 76| 1: [MemberInitializer] ... = ...
|
||||
# 76| 0: [PropertyCall] access to property Subject
|
||||
# 76| 1: [StringLiteral] "Literature"
|
||||
# 77| 5: [LocalVariableDeclStmt] ... ...;
|
||||
# 77| 0: [LocalVariableDeclAndInitExpr] Person1 clone = ...
|
||||
# 77| -1: [TypeMention] Person1
|
||||
# 77| 0: [LocalVariableAccess] access to local variable clone
|
||||
# 77| 1: [WithExpr] ... with { ... }
|
||||
# 77| 0: [LocalVariableAccess] access to local variable p1
|
||||
# 77| 1: [ObjectInitializer] { ..., ... }
|
||||
# 80| 7: [Method] M3
|
||||
# 80| -1: [TypeMention] Void
|
||||
# 81| 4: [BlockStmt] {...}
|
||||
# 82| 0: [LocalVariableDeclStmt] ... ...;
|
||||
# 82| 0: [LocalVariableDeclAndInitExpr] R2 a = ...
|
||||
# 82| -1: [TypeMention] R2
|
||||
# 82| 0: [LocalVariableAccess] access to local variable a
|
||||
# 82| 1: [ObjectCreation] object creation of type R2
|
||||
# 82| -1: [TypeMention] R2
|
||||
# 82| 0: [StringLiteral] "A"
|
||||
# 82| 1: [StringLiteral] "B"
|
||||
# 83| 1: [LocalVariableDeclStmt] ... ...;
|
||||
# 83| 0: [LocalVariableDeclAndInitExpr] R1 b = ...
|
||||
# 83| -1: [TypeMention] R1
|
||||
# 83| 0: [LocalVariableAccess] access to local variable b
|
||||
# 83| 1: [LocalVariableAccess] access to local variable a
|
||||
# 84| 2: [LocalVariableDeclStmt] ... ...;
|
||||
# 84| 0: [LocalVariableDeclAndInitExpr] R1 c = ...
|
||||
# 84| -1: [TypeMention] R1
|
||||
# 84| 0: [LocalVariableAccess] access to local variable c
|
||||
# 84| 1: [WithExpr] ... with { ... }
|
||||
# 84| 0: [LocalVariableAccess] access to local variable b
|
||||
# 84| 1: [ObjectInitializer] { ..., ... }
|
||||
# 84| 0: [MemberInitializer] ... = ...
|
||||
# 84| 0: [PropertyCall] access to property A
|
||||
# 84| 1: [StringLiteral] "C"
|
||||
RelationalPattern.cs:
|
||||
# 3| [Class] RelationalPattern
|
||||
# 5| 5: [Method] M1
|
||||
|
||||
@@ -51,6 +51,10 @@ public record Dog(string Name) : Pet(Name)
|
||||
}
|
||||
}
|
||||
|
||||
public abstract record R1(string A) { }
|
||||
|
||||
public record R2(string A, string B) : R1(A) { }
|
||||
|
||||
public class Record1
|
||||
{
|
||||
public void M1()
|
||||
@@ -63,10 +67,20 @@ public class Record1
|
||||
|
||||
public void M2()
|
||||
{
|
||||
var person = new Person1("Bill", "Wagner");
|
||||
Person1 p1 = new Teacher1("Bill", "Wagner", "Math");
|
||||
|
||||
var (first, last) = person;
|
||||
var (first, last) = p1;
|
||||
Console.WriteLine(first);
|
||||
Console.WriteLine(last);
|
||||
|
||||
var p2 = p1 with { FirstName = "Paul" };
|
||||
var p3 = (Teacher1)p1 with { FirstName = "Paul", Subject = "Literature" };
|
||||
var clone = p1 with { };
|
||||
}
|
||||
|
||||
public void M3()
|
||||
{
|
||||
R2 a = new R2("A", "B");
|
||||
R1 b = a;
|
||||
R1 c = b with { A = "C" };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,4 +10,6 @@
|
||||
| Record.cs:29:66:29:72 | set_Subject | init |
|
||||
| Record.cs:32:70:32:74 | set_Level | init |
|
||||
| Record.cs:35:26:35:29 | set_Name | init |
|
||||
| Record.cs:54:34:54:34 | set_A | init |
|
||||
| Record.cs:56:35:56:35 | set_B | init |
|
||||
| UnaryPattern.cs:5:26:5:28 | set_P1 | set |
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
types
|
||||
| Record.cs:4:1:10:1 | Person | IEquatable<Person> |
|
||||
| Record.cs:12:1:18:1 | Teacher | IEquatable<Teacher> |
|
||||
| Record.cs:20:1:25:1 | Student | IEquatable<Student> |
|
||||
| Record.cs:27:1:27:57 | Person1 | IEquatable<Person1> |
|
||||
| Record.cs:29:1:30:35 | Teacher1 | IEquatable<Teacher1> |
|
||||
| Record.cs:32:1:33:35 | Student1 | IEquatable<Student1> |
|
||||
| Record.cs:35:1:39:1 | Pet | IEquatable<Pet> |
|
||||
| Record.cs:41:1:52:1 | Dog | IEquatable<Dog> |
|
||||
records
|
||||
| Record.cs:4:1:10:1 | Person | IEquatable<Person> | Record.cs:4:1:10:1 | <Clone>$ |
|
||||
| Record.cs:12:1:18:1 | Teacher | IEquatable<Teacher> | Record.cs:12:1:18:1 | <Clone>$ |
|
||||
| Record.cs:20:1:25:1 | Student | IEquatable<Student> | Record.cs:20:1:25:1 | <Clone>$ |
|
||||
| Record.cs:27:1:27:57 | Person1 | IEquatable<Person1> | Record.cs:27:1:27:57 | <Clone>$ |
|
||||
| Record.cs:29:1:30:35 | Teacher1 | IEquatable<Teacher1> | Record.cs:29:1:30:35 | <Clone>$ |
|
||||
| Record.cs:32:1:33:35 | Student1 | IEquatable<Student1> | Record.cs:32:1:33:35 | <Clone>$ |
|
||||
| Record.cs:35:1:39:1 | Pet | IEquatable<Pet> | Record.cs:35:1:39:1 | <Clone>$ |
|
||||
| Record.cs:41:1:52:1 | Dog | IEquatable<Dog> | Record.cs:41:1:52:1 | <Clone>$ |
|
||||
| Record.cs:54:1:54:39 | R1 | IEquatable<R1> | Record.cs:54:1:54:39 | <Clone>$ |
|
||||
| Record.cs:56:1:56:48 | R2 | IEquatable<R2> | Record.cs:56:1:56:48 | <Clone>$ |
|
||||
members
|
||||
| Record.cs:4:1:10:1 | Person | Person.!=(Person, Person) | Record.cs:4:15:4:20 |
|
||||
| Record.cs:4:1:10:1 | Person | Person.<Clone>$() | no location |
|
||||
@@ -198,3 +200,48 @@ members
|
||||
| Record.cs:41:1:52:1 | Dog | System.Object.Object() | no location |
|
||||
| Record.cs:41:1:52:1 | Dog | System.Object.ReferenceEquals(object, object) | no location |
|
||||
| Record.cs:41:1:52:1 | Dog | System.Object.~Object() | no location |
|
||||
| Record.cs:54:1:54:39 | R1 | R1.!=(R1, R1) | Record.cs:54:24:54:25 |
|
||||
| Record.cs:54:1:54:39 | R1 | R1.<Clone>$() | no location |
|
||||
| Record.cs:54:1:54:39 | R1 | R1.==(R1, R1) | Record.cs:54:24:54:25 |
|
||||
| Record.cs:54:1:54:39 | R1 | R1.A | Record.cs:54:34:54:34 |
|
||||
| Record.cs:54:1:54:39 | R1 | R1.Deconstruct(out string) | no location |
|
||||
| Record.cs:54:1:54:39 | R1 | R1.EqualityContract | Record.cs:54:24:54:25 |
|
||||
| Record.cs:54:1:54:39 | R1 | R1.Equals(R1) | no location |
|
||||
| Record.cs:54:1:54:39 | R1 | R1.Equals(object) | no location |
|
||||
| Record.cs:54:1:54:39 | R1 | R1.GetHashCode() | no location |
|
||||
| Record.cs:54:1:54:39 | R1 | R1.PrintMembers(StringBuilder) | no location |
|
||||
| Record.cs:54:1:54:39 | R1 | R1.R1(R1) | no location |
|
||||
| Record.cs:54:1:54:39 | R1 | R1.R1(string) | Record.cs:54:24:54:25 |
|
||||
| Record.cs:54:1:54:39 | R1 | R1.ToString() | no location |
|
||||
| Record.cs:54:1:54:39 | R1 | System.Object.Equals(object, object) | no location |
|
||||
| Record.cs:54:1:54:39 | R1 | System.Object.GetType() | no location |
|
||||
| Record.cs:54:1:54:39 | R1 | System.Object.MemberwiseClone() | no location |
|
||||
| Record.cs:54:1:54:39 | R1 | System.Object.Object() | no location |
|
||||
| Record.cs:54:1:54:39 | R1 | System.Object.ReferenceEquals(object, object) | no location |
|
||||
| Record.cs:54:1:54:39 | R1 | System.Object.~Object() | no location |
|
||||
| Record.cs:56:1:56:48 | R2 | R1.!=(R1, R1) | Record.cs:54:24:54:25 |
|
||||
| Record.cs:56:1:56:48 | R2 | R1.==(R1, R1) | Record.cs:54:24:54:25 |
|
||||
| Record.cs:56:1:56:48 | R2 | R1.A | Record.cs:54:34:54:34 |
|
||||
| Record.cs:56:1:56:48 | R2 | R1.Deconstruct(out string) | no location |
|
||||
| Record.cs:56:1:56:48 | R2 | R1.R1(R1) | no location |
|
||||
| Record.cs:56:1:56:48 | R2 | R1.R1(string) | Record.cs:54:24:54:25 |
|
||||
| Record.cs:56:1:56:48 | R2 | R2.!=(R2, R2) | Record.cs:56:15:56:16 |
|
||||
| Record.cs:56:1:56:48 | R2 | R2.<Clone>$() | no location |
|
||||
| Record.cs:56:1:56:48 | R2 | R2.==(R2, R2) | Record.cs:56:15:56:16 |
|
||||
| Record.cs:56:1:56:48 | R2 | R2.B | Record.cs:56:35:56:35 |
|
||||
| Record.cs:56:1:56:48 | R2 | R2.Deconstruct(out string, out string) | no location |
|
||||
| Record.cs:56:1:56:48 | R2 | R2.EqualityContract | Record.cs:56:15:56:16 |
|
||||
| Record.cs:56:1:56:48 | R2 | R2.Equals(R1) | no location |
|
||||
| Record.cs:56:1:56:48 | R2 | R2.Equals(R2) | no location |
|
||||
| Record.cs:56:1:56:48 | R2 | R2.Equals(object) | no location |
|
||||
| Record.cs:56:1:56:48 | R2 | R2.GetHashCode() | no location |
|
||||
| Record.cs:56:1:56:48 | R2 | R2.PrintMembers(StringBuilder) | no location |
|
||||
| Record.cs:56:1:56:48 | R2 | R2.R2(R2) | no location |
|
||||
| Record.cs:56:1:56:48 | R2 | R2.R2(string, string) | Record.cs:56:15:56:16 |
|
||||
| Record.cs:56:1:56:48 | R2 | R2.ToString() | no location |
|
||||
| Record.cs:56:1:56:48 | R2 | System.Object.Equals(object, object) | no location |
|
||||
| Record.cs:56:1:56:48 | R2 | System.Object.GetType() | no location |
|
||||
| Record.cs:56:1:56:48 | R2 | System.Object.MemberwiseClone() | no location |
|
||||
| Record.cs:56:1:56:48 | R2 | System.Object.Object() | no location |
|
||||
| Record.cs:56:1:56:48 | R2 | System.Object.ReferenceEquals(object, object) | no location |
|
||||
| Record.cs:56:1:56:48 | R2 | System.Object.~Object() | no location |
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import csharp
|
||||
|
||||
query predicate types(Record t, string i) { t.getABaseInterface().toStringWithTypes() = i }
|
||||
query predicate records(Record t, string i, RecordCloneMethod clone) {
|
||||
t.getABaseInterface().toStringWithTypes() = i and clone = t.getCloneMethod()
|
||||
}
|
||||
|
||||
private string getMemberName(Member m) {
|
||||
result = m.getDeclaringType().getQualifiedName() + "." + m.toStringWithTypes()
|
||||
|
||||
17
csharp/ql/test/library-tests/csharp9/withExpr.expected
Normal file
17
csharp/ql/test/library-tests/csharp9/withExpr.expected
Normal file
@@ -0,0 +1,17 @@
|
||||
withExpr
|
||||
| Record.cs:75:18:75:47 | ... with { ... } | Person1 | Record.cs:75:18:75:19 | access to local variable p1 | Record.cs:75:26:75:47 | { ..., ... } | Person1.<Clone>$() |
|
||||
| Record.cs:76:18:76:81 | ... with { ... } | Teacher1 | Record.cs:76:18:76:29 | (...) ... | Record.cs:76:36:76:81 | { ..., ... } | Teacher1.<Clone>$() |
|
||||
| Record.cs:77:21:77:31 | ... with { ... } | Person1 | Record.cs:77:21:77:22 | access to local variable p1 | Record.cs:77:29:77:31 | { ..., ... } | Person1.<Clone>$() |
|
||||
| Record.cs:84:16:84:33 | ... with { ... } | R1 | Record.cs:84:16:84:16 | access to local variable b | Record.cs:84:23:84:33 | { ..., ... } | R1.<Clone>$() |
|
||||
withTarget
|
||||
| Record.cs:75:18:75:47 | ... with { ... } | Record.cs:27:1:27:57 | <Clone>$ | Record.cs:27:1:27:57 | Person1 |
|
||||
| Record.cs:76:18:76:81 | ... with { ... } | Record.cs:29:1:30:35 | <Clone>$ | Record.cs:29:1:30:35 | Teacher1 |
|
||||
| Record.cs:77:21:77:31 | ... with { ... } | Record.cs:27:1:27:57 | <Clone>$ | Record.cs:27:1:27:57 | Person1 |
|
||||
| Record.cs:84:16:84:33 | ... with { ... } | Record.cs:54:1:54:39 | <Clone>$ | Record.cs:54:1:54:39 | R1 |
|
||||
cloneOverrides
|
||||
| Person1.<Clone>$() | Student1.<Clone>$() |
|
||||
| Person1.<Clone>$() | Teacher1.<Clone>$() |
|
||||
| Person.<Clone>$() | Student.<Clone>$() |
|
||||
| Person.<Clone>$() | Teacher.<Clone>$() |
|
||||
| Pet.<Clone>$() | Dog.<Clone>$() |
|
||||
| R1.<Clone>$() | R2.<Clone>$() |
|
||||
26
csharp/ql/test/library-tests/csharp9/withExpr.ql
Normal file
26
csharp/ql/test/library-tests/csharp9/withExpr.ql
Normal file
@@ -0,0 +1,26 @@
|
||||
import csharp
|
||||
|
||||
private string getSignature(Method m) {
|
||||
result = m.getDeclaringType().getQualifiedName() + "." + m.toStringWithTypes()
|
||||
}
|
||||
|
||||
query predicate withExpr(WithExpr with, string type, Expr expr, ObjectInitializer init, string clone) {
|
||||
type = with.getType().toStringWithTypes() and
|
||||
expr = with.getExpr() and
|
||||
init = with.getInitializer() and
|
||||
clone = getSignature(with.getCloneMethod())
|
||||
}
|
||||
|
||||
query predicate withTarget(WithExpr with, RecordCloneMethod clone, Constructor ctor) {
|
||||
with.getCloneMethod() = clone and
|
||||
clone.getConstructor() = ctor
|
||||
}
|
||||
|
||||
query predicate cloneOverrides(string b, string o) {
|
||||
exists(RecordCloneMethod base, RecordCloneMethod overrider |
|
||||
base.getDeclaringType().fromSource() and
|
||||
base.(Virtualizable).getAnOverrider() = overrider and
|
||||
b = getSignature(base) and
|
||||
o = getSignature(overrider)
|
||||
)
|
||||
}
|
||||
@@ -238,6 +238,18 @@ edges
|
||||
| I.cs:37:23:37:23 | i [Field1] : Object | I.cs:39:9:39:9 | access to parameter i [Field1] : Object |
|
||||
| I.cs:39:9:39:9 | access to parameter i [Field1] : Object | I.cs:40:14:40:14 | access to parameter i [Field1] : Object |
|
||||
| I.cs:40:14:40:14 | access to parameter i [Field1] : Object | I.cs:40:14:40:21 | access to field Field1 |
|
||||
| J.cs:12:17:12:28 | object creation of type Object : Object | J.cs:13:29:13:29 | access to local variable o : Object |
|
||||
| J.cs:12:17:12:28 | object creation of type Object : Object | J.cs:21:36:21:36 | access to local variable o : Object |
|
||||
| J.cs:13:18:13:36 | object creation of type Record [Prop1] : Object | J.cs:14:14:14:15 | access to local variable r1 [Prop1] : Object |
|
||||
| J.cs:13:18:13:36 | object creation of type Record [Prop1] : Object | J.cs:18:14:18:15 | access to local variable r2 [Prop1] : Object |
|
||||
| J.cs:13:18:13:36 | object creation of type Record [Prop1] : Object | J.cs:22:14:22:15 | access to local variable r3 [Prop1] : Object |
|
||||
| J.cs:13:29:13:29 | access to local variable o : Object | J.cs:13:18:13:36 | object creation of type Record [Prop1] : Object |
|
||||
| J.cs:14:14:14:15 | access to local variable r1 [Prop1] : Object | J.cs:14:14:14:21 | access to property Prop1 |
|
||||
| J.cs:18:14:18:15 | access to local variable r2 [Prop1] : Object | J.cs:18:14:18:21 | access to property Prop1 |
|
||||
| J.cs:21:18:21:38 | ... with { ... } [Prop2] : Object | J.cs:23:14:23:15 | access to local variable r3 [Prop2] : Object |
|
||||
| J.cs:21:36:21:36 | access to local variable o : Object | J.cs:21:18:21:38 | ... with { ... } [Prop2] : Object |
|
||||
| J.cs:22:14:22:15 | access to local variable r3 [Prop1] : Object | J.cs:22:14:22:21 | access to property Prop1 |
|
||||
| J.cs:23:14:23:15 | access to local variable r3 [Prop2] : Object | J.cs:23:14:23:21 | access to property Prop2 |
|
||||
nodes
|
||||
| A.cs:5:17:5:23 | object creation of type C : C | semmle.label | object creation of type C : C |
|
||||
| A.cs:6:17:6:25 | call to method Make [c] : C | semmle.label | call to method Make [c] : C |
|
||||
@@ -513,6 +525,19 @@ nodes
|
||||
| I.cs:39:9:39:9 | access to parameter i [Field1] : Object | semmle.label | access to parameter i [Field1] : Object |
|
||||
| I.cs:40:14:40:14 | access to parameter i [Field1] : Object | semmle.label | access to parameter i [Field1] : Object |
|
||||
| I.cs:40:14:40:21 | access to field Field1 | semmle.label | access to field Field1 |
|
||||
| J.cs:12:17:12:28 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
|
||||
| J.cs:13:18:13:36 | object creation of type Record [Prop1] : Object | semmle.label | object creation of type Record [Prop1] : Object |
|
||||
| J.cs:13:29:13:29 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| J.cs:14:14:14:15 | access to local variable r1 [Prop1] : Object | semmle.label | access to local variable r1 [Prop1] : Object |
|
||||
| J.cs:14:14:14:21 | access to property Prop1 | semmle.label | access to property Prop1 |
|
||||
| J.cs:18:14:18:15 | access to local variable r2 [Prop1] : Object | semmle.label | access to local variable r2 [Prop1] : Object |
|
||||
| J.cs:18:14:18:21 | access to property Prop1 | semmle.label | access to property Prop1 |
|
||||
| J.cs:21:18:21:38 | ... with { ... } [Prop2] : Object | semmle.label | ... with { ... } [Prop2] : Object |
|
||||
| J.cs:21:36:21:36 | access to local variable o : Object | semmle.label | access to local variable o : Object |
|
||||
| J.cs:22:14:22:15 | access to local variable r3 [Prop1] : Object | semmle.label | access to local variable r3 [Prop1] : Object |
|
||||
| J.cs:22:14:22:21 | access to property Prop1 | semmle.label | access to property Prop1 |
|
||||
| J.cs:23:14:23:15 | access to local variable r3 [Prop2] : Object | semmle.label | access to local variable r3 [Prop2] : Object |
|
||||
| J.cs:23:14:23:21 | access to property Prop2 | semmle.label | access to property Prop2 |
|
||||
#select
|
||||
| A.cs:7:14:7:16 | access to field c | A.cs:5:17:5:23 | object creation of type C : C | A.cs:7:14:7:16 | access to field c | $@ | A.cs:5:17:5:23 | object creation of type C : C | object creation of type C : C |
|
||||
| A.cs:14:14:14:20 | call to method Get | A.cs:13:15:13:22 | object creation of type C1 : C1 | A.cs:14:14:14:20 | call to method Get | $@ | A.cs:13:15:13:22 | object creation of type C1 : C1 | object creation of type C1 : C1 |
|
||||
@@ -566,3 +591,7 @@ nodes
|
||||
| I.cs:23:14:23:21 | access to field Field1 | I.cs:7:18:7:29 | object creation of type Object : Object | I.cs:23:14:23:21 | access to field Field1 | $@ | I.cs:7:18:7:29 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| I.cs:27:14:27:21 | access to field Field1 | I.cs:7:18:7:29 | object creation of type Object : Object | I.cs:27:14:27:21 | access to field Field1 | $@ | I.cs:7:18:7:29 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| I.cs:40:14:40:21 | access to field Field1 | I.cs:31:13:31:24 | object creation of type Object : Object | I.cs:40:14:40:21 | access to field Field1 | $@ | I.cs:31:13:31:24 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| J.cs:14:14:14:21 | access to property Prop1 | J.cs:12:17:12:28 | object creation of type Object : Object | J.cs:14:14:14:21 | access to property Prop1 | $@ | J.cs:12:17:12:28 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| J.cs:18:14:18:21 | access to property Prop1 | J.cs:12:17:12:28 | object creation of type Object : Object | J.cs:18:14:18:21 | access to property Prop1 | $@ | J.cs:12:17:12:28 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| J.cs:22:14:22:21 | access to property Prop1 | J.cs:12:17:12:28 | object creation of type Object : Object | J.cs:22:14:22:21 | access to property Prop1 | $@ | J.cs:12:17:12:28 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
| J.cs:23:14:23:21 | access to property Prop2 | J.cs:12:17:12:28 | object creation of type Object : Object | J.cs:23:14:23:21 | access to property Prop2 | $@ | J.cs:12:17:12:28 | object creation of type Object : Object | object creation of type Object : Object |
|
||||
|
||||
31
csharp/ql/test/library-tests/dataflow/fields/J.cs
Normal file
31
csharp/ql/test/library-tests/dataflow/fields/J.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
internal static class IsExternalInit { }
|
||||
}
|
||||
|
||||
public record Record(object Prop1, object Prop2) { }
|
||||
|
||||
public class J
|
||||
{
|
||||
private void M1()
|
||||
{
|
||||
var o = new object();
|
||||
var r1 = new Record(o, null);
|
||||
Sink(r1.Prop1); // flow
|
||||
Sink(r1.Prop2); // no flow
|
||||
|
||||
var r2 = r1 with { };
|
||||
Sink(r2.Prop1); // flow
|
||||
Sink(r2.Prop2); // no flow
|
||||
|
||||
var r3 = r1 with { Prop2 = o };
|
||||
Sink(r3.Prop1); // flow
|
||||
Sink(r3.Prop2); // flow
|
||||
|
||||
var r4 = r1 with { Prop1 = null };
|
||||
Sink(r4.Prop1); // no flow
|
||||
Sink(r4.Prop2); // no flow
|
||||
}
|
||||
|
||||
public static void Sink(object o) { }
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Add 'with_expr' to 'expr' types.
|
||||
compatibility: backwards
|
||||
@@ -26,6 +26,12 @@ features for query files (extension ``.ql``) and library files (extension ``.qll
|
||||
|
||||
You can also use the VS Code **Format Document** command to format your code according to the `CodeQL style guide <https://github.com/github/codeql/blob/main/docs/ql-style-guide.md>`__.
|
||||
|
||||
Data and telemetry
|
||||
-------------------
|
||||
|
||||
If you specifically opt in to permit GitHub to do so, GitHub will collect usage data and metrics for the purposes of helping the core developers to improve the CodeQL extension for VS Code.
|
||||
For more information, see ":doc:`About telemetry in CodeQL for Visual Studio Code <about-telemetry-in-codeql-for-visual-studio-code>`."
|
||||
|
||||
Further reading
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
:tocdepth: 1
|
||||
|
||||
.. _about-telemetry-in-codeql-for-visual-studio-code:
|
||||
|
||||
About telemetry in CodeQL for Visual Studio Code
|
||||
=================================================
|
||||
|
||||
If you specifically opt in to permit GitHub to do so, GitHub will collect usage data and metrics for the purposes of helping the core developers to improve the CodeQL extension for VS Code.
|
||||
|
||||
This data will not be shared with any parties outside of GitHub. IP addresses and installation IDs will be retained for a maximum of 30 days. Anonymous data will be retained for a maximum of 180 days.
|
||||
|
||||
Why we collect data
|
||||
--------------------------------------
|
||||
|
||||
GitHub collects aggregated, anonymous usage data and metrics to help us improve CodeQL for VS Code. IP addresses and installation IDs are collected only to ensure that anonymous data is not duplicated during aggregation.
|
||||
|
||||
What data is collected
|
||||
--------------------------------------
|
||||
|
||||
If you opt in, GitHub collects the following information related to the usage of the extension. The data collected are:
|
||||
|
||||
- The identifiers of any CodeQL-related VS Code commands that are run.
|
||||
- For each command: the timestamp, time taken, and whether or not the command completed successfully.
|
||||
- VS Code and extension version.
|
||||
- Randomly generated GUID that uniquely identifies a CodeQL extension installation. (Discarded before aggregation.)
|
||||
- IP address of the client sending the telemetry data. (Discarded before aggregation.)
|
||||
- Whether or not the ``codeQL.canary`` setting is enabled and set to ``true``.
|
||||
|
||||
How long data is retained
|
||||
--------------------------
|
||||
|
||||
IP address and GUIDs will be retained for a maximum of 30 days. Anonymous, aggregated data that includes command identifiers, run times, and timestamps will be retained for a maximum of 180 days.
|
||||
|
||||
Access to the data
|
||||
-------------------
|
||||
|
||||
IP address and GUIDs will only be available to the core developers of CodeQL. Aggregated data will be available to GitHub employees.
|
||||
|
||||
What data is **NOT** collected
|
||||
--------------------------------
|
||||
|
||||
We only collect the minimal amount of data we need to answer the questions about how our users are experiencing this product. To that end, we do not collect the following information:
|
||||
|
||||
- No GitHub user ID
|
||||
- No CodeQL database names or contents
|
||||
- No contents of CodeQL queries
|
||||
- No filesystem paths
|
||||
|
||||
Disabling telemetry reporting
|
||||
------------------------------
|
||||
|
||||
Telemetry collection is *disabled* by default.
|
||||
|
||||
When telemetry collection is disabled, no data will be sent to GitHub servers.
|
||||
|
||||
You can disable telemetry collection by setting ``codeQL.telemetry.enableTelemetry`` to ``false`` in your settings. For more information about CodeQL settings, see ":doc:`Customizing settings <customizing-settings>`."
|
||||
|
||||
Additionally, telemetry collection will be disabled if the global ``telemetry.enableTelemetry`` setting is set to ``false``. For more information about global telemetry collection, see "`Microsoft's documentation <https://code.visualstudio.com/docs/supporting/faq#_how-to-disable-telemetry-reporting>`__."
|
||||
|
||||
Further reading
|
||||
----------------
|
||||
|
||||
For more information, see GitHub's "`Privacy Statement <https://docs.github.com/github/site-policy/github-privacy-statement>`__" and "`Terms of Service <https://docs.github.com/github/site-policy/github-terms-of-service>`__."
|
||||
@@ -39,6 +39,8 @@ The CodeQL extension for Visual Studio Code adds rich language support for CodeQ
|
||||
<troubleshooting-codeql-for-visual-studio-code>`: You can use the detailed
|
||||
information written to the extension's log files if you need to troubleshoot problems.
|
||||
|
||||
- :doc:`About telemetry in CodeQL for Visual Studio Code <about-telemetry-in-codeql-for-visual-studio-code>`: If you specifically opt in to permit GitHub to do so, GitHub will collect usage data and metrics for the purposes of helping the core developers to improve the CodeQL extension for VS Code.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
:titlesonly:
|
||||
@@ -51,3 +53,4 @@ The CodeQL extension for Visual Studio Code adds rich language support for CodeQ
|
||||
testing-codeql-queries-in-visual-studio-code
|
||||
customizing-settings
|
||||
troubleshooting-codeql-for-visual-studio-code
|
||||
about-telemetry-in-codeql-for-visual-studio-code
|
||||
|
||||
@@ -27,41 +27,47 @@ Go built-in support
|
||||
:widths: auto
|
||||
|
||||
Name, Category
|
||||
Chi, Web framework
|
||||
Echo, Web framework
|
||||
Gin, Web framework
|
||||
glog, Logging library
|
||||
go-restful, Web application framework
|
||||
go-sh, Utility library
|
||||
GoKit, Microservice toolkit
|
||||
Gokogiri, XPath library
|
||||
golang.org/x/crypto/ssh, Network communicator
|
||||
golang.org/x/net/websocket, Network communicator
|
||||
Gorilla websocket, Network communicator
|
||||
GORM, Database
|
||||
GoWebsocket, Network communicator
|
||||
goxpath, XPath library
|
||||
https://github.com/antchfx/htmlquery, XPath library
|
||||
https://github.com/antchfx/jsonquery, XPath library
|
||||
https://github.com/antchfx/xmlquery, XPath library
|
||||
https://github.com/antchfx/xpath, XPath library
|
||||
https://github.com/go-xmlpath/xmlpath, XPath library
|
||||
json-iterator, Serialization
|
||||
klog, Logging library
|
||||
Logrus, Logging library
|
||||
Macaron, Web framework
|
||||
mongo, Database
|
||||
mux, HTTP request router and dispatcher
|
||||
nhooyr.io/websocket, Network communicator
|
||||
pg, Database
|
||||
proto, Serialization
|
||||
Revel, Web framework
|
||||
Spew, Logging library
|
||||
sqlx, Database
|
||||
SendGrid, Email library
|
||||
Squirrel, Database
|
||||
ws, Network communicator
|
||||
xpathparser, XPath library
|
||||
`beego <https://beego.me/>`_, Web/logging/database framework
|
||||
`Chi <https://github.com/go-chi/chi>`_, Web framework
|
||||
Couchbase (`gocb <https://github.com/couchbase/gocb>`_ and `go-couchbase <http://www.github.com/couchbase/go-couchbase>`_), Database
|
||||
`Echo <https://echo.labstack.com/>`_, Web framework
|
||||
`Gin <https://github.com/gin-gonic/gin>`_, Web framework
|
||||
`glog <https://github.com/golang/glog>`_, Logging library
|
||||
`go-pg <https://pg.uptrace.dev/>`_, Database
|
||||
`go-restful <https://github.com/emicklei/go-restful>`_, Web application framework
|
||||
`go-sh <https://github.com/codeskyblue/go-sh>`_, Utility library
|
||||
`go-spew <https://github.com/davecgh/go-spew>`_, Logging library
|
||||
`GoKit <https://github.com/go-kit/kit>`_, Microservice toolkit
|
||||
`Gokogiri <https://github.com/jbowtie/gokogiri>`_, XPath library
|
||||
`golang.org/x/crypto/ssh <https://pkg.go.dev/golang.org/x/crypto/ssh>`_, Network communicator
|
||||
`golang.org/x/net/websocket <https://pkg.go.dev/golang.org/x/net/websocket>`_, Network communicator
|
||||
`goproxy <https://github.com/elazarl/goproxy>`_, HTTP proxy library
|
||||
`Gorilla mux <http://www.gorillatoolkit.org/pkg/mux>`_, HTTP request router and dispatcher
|
||||
`Gorilla websocket <https://github.com/gorilla/websocket>`_, Network communicator
|
||||
`GORM <https://gorm.io/>`_, Database
|
||||
`GoWebsocket <https://github.com/sacOO7/gowebsocket>`_, Network communicator
|
||||
`goxpath <https://github.com/ChrisTrenkamp/goxpath>`_, XPath library
|
||||
`htmlquery <https://github.com/antchfx/htmlquery>`_, XPath library
|
||||
`json-iterator <https://github.com/json-iterator/go>`_, Serialization
|
||||
`jsonpatch <https://github.com/evanphx/json-patch>`_, Serialization
|
||||
`jsonquery <https://github.com/antchfx/jsonquery>`_, XPath library
|
||||
`klog <https://github.com/kubernetes/klog>`_, Logging library
|
||||
`Logrus <https://github.com/sirupsen/logrus>`_, Logging library
|
||||
`Macaron <https://gopkg.in/macaron.v1>`_, Web framework
|
||||
`mongo <https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo>`_, Database
|
||||
`nhooyr.io/websocket <http://nhooyr.io/websocket>`_, Network communicator
|
||||
`protobuf <https://pkg.go.dev/google.golang.org/protobuf>`_, Serialization
|
||||
`Revel <http://revel.github.io/>`_, Web framework
|
||||
`sqlx <http://jmoiron.github.io/sqlx/>`_, Database
|
||||
`SendGrid <https://github.com/sendgrid/sendgrid-go>`_, Email library
|
||||
`Squirrel <https://github.com/Masterminds/squirrel>`_, Database
|
||||
`ws <https://github.com/gobwas/ws>`_, Network communicator
|
||||
`xmlpath <https://gopkg.in/xmlpath.v2>`_, XPath library
|
||||
`xmlquery <https://github.com/antchfx/xmlquery>`_, XPath library
|
||||
`xpath <https://github.com/antchfx/xpath>`_, XPath library
|
||||
`xpathparser <https://github.com/santhosh-tekuri/xpathparser>`_, XPath library
|
||||
`yaml <https://gopkg.in/yaml.v3>`_, Serialization
|
||||
`zap <https://go.uber.org/zap>`_, Logging library
|
||||
|
||||
Java built-in support
|
||||
==================================
|
||||
|
||||
@@ -173,6 +173,7 @@ private predicate foo(Expr e, Expr p) {
|
||||
1. Use [camelCase](https://en.wikipedia.org/wiki/Camel_case) for:
|
||||
- Predicate names
|
||||
- Variable names
|
||||
1. Acronyms *should* use normal PascalCase/camelCase. However, two-letter acronyms should have both letters capitalized.
|
||||
1. Newtype predicate names *should* begin with `T`.
|
||||
1. Predicates that have a result *should* be named `get...`
|
||||
1. Predicates that can return multiple results *should* be named `getA...` or `getAn...`
|
||||
@@ -183,6 +184,7 @@ private predicate foo(Expr e, Expr p) {
|
||||
1. Use names as they are used in the target-language specification.
|
||||
1. Use American English.
|
||||
|
||||
|
||||
### Examples
|
||||
|
||||
```ql
|
||||
@@ -209,6 +211,9 @@ class Type extends ... {
|
||||
|
||||
/** ... */
|
||||
Type getATypeParameter() { ... }
|
||||
|
||||
/** Gets the SSA variable ... */
|
||||
predicate getSsaVariable() { ... }
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
import java
|
||||
|
||||
predicate complicatedBranch(Stmt branch) {
|
||||
exists(ConditionalExpr ce | ce.getParent*() = branch) or
|
||||
any(ConditionalExpr ce).getParent*() = branch or
|
||||
count(MethodAccess a | a.getParent*() = branch) > 1
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ predicate usefulUpcast(CastExpr e) {
|
||||
)
|
||||
or
|
||||
// Upcasts that are performed on an operand of a ternary expression.
|
||||
exists(ConditionalExpr ce | e = ce.getTrueExpr() or e = ce.getFalseExpr())
|
||||
e = any(ConditionalExpr ce).getABranchExpr()
|
||||
or
|
||||
// Upcasts to raw types.
|
||||
e.getType() instanceof RawType
|
||||
|
||||
@@ -16,10 +16,7 @@ class CharType extends PrimitiveType {
|
||||
CharType() { this.hasName("char") }
|
||||
}
|
||||
|
||||
private Type getABranchType(ConditionalExpr ce) {
|
||||
result = ce.getTrueExpr().getType() or
|
||||
result = ce.getFalseExpr().getType()
|
||||
}
|
||||
private Type getABranchType(ConditionalExpr ce) { result = ce.getABranchExpr().getType() }
|
||||
|
||||
from ConditionalExpr ce
|
||||
where
|
||||
|
||||
@@ -17,8 +17,8 @@ import semmle.code.java.Statement
|
||||
/** An expression that is used as a condition. */
|
||||
class BooleanExpr extends Expr {
|
||||
BooleanExpr() {
|
||||
exists(ConditionalStmt s | s.getCondition() = this) or
|
||||
exists(ConditionalExpr s | s.getCondition() = this)
|
||||
this = any(ConditionalStmt s).getCondition() or
|
||||
this = any(ConditionalExpr s).getCondition()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ private predicate flowsInto(Expr e, Variable v) {
|
||||
or
|
||||
exists(CastExpr c | flowsInto(c, v) | e = c.getExpr())
|
||||
or
|
||||
exists(ConditionalExpr c | flowsInto(c, v) | e = c.getTrueExpr() or e = c.getFalseExpr())
|
||||
exists(ConditionalExpr c | flowsInto(c, v) | e = c.getABranchExpr())
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -148,9 +148,7 @@ predicate upcastToWiderType(Expr e) {
|
||||
or
|
||||
exists(Parameter p | p.getAnArgument() = e and t2 = p.getType())
|
||||
or
|
||||
exists(ConditionalExpr cond | cond.getTrueExpr() = e or cond.getFalseExpr() = e |
|
||||
t2 = cond.getType()
|
||||
)
|
||||
exists(ConditionalExpr cond | cond.getABranchExpr() = e | t2 = cond.getType())
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -45,9 +45,7 @@ predicate unboxed(BoxedExpr e) {
|
||||
or
|
||||
flowTarget(e).getType() instanceof PrimitiveType
|
||||
or
|
||||
exists(ConditionalExpr cond | cond instanceof PrimitiveExpr |
|
||||
cond.getTrueExpr() = e or cond.getFalseExpr() = e
|
||||
)
|
||||
exists(ConditionalExpr cond | cond instanceof PrimitiveExpr | cond.getABranchExpr() = e)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
public class SensitiveGetQuery extends HttpServlet {
|
||||
// BAD - Tests sending sensitive information in a GET request.
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
String password = request.getParameter("password");
|
||||
System.out.println("password = " + password);
|
||||
}
|
||||
|
||||
// GOOD - Tests sending sensitive information in a POST request.
|
||||
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
String password = request.getParameter("password");
|
||||
System.out.println("password = " + password);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>Sensitive information such as user passwords should not be transmitted within the query string of the requested URL. Sensitive information within URLs may be logged in various locations, including the user's browser, the web server, and any forward or reverse proxy servers between the two endpoints. URLs may also be displayed on-screen, bookmarked or emailed around by users. They may be disclosed to third parties via the Referer header when any off-site links are followed. Placing passwords into the URL therefore increases the risk that they will be captured by an attacker.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>Use HTTP POST to send sensitive information as part of the request body; for example, as form data.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>The following example shows two ways of sending sensitive information. In the 'BAD' case, a password is transmitted using the GET method. In the 'GOOD' case, the password is transmitted using the POST method.</p>
|
||||
<sample src="SensitiveGetQuery.java" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
CWE:
|
||||
<a href="https://cwe.mitre.org/data/definitions/598.html">CWE-598: Use of GET Request Method with Sensitive Query Strings</a>
|
||||
</li>
|
||||
<li>
|
||||
PortSwigger (Burp):
|
||||
<a href="https://portswigger.net/kb/issues/00400300_password-submitted-using-get-method">Password Submitted using GET Method</a>
|
||||
</li>
|
||||
<li>
|
||||
OWASP:
|
||||
<a href="https://owasp.org/www-community/vulnerabilities/Information_exposure_through_query_strings_in_url">Information Exposure through Query Strings in URL</a>
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* @name Sensitive GET Query
|
||||
* @description Use of GET request method with sensitive query strings.
|
||||
* @kind path-problem
|
||||
* @id java/sensitive-query-with-get
|
||||
* @tags security
|
||||
* external/cwe-598
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.security.SensitiveActions
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/** A variable that holds sensitive information judging by its name. */
|
||||
class SensitiveInfoExpr extends Expr {
|
||||
SensitiveInfoExpr() {
|
||||
exists(Variable v | this = v.getAnAccess() |
|
||||
v.getName().regexpMatch(getCommonSensitiveInfoRegex()) and
|
||||
not v.getName().regexpMatch("token.*") // exclude ^token.* since sensitive tokens are usually in the form of accessToken, authToken, ...
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `m` is a method of some override of `HttpServlet.doGet`. */
|
||||
private predicate isGetServletMethod(Method m) {
|
||||
isServletRequestMethod(m) and m.getName() = "doGet"
|
||||
}
|
||||
|
||||
/** The `doGet` method of `HttpServlet`. */
|
||||
class DoGetServletMethod extends Method {
|
||||
DoGetServletMethod() { isGetServletMethod(this) }
|
||||
}
|
||||
|
||||
/** Holds if `ma` is (perhaps indirectly) called from the `doGet` method of `HttpServlet`. */
|
||||
predicate isReachableFromServletDoGet(MethodAccess ma) {
|
||||
ma.getEnclosingCallable() instanceof DoGetServletMethod
|
||||
or
|
||||
exists(Method pm, MethodAccess pma |
|
||||
ma.getEnclosingCallable() = pm and
|
||||
pma.getMethod() = pm and
|
||||
isReachableFromServletDoGet(pma)
|
||||
)
|
||||
}
|
||||
|
||||
/** Source of GET servlet requests. */
|
||||
class RequestGetParamSource extends DataFlow::ExprNode {
|
||||
RequestGetParamSource() {
|
||||
exists(MethodAccess ma |
|
||||
isRequestGetParamMethod(ma) and
|
||||
ma = this.asExpr() and
|
||||
isReachableFromServletDoGet(ma)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A taint configuration tracking flow from the `ServletRequest` of a GET request handler to an expression whose name suggests it holds security-sensitive data. */
|
||||
class SensitiveGetQueryConfiguration extends TaintTracking::Configuration {
|
||||
SensitiveGetQueryConfiguration() { this = "SensitiveGetQueryConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RequestGetParamSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof SensitiveInfoExpr }
|
||||
|
||||
/** Holds if the node is in a servlet method other than `doGet`. */
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
isServletRequestMethod(node.getEnclosingCallable()) and
|
||||
not isGetServletMethod(node.getEnclosingCallable())
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, SensitiveGetQueryConfiguration c
|
||||
where c.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"$@ uses the GET request method to transmit sensitive information.", source.getNode(),
|
||||
"This request"
|
||||
@@ -293,7 +293,7 @@ private module ControlFlowGraphImpl {
|
||||
exists(ConditionalExpr condexpr |
|
||||
condexpr.getCondition() = b
|
||||
or
|
||||
(condexpr.getTrueExpr() = b or condexpr.getFalseExpr() = b) and
|
||||
condexpr.getABranchExpr() = b and
|
||||
inBooleanContext(condexpr)
|
||||
)
|
||||
or
|
||||
@@ -706,8 +706,7 @@ private module ControlFlowGraphImpl {
|
||||
or
|
||||
// The last node of a `ConditionalExpr` is in either of its branches.
|
||||
exists(ConditionalExpr condexpr | condexpr = n |
|
||||
last(condexpr.getFalseExpr(), last, completion) or
|
||||
last(condexpr.getTrueExpr(), last, completion)
|
||||
last(condexpr.getABranchExpr(), last, completion)
|
||||
)
|
||||
or
|
||||
exists(InstanceOfExpr ioe | ioe.isPattern() and ioe = n |
|
||||
@@ -915,14 +914,10 @@ private module ControlFlowGraphImpl {
|
||||
)
|
||||
or
|
||||
// Control flows to the corresponding branch depending on the boolean completion of the condition.
|
||||
exists(ConditionalExpr e |
|
||||
exists(ConditionalExpr e, boolean branch |
|
||||
last(e.getCondition(), n, completion) and
|
||||
completion = BooleanCompletion(true, _) and
|
||||
result = first(e.getTrueExpr())
|
||||
or
|
||||
last(e.getCondition(), n, completion) and
|
||||
completion = BooleanCompletion(false, _) and
|
||||
result = first(e.getFalseExpr())
|
||||
completion = BooleanCompletion(branch, _) and
|
||||
result = first(e.getBranchExpr(branch))
|
||||
)
|
||||
or
|
||||
exists(InstanceOfExpr ioe | ioe.isPattern() |
|
||||
|
||||
@@ -184,11 +184,8 @@ class CompileTimeConstantExpr extends Expr {
|
||||
// Ternary conditional, with compile-time constant condition.
|
||||
exists(ConditionalExpr ce, boolean condition |
|
||||
ce = this and
|
||||
condition = ce.getCondition().(CompileTimeConstantExpr).getBooleanValue()
|
||||
|
|
||||
if condition = true
|
||||
then result = ce.getTrueExpr().(CompileTimeConstantExpr).getStringValue()
|
||||
else result = ce.getFalseExpr().(CompileTimeConstantExpr).getStringValue()
|
||||
condition = ce.getCondition().(CompileTimeConstantExpr).getBooleanValue() and
|
||||
result = ce.getBranchExpr(condition).(CompileTimeConstantExpr).getStringValue()
|
||||
)
|
||||
or
|
||||
exists(Variable v | this = v.getAnAccess() |
|
||||
@@ -295,11 +292,8 @@ class CompileTimeConstantExpr extends Expr {
|
||||
// Ternary expressions, where the `true` and `false` expressions are boolean compile-time constants.
|
||||
exists(ConditionalExpr ce, boolean condition |
|
||||
ce = this and
|
||||
condition = ce.getCondition().(CompileTimeConstantExpr).getBooleanValue()
|
||||
|
|
||||
if condition = true
|
||||
then result = ce.getTrueExpr().(CompileTimeConstantExpr).getBooleanValue()
|
||||
else result = ce.getFalseExpr().(CompileTimeConstantExpr).getBooleanValue()
|
||||
condition = ce.getCondition().(CompileTimeConstantExpr).getBooleanValue() and
|
||||
result = ce.getBranchExpr(condition).(CompileTimeConstantExpr).getBooleanValue()
|
||||
)
|
||||
or
|
||||
// Simple or qualified names where the variable is final and the initializer is a constant.
|
||||
@@ -380,11 +374,8 @@ class CompileTimeConstantExpr extends Expr {
|
||||
// Ternary conditional, with compile-time constant condition.
|
||||
exists(ConditionalExpr ce, boolean condition |
|
||||
ce = this and
|
||||
condition = ce.getCondition().(CompileTimeConstantExpr).getBooleanValue()
|
||||
|
|
||||
if condition = true
|
||||
then result = ce.getTrueExpr().(CompileTimeConstantExpr).getIntValue()
|
||||
else result = ce.getFalseExpr().(CompileTimeConstantExpr).getIntValue()
|
||||
condition = ce.getCondition().(CompileTimeConstantExpr).getBooleanValue() and
|
||||
result = ce.getBranchExpr(condition).(CompileTimeConstantExpr).getIntValue()
|
||||
)
|
||||
or
|
||||
// If a `Variable` is a `CompileTimeConstantExpr`, its value is its initializer.
|
||||
@@ -1186,8 +1177,7 @@ class ChooseExpr extends Expr {
|
||||
|
||||
/** Gets a result expression of this `switch` or conditional expression. */
|
||||
Expr getAResultExpr() {
|
||||
result = this.(ConditionalExpr).getTrueExpr() or
|
||||
result = this.(ConditionalExpr).getFalseExpr() or
|
||||
result = this.(ConditionalExpr).getABranchExpr() or
|
||||
result = this.(SwitchExpr).getAResult()
|
||||
}
|
||||
}
|
||||
@@ -1213,6 +1203,23 @@ class ConditionalExpr extends Expr, @conditionalexpr {
|
||||
*/
|
||||
Expr getFalseExpr() { result.isNthChildOf(this, 2) }
|
||||
|
||||
/**
|
||||
* Gets the expression that is evaluated by the specific branch of this
|
||||
* conditional expression. If `true` that is `getTrueExpr()`, if `false`
|
||||
* it is `getFalseExpr()`.
|
||||
*/
|
||||
Expr getBranchExpr(boolean branch) {
|
||||
branch = true and result = getTrueExpr()
|
||||
or
|
||||
branch = false and result = getFalseExpr()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expressions that is evaluated by one of the branches (`true`
|
||||
* or `false` branch) of this conditional expression.
|
||||
*/
|
||||
Expr getABranchExpr() { result = getBranchExpr(_) }
|
||||
|
||||
/** Gets a printable representation of this expression. */
|
||||
override string toString() { result = "...?...:..." }
|
||||
|
||||
|
||||
@@ -40,19 +40,14 @@ predicate implies_v1(Guard g1, boolean b1, Guard g2, boolean b2) {
|
||||
)
|
||||
or
|
||||
exists(ConditionalExpr cond, boolean branch, BooleanLiteral boollit, boolean boolval |
|
||||
cond.getTrueExpr() = boollit and branch = true
|
||||
or
|
||||
cond.getFalseExpr() = boollit and branch = false
|
||||
|
|
||||
cond.getBranchExpr(branch) = boollit and
|
||||
cond = g1 and
|
||||
boolval = boollit.getBooleanValue() and
|
||||
b1 = boolval.booleanNot() and
|
||||
(
|
||||
g2 = cond.getCondition() and b2 = branch.booleanNot()
|
||||
or
|
||||
g2 = cond.getTrueExpr() and b2 = b1
|
||||
or
|
||||
g2 = cond.getFalseExpr() and b2 = b1
|
||||
g2 = cond.getABranchExpr() and b2 = b1
|
||||
)
|
||||
)
|
||||
or
|
||||
@@ -216,9 +211,7 @@ private predicate hasPossibleUnknownValue(SsaVariable v) {
|
||||
* `ConditionalExpr`s.
|
||||
*/
|
||||
private Expr possibleValue(Expr e) {
|
||||
result = possibleValue(e.(ConditionalExpr).getTrueExpr())
|
||||
or
|
||||
result = possibleValue(e.(ConditionalExpr).getFalseExpr())
|
||||
result = possibleValue(e.(ConditionalExpr).getABranchExpr())
|
||||
or
|
||||
result = e and not e instanceof ConditionalExpr
|
||||
}
|
||||
@@ -316,9 +309,7 @@ private predicate conditionalAssign(SsaVariable v, Guard guard, boolean branch,
|
||||
v.(SsaExplicitUpdate).getDefiningExpr().(VariableAssign).getSource() = c and
|
||||
guard = c.getCondition()
|
||||
|
|
||||
branch = true and e = c.getTrueExpr()
|
||||
or
|
||||
branch = false and e = c.getFalseExpr()
|
||||
e = c.getBranchExpr(branch)
|
||||
)
|
||||
or
|
||||
exists(SsaExplicitUpdate upd, SsaPhiNode phi |
|
||||
|
||||
519
java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll
Normal file
519
java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll
Normal file
@@ -0,0 +1,519 @@
|
||||
/**
|
||||
* INTERNAL use only. This is an experimental API subject to change without notice.
|
||||
*
|
||||
* Provides classes and predicates for dealing with flow models specified in CSV format.
|
||||
*
|
||||
* The CSV specification has the following columns:
|
||||
* - Sources:
|
||||
* `namespace; type; subtypes; name; signature; ext; output; kind`
|
||||
* - Sinks:
|
||||
* `namespace; type; subtypes; name; signature; ext; input; kind`
|
||||
* - Summaries:
|
||||
* `namespace; type; subtypes; name; signature; ext; input; output; kind`
|
||||
*
|
||||
* The interpretation of a row is similar to API-graphs with a left-to-right
|
||||
* reading.
|
||||
* 1. The `namespace` column selects a package.
|
||||
* 2. The `type` column selects a type within that package.
|
||||
* 3. The `subtypes` is a boolean that indicates whether to jump to an
|
||||
* arbitrary subtype of that type.
|
||||
* 4. The `name` column optionally selects a specific named member of the type.
|
||||
* 5. The `signature` column optionally restricts the named member. If
|
||||
* `signature` is blank then no such filtering is done. The format of the
|
||||
* signature is a comma-separated list of types enclosed in parentheses. The
|
||||
* types can be short names or fully qualified names (mixing these two options
|
||||
* is not allowed within a single signature).
|
||||
* 6. The `ext` column specifies additional API-graph-like edges. Currently
|
||||
* there are only two valid values: "" and "Annotated". The empty string has no
|
||||
* effect. "Annotated" applies if `name` and `signature` were left blank and
|
||||
* acts by selecting an element that is annotated by the annotation type
|
||||
* selected by the first 4 columns. This can be another member such as a field
|
||||
* or method, or a parameter.
|
||||
* 7. The `input` column specifies how data enters the element selected by the
|
||||
* first 6 columns, and the `output` column specifies how data leaves the
|
||||
* element selected by the first 6 columns. An `input` can be either "",
|
||||
* "Argument", "Argument[n]", "ReturnValue":
|
||||
* - "": Selects a write to the selected element in case this is a field.
|
||||
* - "Argument": Selects any argument in a call to the selected element.
|
||||
* - "Argument[n]": Similar to "Argument" but restricted to a specific numbered
|
||||
* argument (zero-indexed, and `-1` specifies the qualifier).
|
||||
* - "ReturnValue": Selects a value being returned by the selected element.
|
||||
* This requires that the selected element is a method with a body.
|
||||
*
|
||||
* An `output` can be either "", "Argument", "Argument[n]", "Parameter",
|
||||
* "Parameter[n]", or "ReturnValue":
|
||||
* - "": Selects a read of a selected field, or a selected parameter.
|
||||
* - "Argument": Selects the post-update value of an argument in a call to the
|
||||
* selected element. That is, the value of the argument after the call returns.
|
||||
* - "Argument[n]": Similar to "Argument" but restricted to a specific numbered
|
||||
* argument (zero-indexed, and `-1` specifies the qualifier).
|
||||
* - "Parameter": Selects the value of a parameter of the selected element.
|
||||
* "Parameter" is also allowed in case the selected element is already a
|
||||
* parameter itself.
|
||||
* - "Parameter[n]": Similar to "Parameter" but restricted to a specific
|
||||
* numbered parameter (zero-indexed, and `-1` specifies the value of `this`).
|
||||
* - "ReturnValue": Selects the return value of a call to the selected element.
|
||||
* 8. The `kind` column is a tag that can be referenced from QL to determine to
|
||||
* which classes the interpreted elements should be added. For example, for
|
||||
* sources "remote" indicates a default remote flow source, and for summaries
|
||||
* "taint" indicates a default additional taint step and "value" indicates a
|
||||
* globally applicable value-preserving step.
|
||||
*/
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow::DataFlow
|
||||
private import internal.DataFlowPrivate
|
||||
|
||||
private predicate sourceModelCsv(string row) {
|
||||
row =
|
||||
[
|
||||
// ServletRequestGetParameterMethod
|
||||
"javax.servlet;ServletRequest;false;getParameter;(String);;ReturnValue;remote",
|
||||
"javax.servlet;ServletRequest;false;getParameterValues;(String);;ReturnValue;remote",
|
||||
"javax.servlet.http;HttpServletRequest;false;getParameter;(String);;ReturnValue;remote",
|
||||
"javax.servlet.http;HttpServletRequest;false;getParameterValues;(String);;ReturnValue;remote",
|
||||
// ServletRequestGetParameterMapMethod
|
||||
"javax.servlet;ServletRequest;false;getParameterMap;();;ReturnValue;remote",
|
||||
"javax.servlet.http;HttpServletRequest;false;getParameterMap;();;ReturnValue;remote",
|
||||
// ServletRequestGetParameterNamesMethod
|
||||
"javax.servlet;ServletRequest;false;getParameterNames;();;ReturnValue;remote",
|
||||
"javax.servlet.http;HttpServletRequest;false;getParameterNames;();;ReturnValue;remote",
|
||||
// HttpServletRequestGetQueryStringMethod
|
||||
"javax.servlet.http;HttpServletRequest;false;getQueryString;();;ReturnValue;remote",
|
||||
//
|
||||
// URLConnectionGetInputStreamMethod
|
||||
"java.net;URLConnection;false;getInputStream;();;ReturnValue;remote",
|
||||
// SocketGetInputStreamMethod
|
||||
"java.net;Socket;false;getInputStream;();;ReturnValue;remote",
|
||||
// BeanValidationSource
|
||||
"javax.validation;ConstraintValidator;true;isValid;;;Parameter[0];remote"
|
||||
]
|
||||
}
|
||||
|
||||
private predicate sinkModelCsv(string row) { none() }
|
||||
|
||||
private predicate summaryModelCsv(string row) { none() }
|
||||
|
||||
/**
|
||||
* A unit class for adding additional source model rows.
|
||||
*
|
||||
* Extend this class to add additional source definitions.
|
||||
*/
|
||||
class SourceModelCsv extends Unit {
|
||||
/** Holds if `row` specifies a source definition. */
|
||||
abstract predicate row(string row);
|
||||
}
|
||||
|
||||
/**
|
||||
* A unit class for adding additional sink model rows.
|
||||
*
|
||||
* Extend this class to add additional sink definitions.
|
||||
*/
|
||||
class SinkModelCsv extends Unit {
|
||||
/** Holds if `row` specifies a sink definition. */
|
||||
abstract predicate row(string row);
|
||||
}
|
||||
|
||||
/**
|
||||
* A unit class for adding additional summary model rows.
|
||||
*
|
||||
* Extend this class to add additional flow summary definitions.
|
||||
*/
|
||||
class SummaryModelCsv extends Unit {
|
||||
/** Holds if `row` specifies a summary definition. */
|
||||
abstract predicate row(string row);
|
||||
}
|
||||
|
||||
private predicate sourceModel(string row) {
|
||||
sourceModelCsv(row) or
|
||||
any(SourceModelCsv s).row(row)
|
||||
}
|
||||
|
||||
private predicate sinkModel(string row) {
|
||||
sinkModelCsv(row) or
|
||||
any(SinkModelCsv s).row(row)
|
||||
}
|
||||
|
||||
private predicate summaryModel(string row) {
|
||||
summaryModelCsv(row) or
|
||||
any(SummaryModelCsv s).row(row)
|
||||
}
|
||||
|
||||
private predicate sourceModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string output, string kind
|
||||
) {
|
||||
exists(string row |
|
||||
sourceModel(row) and
|
||||
row.splitAt(";", 0) = namespace and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = subtypes.toString() and
|
||||
subtypes = [true, false] and
|
||||
row.splitAt(";", 3) = name and
|
||||
row.splitAt(";", 4) = signature and
|
||||
row.splitAt(";", 5) = ext and
|
||||
row.splitAt(";", 6) = output and
|
||||
row.splitAt(";", 7) = kind
|
||||
)
|
||||
}
|
||||
|
||||
private predicate sinkModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string kind
|
||||
) {
|
||||
exists(string row |
|
||||
sinkModel(row) and
|
||||
row.splitAt(";", 0) = namespace and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = subtypes.toString() and
|
||||
subtypes = [true, false] and
|
||||
row.splitAt(";", 3) = name and
|
||||
row.splitAt(";", 4) = signature and
|
||||
row.splitAt(";", 5) = ext and
|
||||
row.splitAt(";", 6) = input and
|
||||
row.splitAt(";", 7) = kind
|
||||
)
|
||||
}
|
||||
|
||||
private predicate summaryModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string output, string kind
|
||||
) {
|
||||
exists(string row |
|
||||
summaryModel(row) and
|
||||
row.splitAt(";", 0) = namespace and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = subtypes.toString() and
|
||||
subtypes = [true, false] and
|
||||
row.splitAt(";", 3) = name and
|
||||
row.splitAt(";", 4) = signature and
|
||||
row.splitAt(";", 5) = ext and
|
||||
row.splitAt(";", 6) = input and
|
||||
row.splitAt(";", 7) = output and
|
||||
row.splitAt(";", 8) = kind
|
||||
)
|
||||
}
|
||||
|
||||
/** Provides a query predicate to check the CSV data for validation errors. */
|
||||
module CsvValidation {
|
||||
/** Holds if some row in a CSV-based flow model appears to contain typos. */
|
||||
query predicate invalidModelRow(string msg) {
|
||||
exists(string pred, string namespace, string type, string name, string signature, string ext |
|
||||
sourceModel(namespace, type, _, name, signature, ext, _, _) and pred = "source"
|
||||
or
|
||||
sinkModel(namespace, type, _, name, signature, ext, _, _) and pred = "sink"
|
||||
or
|
||||
summaryModel(namespace, type, _, name, signature, ext, _, _, _) and pred = "summary"
|
||||
|
|
||||
not namespace.regexpMatch("[a-zA-Z0-9_\\.]+") and
|
||||
msg = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
|
||||
or
|
||||
not type.regexpMatch("[a-zA-Z0-9_\\$]+") and
|
||||
msg = "Dubious type \"" + type + "\" in " + pred + " model."
|
||||
or
|
||||
not name.regexpMatch("[a-zA-Z0-9_]*") and
|
||||
msg = "Dubious name \"" + name + "\" in " + pred + " model."
|
||||
or
|
||||
not signature.regexpMatch("|\\([a-zA-Z0-9_\\.\\$<>,]*\\)") and
|
||||
msg = "Dubious signature \"" + signature + "\" in " + pred + " model."
|
||||
or
|
||||
not ext.regexpMatch("|Annotated") and
|
||||
msg = "Unrecognized extra API graph element \"" + ext + "\" in " + pred + " model."
|
||||
)
|
||||
or
|
||||
exists(string pred, string input, string part |
|
||||
sinkModel(_, _, _, _, _, _, input, _) and pred = "sink"
|
||||
or
|
||||
summaryModel(_, _, _, _, _, _, input, _, _) and pred = "summary"
|
||||
|
|
||||
specSplit(input, part, _) and
|
||||
not part.regexpMatch("|Argument|ReturnValue") and
|
||||
not parseArg(part, _) and
|
||||
msg = "Unrecognized input specification \"" + part + "\" in " + pred + " model."
|
||||
)
|
||||
or
|
||||
exists(string pred, string output, string part |
|
||||
sourceModel(_, _, _, _, _, _, output, _) and pred = "source"
|
||||
or
|
||||
summaryModel(_, _, _, _, _, _, _, output, _) and pred = "summary"
|
||||
|
|
||||
specSplit(output, part, _) and
|
||||
not part.regexpMatch("|Argument|Parameter|ReturnValue") and
|
||||
not parseArg(part, _) and
|
||||
not parseParam(part, _) and
|
||||
msg = "Unrecognized output specification \"" + part + "\" in " + pred + " model."
|
||||
)
|
||||
or
|
||||
exists(string pred, string row, int expect |
|
||||
sourceModel(row) and expect = 8 and pred = "source"
|
||||
or
|
||||
sinkModel(row) and expect = 8 and pred = "sink"
|
||||
or
|
||||
summaryModel(row) and expect = 9 and pred = "summary"
|
||||
|
|
||||
exists(int cols |
|
||||
cols = 1 + max(int n | exists(row.splitAt(";", n))) and
|
||||
cols != expect and
|
||||
msg =
|
||||
"Wrong number of columns in " + pred + " model row, expected " + expect + ", got " + cols +
|
||||
"."
|
||||
)
|
||||
or
|
||||
exists(string b |
|
||||
b = row.splitAt(";", 2) and
|
||||
not b = ["true", "false"] and
|
||||
msg = "Invalid boolean \"" + b + "\" in " + pred + " model."
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate elementSpec(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
) {
|
||||
sourceModel(namespace, type, subtypes, name, signature, ext, _, _) or
|
||||
sinkModel(namespace, type, subtypes, name, signature, ext, _, _) or
|
||||
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _)
|
||||
}
|
||||
|
||||
bindingset[namespace, type, subtypes]
|
||||
private RefType interpretType(string namespace, string type, boolean subtypes) {
|
||||
exists(RefType t |
|
||||
t.hasQualifiedName(namespace, type) and
|
||||
if subtypes = true then result.getASourceSupertype*() = t else result = t
|
||||
)
|
||||
}
|
||||
|
||||
private string paramsStringPart(Callable c, int i) {
|
||||
i = -1 and result = "("
|
||||
or
|
||||
exists(int n, string p | c.getParameterType(n).toString() = p |
|
||||
i = 2 * n and result = p
|
||||
or
|
||||
i = 2 * n - 1 and result = "," and n != 0
|
||||
)
|
||||
or
|
||||
i = 2 * c.getNumberOfParameters() and result = ")"
|
||||
}
|
||||
|
||||
private string paramsString(Callable c) {
|
||||
result = concat(int i | | paramsStringPart(c, i) order by i)
|
||||
}
|
||||
|
||||
private Element interpretElement0(
|
||||
string namespace, string type, boolean subtypes, string name, string signature
|
||||
) {
|
||||
elementSpec(namespace, type, subtypes, name, signature, _) and
|
||||
exists(RefType t | t = interpretType(namespace, type, subtypes) |
|
||||
exists(Member m |
|
||||
result = m and
|
||||
m.getDeclaringType() = t and
|
||||
m.hasName(name)
|
||||
|
|
||||
signature = "" or
|
||||
m.(Callable).getSignature() = any(string nameprefix) + signature or
|
||||
paramsString(m) = signature
|
||||
)
|
||||
or
|
||||
result = t and
|
||||
name = "" and
|
||||
signature = ""
|
||||
)
|
||||
}
|
||||
|
||||
private Element interpretElement(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
) {
|
||||
elementSpec(namespace, type, subtypes, name, signature, ext) and
|
||||
exists(Element e | e = interpretElement0(namespace, type, subtypes, name, signature) |
|
||||
ext = "" and result = e
|
||||
or
|
||||
ext = "Annotated" and result.(Annotatable).getAnAnnotation().getType() = e
|
||||
)
|
||||
}
|
||||
|
||||
private predicate sourceElement(Element e, string output, string kind) {
|
||||
exists(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
|
|
||||
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind) and
|
||||
e = interpretElement(namespace, type, subtypes, name, signature, ext)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate sinkElement(Element e, string input, string kind) {
|
||||
exists(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
|
|
||||
sinkModel(namespace, type, subtypes, name, signature, ext, input, kind) and
|
||||
e = interpretElement(namespace, type, subtypes, name, signature, ext)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate summaryElement(Element e, string input, string output, string kind) {
|
||||
exists(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
|
|
||||
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind) and
|
||||
e = interpretElement(namespace, type, subtypes, name, signature, ext)
|
||||
)
|
||||
}
|
||||
|
||||
private string inOutSpec() {
|
||||
sourceModel(_, _, _, _, _, _, result, _) or
|
||||
sinkModel(_, _, _, _, _, _, result, _) or
|
||||
summaryModel(_, _, _, _, _, _, result, _, _) or
|
||||
summaryModel(_, _, _, _, _, _, _, result, _)
|
||||
}
|
||||
|
||||
private predicate specSplit(string s, string c, int n) {
|
||||
inOutSpec() = s and s.splitAt(" of ", n) = c
|
||||
}
|
||||
|
||||
private predicate len(string s, int len) { len = 1 + max(int n | specSplit(s, _, n)) }
|
||||
|
||||
private string getLast(string s) {
|
||||
exists(int len |
|
||||
len(s, len) and
|
||||
specSplit(s, result, len - 1)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate parseParam(string c, int n) {
|
||||
specSplit(_, c, _) and c.regexpCapture("Parameter\\[([-0-9]+)\\]", 1).toInt() = n
|
||||
}
|
||||
|
||||
private predicate parseArg(string c, int n) {
|
||||
specSplit(_, c, _) and c.regexpCapture("Argument\\[([-0-9]+)\\]", 1).toInt() = n
|
||||
}
|
||||
|
||||
private predicate inputNeedsReference(string c) {
|
||||
c = "Argument" or
|
||||
parseArg(c, _)
|
||||
}
|
||||
|
||||
private predicate outputNeedsReference(string c) {
|
||||
c = "Argument" or
|
||||
parseArg(c, _) or
|
||||
c = "ReturnValue"
|
||||
}
|
||||
|
||||
private predicate sourceElementRef(Top ref, string output, string kind) {
|
||||
exists(Element e |
|
||||
sourceElement(e, output, kind) and
|
||||
if outputNeedsReference(getLast(output)) then ref.(Call).getCallee() = e else ref = e
|
||||
)
|
||||
}
|
||||
|
||||
private predicate sinkElementRef(Top ref, string input, string kind) {
|
||||
exists(Element e |
|
||||
sinkElement(e, input, kind) and
|
||||
if inputNeedsReference(getLast(input)) then ref.(Call).getCallee() = e else ref = e
|
||||
)
|
||||
}
|
||||
|
||||
private predicate summaryElementRef(Top ref, string input, string output, string kind) {
|
||||
exists(Element e |
|
||||
summaryElement(e, input, output, kind) and
|
||||
if inputNeedsReference(getLast(input)) then ref.(Call).getCallee() = e else ref = e
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TAstOrNode =
|
||||
TAst(Top t) or
|
||||
TNode(Node n)
|
||||
|
||||
private predicate interpretOutput(string output, int idx, Top ref, TAstOrNode node) {
|
||||
(
|
||||
sourceElementRef(ref, output, _) or
|
||||
summaryElementRef(ref, _, output, _)
|
||||
) and
|
||||
len(output, idx) and
|
||||
node = TAst(ref)
|
||||
or
|
||||
exists(Top mid, string c, Node n |
|
||||
interpretOutput(output, idx + 1, ref, TAst(mid)) and
|
||||
specSplit(output, c, idx) and
|
||||
node = TNode(n)
|
||||
|
|
||||
exists(int pos | n.(PostUpdateNode).getPreUpdateNode().(ArgumentNode).argumentOf(mid, pos) |
|
||||
c = "Argument" or parseArg(c, pos)
|
||||
)
|
||||
or
|
||||
exists(int pos | n.(ParameterNode).isParameterOf(mid, pos) |
|
||||
c = "Parameter" or parseParam(c, pos)
|
||||
)
|
||||
or
|
||||
(c = "Parameter" or c = "") and
|
||||
n.asParameter() = mid
|
||||
or
|
||||
c = "ReturnValue" and
|
||||
n.asExpr().(Call) = mid
|
||||
or
|
||||
c = "" and
|
||||
n.asExpr().(FieldRead).getField() = mid
|
||||
)
|
||||
}
|
||||
|
||||
private predicate interpretInput(string input, int idx, Top ref, TAstOrNode node) {
|
||||
(
|
||||
sinkElementRef(ref, input, _) or
|
||||
summaryElementRef(ref, input, _, _)
|
||||
) and
|
||||
len(input, idx) and
|
||||
node = TAst(ref)
|
||||
or
|
||||
exists(Top mid, string c, Node n |
|
||||
interpretInput(input, idx + 1, ref, TAst(mid)) and
|
||||
specSplit(input, c, idx) and
|
||||
node = TNode(n)
|
||||
|
|
||||
exists(int pos | n.(ArgumentNode).argumentOf(mid, pos) | c = "Argument" or parseArg(c, pos))
|
||||
or
|
||||
exists(ReturnStmt ret |
|
||||
c = "ReturnValue" and
|
||||
n.asExpr() = ret.getResult() and
|
||||
mid = ret.getEnclosingCallable()
|
||||
)
|
||||
or
|
||||
exists(FieldWrite fw |
|
||||
c = "" and
|
||||
fw.getField() = mid and
|
||||
n.asExpr() = fw.getRHS()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is specified as a source with the given kind in a CSV flow
|
||||
* model.
|
||||
*/
|
||||
predicate sourceNode(Node node, string kind) {
|
||||
exists(Top ref, string output |
|
||||
sourceElementRef(ref, output, kind) and
|
||||
interpretOutput(output, 0, ref, TNode(node))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is specified as a sink with the given kind in a CSV flow
|
||||
* model.
|
||||
*/
|
||||
predicate sinkNode(Node node, string kind) {
|
||||
exists(Top ref, string input |
|
||||
sinkElementRef(ref, input, kind) and
|
||||
interpretInput(input, 0, ref, TNode(node))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node1` to `node2` is specified as a flow step with the given kind
|
||||
* in a CSV flow model.
|
||||
*/
|
||||
predicate summaryStep(Node node1, Node node2, string kind) {
|
||||
exists(Top ref, string input, string output |
|
||||
summaryElementRef(ref, input, output, kind) and
|
||||
interpretInput(input, 0, ref, TNode(node1)) and
|
||||
interpretOutput(output, 0, ref, TNode(node2))
|
||||
)
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import semmle.code.java.frameworks.spring.SpringWebClient
|
||||
import semmle.code.java.frameworks.Guice
|
||||
import semmle.code.java.frameworks.struts.StrutsActions
|
||||
import semmle.code.java.frameworks.Thrift
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
|
||||
/** A data flow source of remote user input. */
|
||||
abstract class RemoteFlowSource extends DataFlow::Node {
|
||||
@@ -31,6 +32,12 @@ abstract class RemoteFlowSource extends DataFlow::Node {
|
||||
abstract string getSourceType();
|
||||
}
|
||||
|
||||
private class ExternalRemoteFlowSource extends RemoteFlowSource {
|
||||
ExternalRemoteFlowSource() { sourceNode(this, "remote") }
|
||||
|
||||
override string getSourceType() { result = "external" }
|
||||
}
|
||||
|
||||
private class RemoteTaintedMethodAccessSource extends RemoteFlowSource {
|
||||
RemoteTaintedMethodAccessSource() {
|
||||
this.asExpr().(MethodAccess).getMethod() instanceof RemoteTaintedMethod
|
||||
|
||||
@@ -268,9 +268,7 @@ predicate exprModulus(Expr e, Bound b, int val, int mod) {
|
||||
private predicate condExprBranchModulus(
|
||||
ConditionalExpr cond, boolean branch, Bound b, int val, int mod
|
||||
) {
|
||||
exprModulus(cond.getTrueExpr(), b, val, mod) and branch = true
|
||||
or
|
||||
exprModulus(cond.getFalseExpr(), b, val, mod) and branch = false
|
||||
exprModulus(cond.getBranchExpr(branch), b, val, mod)
|
||||
}
|
||||
|
||||
private predicate addModulus(Expr add, boolean isLeft, Bound b, int val, int mod) {
|
||||
|
||||
@@ -191,7 +191,7 @@ private predicate varMaybeNull(SsaVariable v, string msg, Expr reason) {
|
||||
// Comparisons in finally blocks are excluded since missing exception edges in the CFG could otherwise yield FPs.
|
||||
not exists(TryStmt try | try.getFinally() = e.getEnclosingStmt().getEnclosingStmt*()) and
|
||||
(
|
||||
exists(ConditionalExpr c | c.getCondition().getAChildExpr*() = e) or
|
||||
e = any(ConditionalExpr c).getCondition().getAChildExpr*() or
|
||||
not exists(MethodAccess ma | ma.getAnArgument().getAChildExpr*() = e)
|
||||
) and
|
||||
// Don't use a guard as reason if there is a null assignment.
|
||||
@@ -438,13 +438,8 @@ private predicate varConditionallyNull(SsaExplicitUpdate v, ConditionBlock cond,
|
||||
v.getDefiningExpr().(VariableAssign).getSource() = condexpr and
|
||||
condexpr.getCondition() = cond.getCondition()
|
||||
|
|
||||
condexpr.getTrueExpr() = nullExpr() and
|
||||
branch = true and
|
||||
not condexpr.getFalseExpr() = nullExpr()
|
||||
or
|
||||
condexpr.getFalseExpr() = nullExpr() and
|
||||
branch = false and
|
||||
not condexpr.getTrueExpr() = nullExpr()
|
||||
condexpr.getBranchExpr(branch) = nullExpr() and
|
||||
not condexpr.getBranchExpr(branch.booleanNot()) = nullExpr()
|
||||
)
|
||||
or
|
||||
v.getDefiningExpr().(VariableAssign).getSource() = nullExpr() and
|
||||
|
||||
@@ -874,7 +874,5 @@ private predicate boundedConditionalExpr(
|
||||
ConditionalExpr cond, Bound b, boolean upper, boolean branch, int delta, boolean fromBackEdge,
|
||||
int origdelta, Reason reason
|
||||
) {
|
||||
branch = true and bounded(cond.getTrueExpr(), b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
or
|
||||
branch = false and bounded(cond.getFalseExpr(), b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
bounded(cond.getBranchExpr(branch), b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
}
|
||||
|
||||
@@ -27,10 +27,9 @@ private predicate nonNullSsaFwdStep(SsaVariable v, SsaVariable phi) {
|
||||
}
|
||||
|
||||
private predicate nonNullDefStep(Expr e1, Expr e2) {
|
||||
exists(ConditionalExpr cond | cond = e2 |
|
||||
cond.getTrueExpr() = e1 and cond.getFalseExpr() instanceof NullLiteral
|
||||
or
|
||||
cond.getFalseExpr() = e1 and cond.getTrueExpr() instanceof NullLiteral
|
||||
exists(ConditionalExpr cond, boolean branch | cond = e2 |
|
||||
cond.getBranchExpr(branch) = e1 and
|
||||
cond.getBranchExpr(branch.booleanNot()) instanceof NullLiteral
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ private import DataFlowPrivate
|
||||
private import semmle.code.java.dataflow.SSA
|
||||
private import semmle.code.java.dataflow.TypeFlow
|
||||
private import semmle.code.java.controlflow.Guards
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
import semmle.code.java.dataflow.InstanceAccess
|
||||
|
||||
cached
|
||||
@@ -405,6 +406,8 @@ predicate simpleLocalFlowStep(Node node1, Node node2) {
|
||||
or
|
||||
node2.asExpr().(AssignExpr).getSource() = node1.asExpr()
|
||||
or
|
||||
summaryStep(node1, node2, "value")
|
||||
or
|
||||
exists(MethodAccess ma, Method m |
|
||||
ma = node2.asExpr() and
|
||||
m = ma.getMethod() and
|
||||
|
||||
@@ -10,6 +10,7 @@ private import semmle.code.java.dataflow.internal.ContainerFlow
|
||||
private import semmle.code.java.frameworks.spring.SpringController
|
||||
private import semmle.code.java.frameworks.spring.SpringHttp
|
||||
private import semmle.code.java.frameworks.Networking
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
import semmle.code.java.dataflow.FlowSteps
|
||||
|
||||
/**
|
||||
@@ -45,6 +46,8 @@ predicate localAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
localAdditionalTaintUpdateStep(src.asExpr(),
|
||||
sink.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr())
|
||||
or
|
||||
summaryStep(src, sink, "taint")
|
||||
or
|
||||
exists(Argument arg |
|
||||
src.asExpr() = arg and
|
||||
arg.isVararg() and
|
||||
|
||||
@@ -7,10 +7,7 @@ import semmle.code.java.JDKAnnotations
|
||||
Expr valueFlow(Expr src) {
|
||||
result = src
|
||||
or
|
||||
exists(ConditionalExpr c | result = c |
|
||||
src = c.getTrueExpr() or
|
||||
src = c.getFalseExpr()
|
||||
)
|
||||
result.(ConditionalExpr).getABranchExpr() = src
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -322,3 +322,18 @@ class ServletWebXMLListenerType extends RefType {
|
||||
// - `HttpSessionBindingListener`
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `m` is a request handler method (for example `doGet` or `doPost`). */
|
||||
predicate isServletRequestMethod(Method m) {
|
||||
m.getDeclaringType() instanceof ServletClass and
|
||||
m.getNumberOfParameters() = 2 and
|
||||
m.getParameter(0).getType() instanceof ServletRequest and
|
||||
m.getParameter(1).getType() instanceof ServletResponse
|
||||
}
|
||||
|
||||
/** Holds if `ma` is a call that gets a request parameter. */
|
||||
predicate isRequestGetParamMethod(MethodAccess ma) {
|
||||
ma.getMethod() instanceof ServletRequestGetParameterMethod or
|
||||
ma.getMethod() instanceof ServletRequestGetParameterMapMethod or
|
||||
ma.getMethod() instanceof HttpServletRequestGetQueryStringMethod
|
||||
}
|
||||
|
||||
@@ -118,3 +118,96 @@ private class ApacheStringUtilsTaintPreservingMethod extends TaintPreservingCall
|
||||
not isExcludedParameter(arg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method declared on Apache Commons Lang's `StrBuilder`, or the same class or its
|
||||
* renamed version `TextStringBuilder` in Commons Text.
|
||||
*/
|
||||
class ApacheStrBuilderCallable extends Callable {
|
||||
ApacheStrBuilderCallable() {
|
||||
this.getDeclaringType().hasQualifiedName("org.apache.commons.lang3.text", "StrBuilder") or
|
||||
this.getDeclaringType()
|
||||
.hasQualifiedName("org.apache.commons.text", ["StrBuilder", "TextStringBuilder"])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An Apache Commons Lang `StrBuilder` method that adds taint to the `StrBuilder`.
|
||||
*/
|
||||
private class ApacheStrBuilderTaintingMethod extends ApacheStrBuilderCallable,
|
||||
TaintPreservingCallable {
|
||||
ApacheStrBuilderTaintingMethod() {
|
||||
this instanceof Constructor
|
||||
or
|
||||
this.hasName([
|
||||
"append", "appendAll", "appendFixedWidthPadLeft", "appendFixedWidthPadRight", "appendln",
|
||||
"appendSeparator", "appendWithSeparators", "insert", "readFrom", "replace", "replaceAll",
|
||||
"replaceFirst"
|
||||
])
|
||||
}
|
||||
|
||||
private predicate consumesTaintFromAllArgs() {
|
||||
// Specifically the append[ln](String, Object...) overloads also consume taint from their other arguments:
|
||||
this.getName() in ["appendAll", "appendWithSeparators"]
|
||||
or
|
||||
this.getName() = ["append", "appendln"] and this.getAParameter().isVarargs()
|
||||
or
|
||||
this.getName() = "appendSeparator" and this.getParameterType(1) instanceof TypeString
|
||||
}
|
||||
|
||||
override predicate transfersTaint(int fromArg, int toArg) {
|
||||
// Taint the qualifier
|
||||
toArg = -1 and
|
||||
(
|
||||
this.getName().matches(["append%", "readFrom"]) and fromArg = 0
|
||||
or
|
||||
this.getName() = "insert" and fromArg = 1
|
||||
or
|
||||
this.getName().matches("replace%") and
|
||||
(
|
||||
if this.getParameterType(0).(PrimitiveType).getName() = "int"
|
||||
then fromArg = 2
|
||||
else fromArg = 1
|
||||
)
|
||||
or
|
||||
this.consumesTaintFromAllArgs() and fromArg in [0 .. this.getNumberOfParameters() - 1]
|
||||
)
|
||||
}
|
||||
|
||||
override predicate returnsTaintFrom(int arg) { this instanceof Constructor and arg = 0 }
|
||||
}
|
||||
|
||||
/**
|
||||
* An Apache Commons Lang `StrBuilder` method that returns taint from the `StrBuilder`.
|
||||
*/
|
||||
private class ApacheStrBuilderTaintGetter extends ApacheStrBuilderCallable, TaintPreservingCallable {
|
||||
ApacheStrBuilderTaintGetter() {
|
||||
// Taint getters:
|
||||
this.hasName([
|
||||
"asReader", "asTokenizer", "build", "getChars", "leftString", "midString", "rightString",
|
||||
"subSequence", "substring", "toCharArray", "toString", "toStringBuffer", "toStringBuilder"
|
||||
])
|
||||
or
|
||||
// Fluent methods that return an alias of `this`:
|
||||
this.getReturnType() = this.getDeclaringType()
|
||||
}
|
||||
|
||||
override predicate returnsTaintFrom(int arg) { arg = -1 }
|
||||
}
|
||||
|
||||
/**
|
||||
* An Apache Commons Lang `StrBuilder` method that writes taint from the `StrBuilder` to some parameter.
|
||||
*/
|
||||
private class ApacheStrBuilderTaintWriter extends ApacheStrBuilderCallable, TaintPreservingCallable {
|
||||
ApacheStrBuilderTaintWriter() { this.hasName(["appendTo", "getChars"]) }
|
||||
|
||||
override predicate transfersTaint(int fromArg, int toArg) {
|
||||
fromArg = -1 and
|
||||
// appendTo(Readable) and getChars(char[])
|
||||
if this.getNumberOfParameters() = 1
|
||||
then toArg = 0
|
||||
else
|
||||
// getChars(int, int, char[], int)
|
||||
toArg = 2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
public class A {
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
public class A {
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
edges
|
||||
| SensitiveGetQuery2.java:12:13:12:37 | getParameterMap(...) : Map | SensitiveGetQuery2.java:14:21:14:48 | (...)... : Object |
|
||||
| SensitiveGetQuery2.java:14:21:14:48 | (...)... : Object | SensitiveGetQuery2.java:15:29:15:36 | password |
|
||||
| SensitiveGetQuery2.java:14:21:14:48 | (...)... : Object | SensitiveGetQuery2.java:15:29:15:36 | password : Object |
|
||||
| SensitiveGetQuery2.java:15:29:15:36 | password : Object | SensitiveGetQuery2.java:18:40:18:54 | password : Object |
|
||||
| SensitiveGetQuery2.java:18:40:18:54 | password : Object | SensitiveGetQuery2.java:19:61:19:68 | password |
|
||||
| SensitiveGetQuery3.java:12:21:12:60 | getRequestParameter(...) : String | SensitiveGetQuery3.java:13:57:13:64 | password |
|
||||
| SensitiveGetQuery3.java:17:10:17:40 | getParameter(...) : String | SensitiveGetQuery3.java:12:21:12:60 | getRequestParameter(...) : String |
|
||||
| SensitiveGetQuery4.java:14:24:14:66 | getRequestParameter(...) : String | SensitiveGetQuery4.java:16:37:16:47 | accessToken |
|
||||
| SensitiveGetQuery4.java:20:10:20:40 | getParameter(...) : String | SensitiveGetQuery4.java:14:24:14:66 | getRequestParameter(...) : String |
|
||||
| SensitiveGetQuery.java:12:21:12:52 | getParameter(...) : String | SensitiveGetQuery.java:14:29:14:36 | password |
|
||||
| SensitiveGetQuery.java:12:21:12:52 | getParameter(...) : String | SensitiveGetQuery.java:14:29:14:36 | password : String |
|
||||
| SensitiveGetQuery.java:14:29:14:36 | password : String | SensitiveGetQuery.java:17:40:17:54 | password : String |
|
||||
| SensitiveGetQuery.java:17:40:17:54 | password : String | SensitiveGetQuery.java:18:61:18:68 | password |
|
||||
nodes
|
||||
| SensitiveGetQuery2.java:12:13:12:37 | getParameterMap(...) : Map | semmle.label | getParameterMap(...) : Map |
|
||||
| SensitiveGetQuery2.java:14:21:14:48 | (...)... : Object | semmle.label | (...)... : Object |
|
||||
| SensitiveGetQuery2.java:15:29:15:36 | password | semmle.label | password |
|
||||
| SensitiveGetQuery2.java:15:29:15:36 | password : Object | semmle.label | password : Object |
|
||||
| SensitiveGetQuery2.java:18:40:18:54 | password : Object | semmle.label | password : Object |
|
||||
| SensitiveGetQuery2.java:19:61:19:68 | password | semmle.label | password |
|
||||
| SensitiveGetQuery3.java:12:21:12:60 | getRequestParameter(...) : String | semmle.label | getRequestParameter(...) : String |
|
||||
| SensitiveGetQuery3.java:13:57:13:64 | password | semmle.label | password |
|
||||
| SensitiveGetQuery3.java:17:10:17:40 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| SensitiveGetQuery4.java:14:24:14:66 | getRequestParameter(...) : String | semmle.label | getRequestParameter(...) : String |
|
||||
| SensitiveGetQuery4.java:16:37:16:47 | accessToken | semmle.label | accessToken |
|
||||
| SensitiveGetQuery4.java:20:10:20:40 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| SensitiveGetQuery.java:12:21:12:52 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| SensitiveGetQuery.java:14:29:14:36 | password | semmle.label | password |
|
||||
| SensitiveGetQuery.java:14:29:14:36 | password : String | semmle.label | password : String |
|
||||
| SensitiveGetQuery.java:17:40:17:54 | password : String | semmle.label | password : String |
|
||||
| SensitiveGetQuery.java:18:61:18:68 | password | semmle.label | password |
|
||||
#select
|
||||
| SensitiveGetQuery2.java:15:29:15:36 | password | SensitiveGetQuery2.java:12:13:12:37 | getParameterMap(...) : Map | SensitiveGetQuery2.java:15:29:15:36 | password | $@ uses the GET request method to transmit sensitive information. | SensitiveGetQuery2.java:12:13:12:37 | getParameterMap(...) | This request |
|
||||
| SensitiveGetQuery2.java:19:61:19:68 | password | SensitiveGetQuery2.java:12:13:12:37 | getParameterMap(...) : Map | SensitiveGetQuery2.java:19:61:19:68 | password | $@ uses the GET request method to transmit sensitive information. | SensitiveGetQuery2.java:12:13:12:37 | getParameterMap(...) | This request |
|
||||
| SensitiveGetQuery3.java:13:57:13:64 | password | SensitiveGetQuery3.java:17:10:17:40 | getParameter(...) : String | SensitiveGetQuery3.java:13:57:13:64 | password | $@ uses the GET request method to transmit sensitive information. | SensitiveGetQuery3.java:17:10:17:40 | getParameter(...) | This request |
|
||||
| SensitiveGetQuery4.java:16:37:16:47 | accessToken | SensitiveGetQuery4.java:20:10:20:40 | getParameter(...) : String | SensitiveGetQuery4.java:16:37:16:47 | accessToken | $@ uses the GET request method to transmit sensitive information. | SensitiveGetQuery4.java:20:10:20:40 | getParameter(...) | This request |
|
||||
| SensitiveGetQuery.java:14:29:14:36 | password | SensitiveGetQuery.java:12:21:12:52 | getParameter(...) : String | SensitiveGetQuery.java:14:29:14:36 | password | $@ uses the GET request method to transmit sensitive information. | SensitiveGetQuery.java:12:21:12:52 | getParameter(...) | This request |
|
||||
| SensitiveGetQuery.java:18:61:18:68 | password | SensitiveGetQuery.java:12:21:12:52 | getParameter(...) : String | SensitiveGetQuery.java:18:61:18:68 | password | $@ uses the GET request method to transmit sensitive information. | SensitiveGetQuery.java:12:21:12:52 | getParameter(...) | This request |
|
||||
@@ -0,0 +1,26 @@
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
public class SensitiveGetQuery extends HttpServlet {
|
||||
// BAD - Tests retrieving sensitive information through `request.getParameter()` in a GET request.
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
String username = request.getParameter("username");
|
||||
String password = request.getParameter("password");
|
||||
|
||||
processUserInfo(username, password);
|
||||
}
|
||||
|
||||
void processUserInfo(String username, String password) {
|
||||
System.out.println("username = " + username+"; password "+password);
|
||||
}
|
||||
|
||||
// GOOD - Tests retrieving sensitive information through `request.getParameter()` in a POST request.
|
||||
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
String password = request.getParameter("password");
|
||||
System.out.println("password = " + password);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE/CWE-598/SensitiveGetQuery.ql
|
||||
@@ -0,0 +1,29 @@
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
public class SensitiveGetQuery2 extends HttpServlet {
|
||||
// BAD - Tests retrieving sensitive information through `request.getParameterMap()` in a GET request.
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
Map map = request.getParameterMap();
|
||||
String username = (String) map.get("username");
|
||||
String password = (String) map.get("password");
|
||||
processUserInfo(username, password);
|
||||
}
|
||||
|
||||
void processUserInfo(String username, String password) {
|
||||
System.out.println("username = " + username+"; password "+password);
|
||||
}
|
||||
|
||||
// GOOD - Tests retrieving sensitive information through `request.getParameterMap()` in a POST request.
|
||||
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
Map map = request.getParameterMap();
|
||||
String username = (String) map.get("username");
|
||||
String password = (String) map.get("password");
|
||||
processUserInfo(username, password);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
public class SensitiveGetQuery3 extends HttpServlet {
|
||||
// BAD - Tests retrieving sensitive information through a wrapper call in a GET request.
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
String username = getRequestParameter(request, "username");
|
||||
String password = getRequestParameter(request, "password");
|
||||
System.out.println("Username="+username+"; password="+password);
|
||||
}
|
||||
|
||||
String getRequestParameter(HttpServletRequest request, String paramName) {
|
||||
return request.getParameter(paramName);
|
||||
}
|
||||
|
||||
// GOOD - Tests retrieving sensitive information through a wrapper call in a POST request.
|
||||
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
String username = getRequestParameter(request, "username");
|
||||
String password = getRequestParameter(request, "password");
|
||||
System.out.println("Username="+username+"; password="+password);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
public class SensitiveGetQuery4 extends HttpServlet {
|
||||
// BAD - Tests retrieving non-sensitive tokens and sensitive tokens in a GET request.
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
String username = getRequestParameter(request, "username");
|
||||
String token = getRequestParameter(request, "token");
|
||||
String tokenType = getRequestParameter(request, "tokenType");
|
||||
String accessToken = getRequestParameter(request, "accessToken");
|
||||
System.out.println("Username="+username+"; token="+token+"; tokenType="+tokenType);
|
||||
System.out.println("AccessToken="+accessToken);
|
||||
}
|
||||
|
||||
String getRequestParameter(HttpServletRequest request, String paramName) {
|
||||
return request.getParameter(paramName);
|
||||
}
|
||||
|
||||
// GOOD - Tests retrieving non-sensitive tokens and sensitive tokens in a POST request.
|
||||
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
String username = getRequestParameter(request, "username");
|
||||
String token = getRequestParameter(request, "token");
|
||||
String tokenType = getRequestParameter(request, "tokenType");
|
||||
String accessToken = getRequestParameter(request, "accessToken");
|
||||
System.out.println("Username="+username+"; token="+token+"; tokenType="+tokenType);
|
||||
System.out.println("AccessToken="+accessToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4
|
||||
62
java/ql/test/library-tests/dataflow/external-models/A.java
Normal file
62
java/ql/test/library-tests/dataflow/external-models/A.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package my.qltest;
|
||||
|
||||
public class A {
|
||||
void foo() {
|
||||
Object x;
|
||||
x = src1();
|
||||
x = src1("");
|
||||
|
||||
Sub sub = new Sub();
|
||||
x = sub.src2();
|
||||
x = sub.src3();
|
||||
|
||||
srcArg(x);
|
||||
|
||||
Handler h = srcparam1 -> { };
|
||||
|
||||
Handler h2 = new Handler() {
|
||||
@Override public void handle(Object srcparam2) { }
|
||||
};
|
||||
|
||||
x = taggedSrcMethod();
|
||||
x = taggedSrcField;
|
||||
|
||||
x = srcTwoArg("", "");
|
||||
}
|
||||
|
||||
@Tag
|
||||
void tagged1(Object taggedMethodParam) {
|
||||
}
|
||||
|
||||
void tagged2(@Tag Object taggedSrcParam) {
|
||||
}
|
||||
|
||||
Object src1() { return null; }
|
||||
|
||||
Object src1(String s) { return null; }
|
||||
|
||||
Object src2() { return null; }
|
||||
|
||||
Object src3() { return null; }
|
||||
|
||||
static class Sub extends A {
|
||||
// inherit src2
|
||||
@Override Object src3() { return null; }
|
||||
}
|
||||
|
||||
void srcArg(Object src) { }
|
||||
|
||||
interface Handler {
|
||||
void handle(Object src);
|
||||
}
|
||||
|
||||
@interface Tag { }
|
||||
|
||||
@Tag
|
||||
Object taggedSrcMethod() { return null; }
|
||||
|
||||
@Tag
|
||||
Object taggedSrcField;
|
||||
|
||||
Object srcTwoArg(String s1, String s2) { return null; }
|
||||
}
|
||||
35
java/ql/test/library-tests/dataflow/external-models/B.java
Normal file
35
java/ql/test/library-tests/dataflow/external-models/B.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package my.qltest;
|
||||
|
||||
public class B {
|
||||
void foo() {
|
||||
Object arg1 = new Object();
|
||||
sink1(arg1);
|
||||
|
||||
Object argToTagged = new Object();
|
||||
taggedSinkMethod(argToTagged);
|
||||
|
||||
Object fieldWrite = new Object();
|
||||
taggedField = fieldWrite;
|
||||
}
|
||||
|
||||
Object sinkMethod() {
|
||||
Object res = new Object();
|
||||
return res;
|
||||
}
|
||||
|
||||
@Tag
|
||||
Object taggedSinkMethod() {
|
||||
Object resTag = new Object();
|
||||
return resTag;
|
||||
}
|
||||
|
||||
void sink1(Object x) { }
|
||||
|
||||
@interface Tag { }
|
||||
|
||||
@Tag
|
||||
void taggedSinkMethod(Object x) { }
|
||||
|
||||
@Tag
|
||||
Object taggedField;
|
||||
}
|
||||
36
java/ql/test/library-tests/dataflow/external-models/C.java
Normal file
36
java/ql/test/library-tests/dataflow/external-models/C.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package my.qltest;
|
||||
|
||||
public class C {
|
||||
void foo() {
|
||||
Object arg1 = new Object();
|
||||
stepArgRes(arg1);
|
||||
|
||||
Object argIn1 = new Object();
|
||||
Object argOut1 = new Object();
|
||||
stepArgArg(argIn1, argOut1);
|
||||
Object argIn2 = new Object();
|
||||
Object argOut2 = new Object();
|
||||
stepArgArg(argIn2, argOut2);
|
||||
|
||||
Object arg2 = new Object();
|
||||
stepArgQual(arg2);
|
||||
Object arg3 = new Object();
|
||||
this.stepArgQual(arg3);
|
||||
|
||||
this.stepQualRes();
|
||||
stepQualRes();
|
||||
|
||||
Object argOut = new Object();
|
||||
stepQualArg(argOut);
|
||||
}
|
||||
|
||||
Object stepArgRes(Object x) { return null; }
|
||||
|
||||
void stepArgArg(Object in, Object out) { }
|
||||
|
||||
void stepArgQual(Object x) { }
|
||||
|
||||
Object stepQualRes() { return null; }
|
||||
|
||||
void stepQualArg(Object out) { }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
invalidModelRow
|
||||
#select
|
||||
| B.java:6:11:6:14 | arg1 | qltest |
|
||||
| B.java:9:5:9:33 | this <.method> | qltest-arg |
|
||||
| B.java:9:22:9:32 | argToTagged | qltest-arg |
|
||||
| B.java:12:19:12:28 | fieldWrite | qltest-nospec |
|
||||
| B.java:17:12:17:14 | res | qltest |
|
||||
| B.java:23:12:23:17 | resTag | qltest-retval |
|
||||
22
java/ql/test/library-tests/dataflow/external-models/sinks.ql
Normal file
22
java/ql/test/library-tests/dataflow/external-models/sinks.ql
Normal file
@@ -0,0 +1,22 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.ExternalFlow
|
||||
import CsvValidation
|
||||
|
||||
class SinkModelTest extends SinkModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
//"package;type;overrides;name;signature;ext;spec;kind",
|
||||
"my.qltest;B;false;sink1;(Object);;Argument[0];qltest",
|
||||
"my.qltest;B;false;sinkMethod;();;ReturnValue;qltest",
|
||||
"my.qltest;B$Tag;false;;;Annotated;ReturnValue;qltest-retval",
|
||||
"my.qltest;B$Tag;false;;;Annotated;Argument;qltest-arg",
|
||||
"my.qltest;B$Tag;false;;;Annotated;;qltest-nospec"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::Node node, string kind
|
||||
where sinkNode(node, kind)
|
||||
select node, kind
|
||||
@@ -0,0 +1,24 @@
|
||||
invalidModelRow
|
||||
#select
|
||||
| A.java:6:9:6:14 | src1(...) | qltest |
|
||||
| A.java:6:9:6:14 | src1(...) | qltest-all-overloads |
|
||||
| A.java:7:9:7:16 | src1(...) | qltest |
|
||||
| A.java:7:9:7:16 | src1(...) | qltest-all-overloads |
|
||||
| A.java:7:9:7:16 | src1(...) | qltest-alt |
|
||||
| A.java:10:9:10:18 | src2(...) | qltest |
|
||||
| A.java:10:9:10:18 | src2(...) | qltest-w-subtypes |
|
||||
| A.java:11:9:11:18 | src3(...) | qltest-w-subtypes |
|
||||
| A.java:13:5:13:13 | this <.method> [post update] | qltest-argany |
|
||||
| A.java:13:12:13:12 | x [post update] | qltest-argany |
|
||||
| A.java:13:12:13:12 | x [post update] | qltest-argnum |
|
||||
| A.java:15:17:15:25 | srcparam1 | qltest-param-override |
|
||||
| A.java:18:36:18:51 | srcparam2 | qltest-param-override |
|
||||
| A.java:21:9:21:25 | taggedSrcMethod(...) | qltest-retval |
|
||||
| A.java:22:9:22:22 | taggedSrcField | qltest-nospec |
|
||||
| A.java:24:9:24:25 | srcTwoArg(...) | qltest-longsig |
|
||||
| A.java:24:9:24:25 | srcTwoArg(...) | qltest-shortsig |
|
||||
| A.java:28:8:28:14 | parameter this | qltest-param |
|
||||
| A.java:28:16:28:39 | taggedMethodParam | qltest-param |
|
||||
| A.java:31:16:31:41 | taggedSrcParam | qltest-nospec |
|
||||
| A.java:31:16:31:41 | taggedSrcParam | qltest-param |
|
||||
| A.java:56:10:56:24 | parameter this | qltest-param |
|
||||
33
java/ql/test/library-tests/dataflow/external-models/srcs.ql
Normal file
33
java/ql/test/library-tests/dataflow/external-models/srcs.ql
Normal file
@@ -0,0 +1,33 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.ExternalFlow
|
||||
import CsvValidation
|
||||
|
||||
class SourceModelTest extends SourceModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
//"package;type;overrides;name;signature;ext;spec;kind",
|
||||
"my.qltest;A;false;src1;();;ReturnValue;qltest",
|
||||
"my.qltest;A;false;src1;(String);;ReturnValue;qltest",
|
||||
"my.qltest;A;false;src1;(java.lang.String);;ReturnValue;qltest-alt",
|
||||
"my.qltest;A;false;src1;;;ReturnValue;qltest-all-overloads",
|
||||
"my.qltest;A;false;src2;();;ReturnValue;qltest",
|
||||
"my.qltest;A;false;src3;();;ReturnValue;qltest",
|
||||
"my.qltest;A;true;src2;();;ReturnValue;qltest-w-subtypes",
|
||||
"my.qltest;A;true;src3;();;ReturnValue;qltest-w-subtypes",
|
||||
"my.qltest;A;false;srcArg;(Object);;Argument[0];qltest-argnum",
|
||||
"my.qltest;A;false;srcArg;(Object);;Argument;qltest-argany",
|
||||
"my.qltest;A$Handler;true;handle;(Object);;Parameter[0];qltest-param-override",
|
||||
"my.qltest;A$Tag;false;;;Annotated;ReturnValue;qltest-retval",
|
||||
"my.qltest;A$Tag;false;;;Annotated;Parameter;qltest-param",
|
||||
"my.qltest;A$Tag;false;;;Annotated;;qltest-nospec",
|
||||
"my.qltest;A;false;srcTwoArg;(String,String);;ReturnValue;qltest-shortsig",
|
||||
"my.qltest;A;false;srcTwoArg;(java.lang.String,java.lang.String);;ReturnValue;qltest-longsig"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::Node node, string kind
|
||||
where sourceNode(node, kind)
|
||||
select node, kind
|
||||
@@ -0,0 +1,10 @@
|
||||
invalidModelRow
|
||||
#select
|
||||
| C.java:6:16:6:19 | arg1 | C.java:6:5:6:20 | stepArgRes(...) | qltest |
|
||||
| C.java:10:16:10:21 | argIn1 | C.java:10:24:10:30 | argOut1 [post update] | qltest |
|
||||
| C.java:13:16:13:21 | argIn2 | C.java:13:24:13:30 | argOut2 [post update] | qltest |
|
||||
| C.java:16:17:16:20 | arg2 | C.java:16:5:16:21 | this <.method> [post update] | qltest |
|
||||
| C.java:18:22:18:25 | arg3 | C.java:18:5:18:8 | this [post update] | qltest |
|
||||
| C.java:20:5:20:8 | this | C.java:20:5:20:22 | stepQualRes(...) | qltest |
|
||||
| C.java:21:5:21:17 | this <.method> | C.java:21:5:21:17 | stepQualRes(...) | qltest |
|
||||
| C.java:24:5:24:23 | this <.method> | C.java:24:17:24:22 | argOut [post update] | qltest |
|
||||
22
java/ql/test/library-tests/dataflow/external-models/steps.ql
Normal file
22
java/ql/test/library-tests/dataflow/external-models/steps.ql
Normal file
@@ -0,0 +1,22 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.ExternalFlow
|
||||
import CsvValidation
|
||||
|
||||
class SummaryModelTest extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
//"package;type;overrides;name;signature;ext;inputspec;outputspec;kind",
|
||||
"my.qltest;C;false;stepArgRes;(Object);;Argument[0];ReturnValue;qltest",
|
||||
"my.qltest;C;false;stepArgArg;(Object,Object);;Argument[0];Argument[1];qltest",
|
||||
"my.qltest;C;false;stepArgQual;(Object);;Argument[0];Argument[-1];qltest",
|
||||
"my.qltest;C;false;stepQualRes;();;Argument[-1];ReturnValue;qltest",
|
||||
"my.qltest;C;false;stepQualArg;(Object);;Argument[-1];Argument[0];qltest"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::Node node1, DataFlow::Node node2, string kind
|
||||
where summaryStep(node1, node2, kind)
|
||||
select node1, node2, kind
|
||||
@@ -0,0 +1,133 @@
|
||||
import org.apache.commons.lang3.text.StrBuilder;
|
||||
import org.apache.commons.lang3.text.StrMatcher;
|
||||
import org.apache.commons.lang3.text.StrTokenizer;
|
||||
import java.io.StringReader;
|
||||
import java.nio.CharBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
class StrBuilderTest {
|
||||
String taint() { return "tainted"; }
|
||||
|
||||
void sink(Object o) {}
|
||||
|
||||
void test() throws Exception {
|
||||
|
||||
StrBuilder cons1 = new StrBuilder(taint()); sink(cons1.toString()); // $hasTaintFlow=y
|
||||
|
||||
StrBuilder sb1 = new StrBuilder(); sb1.append(taint().toCharArray()); sink(sb1.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb2 = new StrBuilder(); sb2.append(taint().toCharArray(), 0, 0); sink(sb2.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb3 = new StrBuilder(); sb3.append(CharBuffer.wrap(taint().toCharArray())); sink(sb3.toString()); // $ MISSING: hasTaintFlow=y
|
||||
StrBuilder sb4 = new StrBuilder(); sb4.append(CharBuffer.wrap(taint().toCharArray()), 0, 0); sink(sb4.toString()); // $ MISSING: hasTaintFlow=y
|
||||
StrBuilder sb5 = new StrBuilder(); sb5.append((CharSequence)taint()); sink(sb5.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb6 = new StrBuilder(); sb6.append((CharSequence)taint(), 0, 0); sink(sb6.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb7 = new StrBuilder(); sb7.append((Object)taint()); sink(sb7.toString()); // $hasTaintFlow=y
|
||||
{
|
||||
StrBuilder auxsb = new StrBuilder(); auxsb.append(taint());
|
||||
StrBuilder sb8 = new StrBuilder(); sb8.append(auxsb); sink(sb8.toString()); // $hasTaintFlow=y
|
||||
}
|
||||
StrBuilder sb9 = new StrBuilder(); sb9.append(new StringBuffer(taint())); sink(sb9.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb10 = new StrBuilder(); sb10.append(new StringBuffer(taint()), 0, 0); sink(sb10.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb11 = new StrBuilder(); sb11.append(new StringBuilder(taint())); sink(sb11.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb12 = new StrBuilder(); sb12.append(new StringBuilder(taint()), 0, 0); sink(sb12.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb13 = new StrBuilder(); sb13.append(taint()); sink(sb13.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb14 = new StrBuilder(); sb14.append(taint(), 0, 0); sink(sb14.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb15 = new StrBuilder(); sb15.append(taint(), "format", "args"); sink(sb15.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb16 = new StrBuilder(); sb16.append("Format string", taint(), "args"); sink(sb16.toString()); // $hasTaintFlow=y
|
||||
{
|
||||
List<String> taintedList = new ArrayList<>();
|
||||
taintedList.add(taint());
|
||||
StrBuilder sb17 = new StrBuilder(); sb17.appendAll(taintedList); sink(sb17.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb18 = new StrBuilder(); sb18.appendAll(taintedList.iterator()); sink(sb18.toString()); // $hasTaintFlow=y
|
||||
}
|
||||
StrBuilder sb19 = new StrBuilder(); sb19.appendAll("clean", taint()); sink(sb19.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb20 = new StrBuilder(); sb20.appendAll(taint(), "clean"); sink(sb20.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb21 = new StrBuilder(); sb21.appendFixedWidthPadLeft(taint(), 0, ' '); sink(sb21.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb22 = new StrBuilder(); sb22.appendFixedWidthPadRight(taint(), 0, ' '); sink(sb22.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb23 = new StrBuilder(); sb23.appendln(taint().toCharArray()); sink(sb23.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb24 = new StrBuilder(); sb24.appendln(taint().toCharArray(), 0, 0); sink(sb24.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb25 = new StrBuilder(); sb25.appendln((Object)taint()); sink(sb25.toString()); // $hasTaintFlow=y
|
||||
{
|
||||
StrBuilder auxsb = new StrBuilder(); auxsb.appendln(taint());
|
||||
StrBuilder sb26 = new StrBuilder(); sb26.appendln(auxsb); sink(sb26.toString()); // $hasTaintFlow=y
|
||||
}
|
||||
StrBuilder sb27 = new StrBuilder(); sb27.appendln(new StringBuffer(taint())); sink(sb27.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb28 = new StrBuilder(); sb28.appendln(new StringBuffer(taint()), 0, 0); sink(sb28.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb29 = new StrBuilder(); sb29.appendln(new StringBuilder(taint())); sink(sb29.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb30 = new StrBuilder(); sb30.appendln(new StringBuilder(taint()), 0, 0); sink(sb30.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb31 = new StrBuilder(); sb31.appendln(taint()); sink(sb31.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb32 = new StrBuilder(); sb32.appendln(taint(), 0, 0); sink(sb32.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb33 = new StrBuilder(); sb33.appendln(taint(), "format", "args"); sink(sb33.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb34 = new StrBuilder(); sb34.appendln("Format string", taint(), "args"); sink(sb34.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb35 = new StrBuilder(); sb35.appendSeparator(taint()); sink(sb35.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb36 = new StrBuilder(); sb36.appendSeparator(taint(), 0); sink(sb36.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb37 = new StrBuilder(); sb37.appendSeparator(taint(), "default"); sink(sb37.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb38 = new StrBuilder(); sb38.appendSeparator("", taint()); sink(sb38.toString()); // $hasTaintFlow=y
|
||||
{
|
||||
StrBuilder auxsb = new StrBuilder(); auxsb.appendln(taint());
|
||||
StrBuilder sb39 = new StrBuilder(); auxsb.appendTo(sb39); sink(sb39.toString()); // $hasTaintFlow=y
|
||||
}
|
||||
{
|
||||
List<String> taintedList = new ArrayList<>();
|
||||
taintedList.add(taint());
|
||||
StrBuilder sb40 = new StrBuilder(); sb40.appendWithSeparators(taintedList, ", "); sink(sb40.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb41 = new StrBuilder(); sb41.appendWithSeparators(taintedList.iterator(), ", "); sink(sb41.toString()); // $hasTaintFlow=y
|
||||
List<String> untaintedList = new ArrayList<>();
|
||||
StrBuilder sb42 = new StrBuilder(); sb42.appendWithSeparators(untaintedList, taint()); sink(sb42.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb43 = new StrBuilder(); sb43.appendWithSeparators(untaintedList.iterator(), taint()); sink(sb43.toString()); // $hasTaintFlow=y
|
||||
String[] taintedArray = new String[] { taint() };
|
||||
String[] untaintedArray = new String[] {};
|
||||
StrBuilder sb44 = new StrBuilder(); sb44.appendWithSeparators(taintedArray, ", "); sink(sb44.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb45 = new StrBuilder(); sb45.appendWithSeparators(untaintedArray, taint()); sink(sb45.toString()); // $hasTaintFlow=y
|
||||
}
|
||||
{
|
||||
StrBuilder sb46 = new StrBuilder(); sb46.append(taint());
|
||||
char[] target = new char[100];
|
||||
sb46.asReader().read(target);
|
||||
sink(target); // $hasTaintFlow=y
|
||||
}
|
||||
StrBuilder sb47 = new StrBuilder(); sb47.append(taint()); sink(sb47.asTokenizer().next()); // $hasTaintFlow=y
|
||||
StrBuilder sb48 = new StrBuilder(); sb48.append(taint()); sink(sb48.build()); // $hasTaintFlow=y
|
||||
StrBuilder sb49 = new StrBuilder(); sb49.append(taint()); sink(sb49.getChars(null)); // $hasTaintFlow=y
|
||||
{
|
||||
StrBuilder sb50 = new StrBuilder(); sb50.append(taint());
|
||||
char[] target = new char[100];
|
||||
sb50.getChars(target);
|
||||
sink(target); // $hasTaintFlow=y
|
||||
}
|
||||
{
|
||||
StrBuilder sb51 = new StrBuilder(); sb51.append(taint());
|
||||
char[] target = new char[100];
|
||||
sb51.getChars(0, 0, target, 0);
|
||||
sink(target); // $hasTaintFlow=y
|
||||
}
|
||||
StrBuilder sb52 = new StrBuilder(); sb52.insert(0, taint().toCharArray()); sink(sb52.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb53 = new StrBuilder(); sb53.insert(0, taint().toCharArray(), 0, 0); sink(sb53.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb54 = new StrBuilder(); sb54.insert(0, taint()); sink(sb54.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb55 = new StrBuilder(); sb55.insert(0, (Object)taint()); sink(sb55.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb56 = new StrBuilder(); sb56.append(taint()); sink(sb56.leftString(0)); // $hasTaintFlow=y
|
||||
StrBuilder sb57 = new StrBuilder(); sb57.append(taint()); sink(sb57.midString(0, 0)); // $hasTaintFlow=y
|
||||
{
|
||||
StringReader reader = new StringReader(taint());
|
||||
StrBuilder sb58 = new StrBuilder(); sb58.readFrom(reader); sink(sb58.toString()); // $hasTaintFlow=y
|
||||
}
|
||||
StrBuilder sb59 = new StrBuilder(); sb59.replace(0, 0, taint()); sink(sb59.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb60 = new StrBuilder(); sb60.replace(null, taint(), 0, 0, 0); sink(sb60.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb61 = new StrBuilder(); sb61.replaceAll((StrMatcher)null, taint()); sink(sb61.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb62 = new StrBuilder(); sb62.replaceAll("search", taint()); sink(sb62.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb63 = new StrBuilder(); sb63.replaceAll(taint(), "replace"); sink(sb63.toString()); // GOOD (search string doesn't convey taint)
|
||||
StrBuilder sb64 = new StrBuilder(); sb64.replaceFirst((StrMatcher)null, taint()); sink(sb64.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb65 = new StrBuilder(); sb65.replaceFirst("search", taint()); sink(sb65.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb66 = new StrBuilder(); sb66.replaceFirst(taint(), "replace"); sink(sb66.toString()); // GOOD (search string doesn't convey taint)
|
||||
StrBuilder sb67 = new StrBuilder(); sb67.append(taint()); sink(sb67.rightString(0)); // $hasTaintFlow=y
|
||||
StrBuilder sb68 = new StrBuilder(); sb68.append(taint()); sink(sb68.subSequence(0, 0)); // $hasTaintFlow=y
|
||||
StrBuilder sb69 = new StrBuilder(); sb69.append(taint()); sink(sb69.substring(0)); // $hasTaintFlow=y
|
||||
StrBuilder sb70 = new StrBuilder(); sb70.append(taint()); sink(sb70.substring(0, 0)); // $hasTaintFlow=y
|
||||
StrBuilder sb71 = new StrBuilder(); sb71.append(taint()); sink(sb71.toCharArray()); // $hasTaintFlow=y
|
||||
StrBuilder sb72 = new StrBuilder(); sb72.append(taint()); sink(sb72.toCharArray(0, 0)); // $hasTaintFlow=y
|
||||
StrBuilder sb73 = new StrBuilder(); sb73.append(taint()); sink(sb73.toStringBuffer()); // $hasTaintFlow=y
|
||||
StrBuilder sb74 = new StrBuilder(); sb74.append(taint()); sink(sb74.toStringBuilder()); // $hasTaintFlow=y
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
import org.apache.commons.text.StrBuilder;
|
||||
import org.apache.commons.text.StrMatcher;
|
||||
import org.apache.commons.text.StrTokenizer;
|
||||
import java.io.StringReader;
|
||||
import java.nio.CharBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
class StrBuilderTextTest {
|
||||
String taint() { return "tainted"; }
|
||||
|
||||
void sink(Object o) {}
|
||||
|
||||
void test() throws Exception {
|
||||
|
||||
StrBuilder cons1 = new StrBuilder(taint()); sink(cons1.toString()); // $hasTaintFlow=y
|
||||
|
||||
StrBuilder sb1 = new StrBuilder(); sb1.append(taint().toCharArray()); sink(sb1.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb2 = new StrBuilder(); sb2.append(taint().toCharArray(), 0, 0); sink(sb2.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb3 = new StrBuilder(); sb3.append(CharBuffer.wrap(taint().toCharArray())); sink(sb3.toString()); // $ MISSING: hasTaintFlow=y
|
||||
StrBuilder sb4 = new StrBuilder(); sb4.append(CharBuffer.wrap(taint().toCharArray()), 0, 0); sink(sb4.toString()); // $ MISSING: hasTaintFlow=y
|
||||
StrBuilder sb5 = new StrBuilder(); sb5.append((CharSequence)taint()); sink(sb5.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb6 = new StrBuilder(); sb6.append((CharSequence)taint(), 0, 0); sink(sb6.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb7 = new StrBuilder(); sb7.append((Object)taint()); sink(sb7.toString()); // $hasTaintFlow=y
|
||||
{
|
||||
StrBuilder auxsb = new StrBuilder(); auxsb.append(taint());
|
||||
StrBuilder sb8 = new StrBuilder(); sb8.append(auxsb); sink(sb8.toString()); // $hasTaintFlow=y
|
||||
}
|
||||
StrBuilder sb9 = new StrBuilder(); sb9.append(new StringBuffer(taint())); sink(sb9.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb10 = new StrBuilder(); sb10.append(new StringBuffer(taint()), 0, 0); sink(sb10.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb11 = new StrBuilder(); sb11.append(new StringBuilder(taint())); sink(sb11.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb12 = new StrBuilder(); sb12.append(new StringBuilder(taint()), 0, 0); sink(sb12.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb13 = new StrBuilder(); sb13.append(taint()); sink(sb13.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb14 = new StrBuilder(); sb14.append(taint(), 0, 0); sink(sb14.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb15 = new StrBuilder(); sb15.append(taint(), "format", "args"); sink(sb15.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb16 = new StrBuilder(); sb16.append("Format string", taint(), "args"); sink(sb16.toString()); // $hasTaintFlow=y
|
||||
{
|
||||
List<String> taintedList = new ArrayList<>();
|
||||
taintedList.add(taint());
|
||||
StrBuilder sb17 = new StrBuilder(); sb17.appendAll(taintedList); sink(sb17.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb18 = new StrBuilder(); sb18.appendAll(taintedList.iterator()); sink(sb18.toString()); // $hasTaintFlow=y
|
||||
}
|
||||
StrBuilder sb19 = new StrBuilder(); sb19.appendAll("clean", taint()); sink(sb19.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb20 = new StrBuilder(); sb20.appendAll(taint(), "clean"); sink(sb20.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb21 = new StrBuilder(); sb21.appendFixedWidthPadLeft(taint(), 0, ' '); sink(sb21.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb22 = new StrBuilder(); sb22.appendFixedWidthPadRight(taint(), 0, ' '); sink(sb22.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb23 = new StrBuilder(); sb23.appendln(taint().toCharArray()); sink(sb23.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb24 = new StrBuilder(); sb24.appendln(taint().toCharArray(), 0, 0); sink(sb24.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb25 = new StrBuilder(); sb25.appendln((Object)taint()); sink(sb25.toString()); // $hasTaintFlow=y
|
||||
{
|
||||
StrBuilder auxsb = new StrBuilder(); auxsb.appendln(taint());
|
||||
StrBuilder sb26 = new StrBuilder(); sb26.appendln(auxsb); sink(sb26.toString()); // $hasTaintFlow=y
|
||||
}
|
||||
StrBuilder sb27 = new StrBuilder(); sb27.appendln(new StringBuffer(taint())); sink(sb27.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb28 = new StrBuilder(); sb28.appendln(new StringBuffer(taint()), 0, 0); sink(sb28.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb29 = new StrBuilder(); sb29.appendln(new StringBuilder(taint())); sink(sb29.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb30 = new StrBuilder(); sb30.appendln(new StringBuilder(taint()), 0, 0); sink(sb30.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb31 = new StrBuilder(); sb31.appendln(taint()); sink(sb31.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb32 = new StrBuilder(); sb32.appendln(taint(), 0, 0); sink(sb32.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb33 = new StrBuilder(); sb33.appendln(taint(), "format", "args"); sink(sb33.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb34 = new StrBuilder(); sb34.appendln("Format string", taint(), "args"); sink(sb34.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb35 = new StrBuilder(); sb35.appendSeparator(taint()); sink(sb35.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb36 = new StrBuilder(); sb36.appendSeparator(taint(), 0); sink(sb36.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb37 = new StrBuilder(); sb37.appendSeparator(taint(), "default"); sink(sb37.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb38 = new StrBuilder(); sb38.appendSeparator("", taint()); sink(sb38.toString()); // $hasTaintFlow=y
|
||||
{
|
||||
StrBuilder auxsb = new StrBuilder(); auxsb.appendln(taint());
|
||||
StrBuilder sb39 = new StrBuilder(); auxsb.appendTo(sb39); sink(sb39.toString()); // $hasTaintFlow=y
|
||||
}
|
||||
{
|
||||
List<String> taintedList = new ArrayList<>();
|
||||
taintedList.add(taint());
|
||||
StrBuilder sb40 = new StrBuilder(); sb40.appendWithSeparators(taintedList, ", "); sink(sb40.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb41 = new StrBuilder(); sb41.appendWithSeparators(taintedList.iterator(), ", "); sink(sb41.toString()); // $hasTaintFlow=y
|
||||
List<String> untaintedList = new ArrayList<>();
|
||||
StrBuilder sb42 = new StrBuilder(); sb42.appendWithSeparators(untaintedList, taint()); sink(sb42.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb43 = new StrBuilder(); sb43.appendWithSeparators(untaintedList.iterator(), taint()); sink(sb43.toString()); // $hasTaintFlow=y
|
||||
String[] taintedArray = new String[] { taint() };
|
||||
String[] untaintedArray = new String[] {};
|
||||
StrBuilder sb44 = new StrBuilder(); sb44.appendWithSeparators(taintedArray, ", "); sink(sb44.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb45 = new StrBuilder(); sb45.appendWithSeparators(untaintedArray, taint()); sink(sb45.toString()); // $hasTaintFlow=y
|
||||
}
|
||||
{
|
||||
StrBuilder sb46 = new StrBuilder(); sb46.append(taint());
|
||||
char[] target = new char[100];
|
||||
sb46.asReader().read(target);
|
||||
sink(target); // $hasTaintFlow=y
|
||||
}
|
||||
StrBuilder sb47 = new StrBuilder(); sb47.append(taint()); sink(sb47.asTokenizer().next()); // $hasTaintFlow=y
|
||||
StrBuilder sb48 = new StrBuilder(); sb48.append(taint()); sink(sb48.build()); // $hasTaintFlow=y
|
||||
StrBuilder sb49 = new StrBuilder(); sb49.append(taint()); sink(sb49.getChars(null)); // $hasTaintFlow=y
|
||||
{
|
||||
StrBuilder sb50 = new StrBuilder(); sb50.append(taint());
|
||||
char[] target = new char[100];
|
||||
sb50.getChars(target);
|
||||
sink(target); // $hasTaintFlow=y
|
||||
}
|
||||
{
|
||||
StrBuilder sb51 = new StrBuilder(); sb51.append(taint());
|
||||
char[] target = new char[100];
|
||||
sb51.getChars(0, 0, target, 0);
|
||||
sink(target); // $hasTaintFlow=y
|
||||
}
|
||||
StrBuilder sb52 = new StrBuilder(); sb52.insert(0, taint().toCharArray()); sink(sb52.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb53 = new StrBuilder(); sb53.insert(0, taint().toCharArray(), 0, 0); sink(sb53.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb54 = new StrBuilder(); sb54.insert(0, taint()); sink(sb54.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb55 = new StrBuilder(); sb55.insert(0, (Object)taint()); sink(sb55.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb56 = new StrBuilder(); sb56.append(taint()); sink(sb56.leftString(0)); // $hasTaintFlow=y
|
||||
StrBuilder sb57 = new StrBuilder(); sb57.append(taint()); sink(sb57.midString(0, 0)); // $hasTaintFlow=y
|
||||
{
|
||||
StringReader reader = new StringReader(taint());
|
||||
StrBuilder sb58 = new StrBuilder(); sb58.readFrom(reader); sink(sb58.toString()); // $hasTaintFlow=y
|
||||
}
|
||||
StrBuilder sb59 = new StrBuilder(); sb59.replace(0, 0, taint()); sink(sb59.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb60 = new StrBuilder(); sb60.replace(null, taint(), 0, 0, 0); sink(sb60.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb61 = new StrBuilder(); sb61.replaceAll((StrMatcher)null, taint()); sink(sb61.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb62 = new StrBuilder(); sb62.replaceAll("search", taint()); sink(sb62.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb63 = new StrBuilder(); sb63.replaceAll(taint(), "replace"); sink(sb63.toString()); // GOOD (search string doesn't convey taint)
|
||||
StrBuilder sb64 = new StrBuilder(); sb64.replaceFirst((StrMatcher)null, taint()); sink(sb64.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb65 = new StrBuilder(); sb65.replaceFirst("search", taint()); sink(sb65.toString()); // $hasTaintFlow=y
|
||||
StrBuilder sb66 = new StrBuilder(); sb66.replaceFirst(taint(), "replace"); sink(sb66.toString()); // GOOD (search string doesn't convey taint)
|
||||
StrBuilder sb67 = new StrBuilder(); sb67.append(taint()); sink(sb67.rightString(0)); // $hasTaintFlow=y
|
||||
StrBuilder sb68 = new StrBuilder(); sb68.append(taint()); sink(sb68.subSequence(0, 0)); // $hasTaintFlow=y
|
||||
StrBuilder sb69 = new StrBuilder(); sb69.append(taint()); sink(sb69.substring(0)); // $hasTaintFlow=y
|
||||
StrBuilder sb70 = new StrBuilder(); sb70.append(taint()); sink(sb70.substring(0, 0)); // $hasTaintFlow=y
|
||||
StrBuilder sb71 = new StrBuilder(); sb71.append(taint()); sink(sb71.toCharArray()); // $hasTaintFlow=y
|
||||
StrBuilder sb72 = new StrBuilder(); sb72.append(taint()); sink(sb72.toCharArray(0, 0)); // $hasTaintFlow=y
|
||||
StrBuilder sb73 = new StrBuilder(); sb73.append(taint()); sink(sb73.toStringBuffer()); // $hasTaintFlow=y
|
||||
StrBuilder sb74 = new StrBuilder(); sb74.append(taint()); sink(sb74.toStringBuilder()); // $hasTaintFlow=y
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
import org.apache.commons.text.TextStringBuilder;
|
||||
import org.apache.commons.text.matcher.StringMatcher;
|
||||
import org.apache.commons.text.StringTokenizer;
|
||||
import java.io.StringReader;
|
||||
import java.nio.CharBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
class TextStringBuilderTest {
|
||||
String taint() { return "tainted"; }
|
||||
|
||||
void sink(Object o) {}
|
||||
|
||||
void test() throws Exception {
|
||||
|
||||
TextStringBuilder cons1 = new TextStringBuilder(taint()); sink(cons1.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder cons2 = new TextStringBuilder((CharSequence)taint()); sink(cons2.toString()); // $hasTaintFlow=y
|
||||
|
||||
TextStringBuilder sb1 = new TextStringBuilder(); sb1.append(taint().toCharArray()); sink(sb1.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb2 = new TextStringBuilder(); sb2.append(taint().toCharArray(), 0, 0); sink(sb2.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb3 = new TextStringBuilder(); sb3.append(CharBuffer.wrap(taint().toCharArray())); sink(sb3.toString()); // $ MISSING: hasTaintFlow=y
|
||||
TextStringBuilder sb4 = new TextStringBuilder(); sb4.append(CharBuffer.wrap(taint().toCharArray()), 0, 0); sink(sb4.toString()); // $ MISSING: hasTaintFlow=y
|
||||
TextStringBuilder sb5 = new TextStringBuilder(); sb5.append((CharSequence)taint()); sink(sb5.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb6 = new TextStringBuilder(); sb6.append((CharSequence)taint(), 0, 0); sink(sb6.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb7 = new TextStringBuilder(); sb7.append((Object)taint()); sink(sb7.toString()); // $hasTaintFlow=y
|
||||
{
|
||||
TextStringBuilder auxsb = new TextStringBuilder(); auxsb.append(taint());
|
||||
TextStringBuilder sb8 = new TextStringBuilder(); sb8.append(auxsb); sink(sb8.toString()); // $hasTaintFlow=y
|
||||
}
|
||||
TextStringBuilder sb9 = new TextStringBuilder(); sb9.append(new StringBuffer(taint())); sink(sb9.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb10 = new TextStringBuilder(); sb10.append(new StringBuffer(taint()), 0, 0); sink(sb10.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb11 = new TextStringBuilder(); sb11.append(new StringBuilder(taint())); sink(sb11.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb12 = new TextStringBuilder(); sb12.append(new StringBuilder(taint()), 0, 0); sink(sb12.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb13 = new TextStringBuilder(); sb13.append(taint()); sink(sb13.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb14 = new TextStringBuilder(); sb14.append(taint(), 0, 0); sink(sb14.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb15 = new TextStringBuilder(); sb15.append(taint(), "format", "args"); sink(sb15.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb16 = new TextStringBuilder(); sb16.append("Format string", taint(), "args"); sink(sb16.toString()); // $hasTaintFlow=y
|
||||
{
|
||||
List<String> taintedList = new ArrayList<>();
|
||||
taintedList.add(taint());
|
||||
TextStringBuilder sb17 = new TextStringBuilder(); sb17.appendAll(taintedList); sink(sb17.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb18 = new TextStringBuilder(); sb18.appendAll(taintedList.iterator()); sink(sb18.toString()); // $hasTaintFlow=y
|
||||
}
|
||||
TextStringBuilder sb19 = new TextStringBuilder(); sb19.appendAll("clean", taint()); sink(sb19.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb20 = new TextStringBuilder(); sb20.appendAll(taint(), "clean"); sink(sb20.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb21 = new TextStringBuilder(); sb21.appendFixedWidthPadLeft(taint(), 0, ' '); sink(sb21.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb22 = new TextStringBuilder(); sb22.appendFixedWidthPadRight(taint(), 0, ' '); sink(sb22.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb23 = new TextStringBuilder(); sb23.appendln(taint().toCharArray()); sink(sb23.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb24 = new TextStringBuilder(); sb24.appendln(taint().toCharArray(), 0, 0); sink(sb24.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb25 = new TextStringBuilder(); sb25.appendln((Object)taint()); sink(sb25.toString()); // $hasTaintFlow=y
|
||||
{
|
||||
TextStringBuilder auxsb = new TextStringBuilder(); auxsb.appendln(taint());
|
||||
TextStringBuilder sb26 = new TextStringBuilder(); sb26.appendln(auxsb); sink(sb26.toString()); // $hasTaintFlow=y
|
||||
}
|
||||
TextStringBuilder sb27 = new TextStringBuilder(); sb27.appendln(new StringBuffer(taint())); sink(sb27.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb28 = new TextStringBuilder(); sb28.appendln(new StringBuffer(taint()), 0, 0); sink(sb28.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb29 = new TextStringBuilder(); sb29.appendln(new StringBuilder(taint())); sink(sb29.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb30 = new TextStringBuilder(); sb30.appendln(new StringBuilder(taint()), 0, 0); sink(sb30.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb31 = new TextStringBuilder(); sb31.appendln(taint()); sink(sb31.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb32 = new TextStringBuilder(); sb32.appendln(taint(), 0, 0); sink(sb32.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb33 = new TextStringBuilder(); sb33.appendln(taint(), "format", "args"); sink(sb33.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb34 = new TextStringBuilder(); sb34.appendln("Format string", taint(), "args"); sink(sb34.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb35 = new TextStringBuilder(); sb35.appendSeparator(taint()); sink(sb35.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb36 = new TextStringBuilder(); sb36.appendSeparator(taint(), 0); sink(sb36.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb37 = new TextStringBuilder(); sb37.appendSeparator(taint(), "default"); sink(sb37.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb38 = new TextStringBuilder(); sb38.appendSeparator("", taint()); sink(sb38.toString()); // $hasTaintFlow=y
|
||||
{
|
||||
TextStringBuilder auxsb = new TextStringBuilder(); auxsb.appendln(taint());
|
||||
TextStringBuilder sb39 = new TextStringBuilder(); auxsb.appendTo(sb39); sink(sb39.toString()); // $hasTaintFlow=y
|
||||
}
|
||||
{
|
||||
List<String> taintedList = new ArrayList<>();
|
||||
taintedList.add(taint());
|
||||
TextStringBuilder sb40 = new TextStringBuilder(); sb40.appendWithSeparators(taintedList, ", "); sink(sb40.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb41 = new TextStringBuilder(); sb41.appendWithSeparators(taintedList.iterator(), ", "); sink(sb41.toString()); // $hasTaintFlow=y
|
||||
List<String> untaintedList = new ArrayList<>();
|
||||
TextStringBuilder sb42 = new TextStringBuilder(); sb42.appendWithSeparators(untaintedList, taint()); sink(sb42.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb43 = new TextStringBuilder(); sb43.appendWithSeparators(untaintedList.iterator(), taint()); sink(sb43.toString()); // $hasTaintFlow=y
|
||||
String[] taintedArray = new String[] { taint() };
|
||||
String[] untaintedArray = new String[] {};
|
||||
TextStringBuilder sb44 = new TextStringBuilder(); sb44.appendWithSeparators(taintedArray, ", "); sink(sb44.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb45 = new TextStringBuilder(); sb45.appendWithSeparators(untaintedArray, taint()); sink(sb45.toString()); // $hasTaintFlow=y
|
||||
}
|
||||
{
|
||||
TextStringBuilder sb46 = new TextStringBuilder(); sb46.append(taint());
|
||||
char[] target = new char[100];
|
||||
sb46.asReader().read(target);
|
||||
sink(target); // $hasTaintFlow=y
|
||||
}
|
||||
TextStringBuilder sb47 = new TextStringBuilder(); sb47.append(taint()); sink(sb47.asTokenizer().next()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb48 = new TextStringBuilder(); sb48.append(taint()); sink(sb48.build()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb49 = new TextStringBuilder(); sb49.append(taint()); sink(sb49.getChars(null)); // $hasTaintFlow=y
|
||||
{
|
||||
TextStringBuilder sb50 = new TextStringBuilder(); sb50.append(taint());
|
||||
char[] target = new char[100];
|
||||
sb50.getChars(target);
|
||||
sink(target); // $hasTaintFlow=y
|
||||
}
|
||||
{
|
||||
TextStringBuilder sb51 = new TextStringBuilder(); sb51.append(taint());
|
||||
char[] target = new char[100];
|
||||
sb51.getChars(0, 0, target, 0);
|
||||
sink(target); // $hasTaintFlow=y
|
||||
}
|
||||
TextStringBuilder sb52 = new TextStringBuilder(); sb52.insert(0, taint().toCharArray()); sink(sb52.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb53 = new TextStringBuilder(); sb53.insert(0, taint().toCharArray(), 0, 0); sink(sb53.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb54 = new TextStringBuilder(); sb54.insert(0, taint()); sink(sb54.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb55 = new TextStringBuilder(); sb55.insert(0, (Object)taint()); sink(sb55.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb56 = new TextStringBuilder(); sb56.append(taint()); sink(sb56.leftString(0)); // $hasTaintFlow=y
|
||||
TextStringBuilder sb57 = new TextStringBuilder(); sb57.append(taint()); sink(sb57.midString(0, 0)); // $hasTaintFlow=y
|
||||
{
|
||||
StringReader reader = new StringReader(taint());
|
||||
TextStringBuilder sb58 = new TextStringBuilder(); sb58.readFrom(reader); sink(sb58.toString()); // $hasTaintFlow=y
|
||||
}
|
||||
TextStringBuilder sb59 = new TextStringBuilder(); sb59.replace(0, 0, taint()); sink(sb59.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb60 = new TextStringBuilder(); sb60.replace(null, taint(), 0, 0, 0); sink(sb60.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb61 = new TextStringBuilder(); sb61.replaceAll((StringMatcher)null, taint()); sink(sb61.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb62 = new TextStringBuilder(); sb62.replaceAll("search", taint()); sink(sb62.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb63 = new TextStringBuilder(); sb63.replaceAll(taint(), "replace"); sink(sb63.toString()); // GOOD (search string doesn't convey taint)
|
||||
TextStringBuilder sb64 = new TextStringBuilder(); sb64.replaceFirst((StringMatcher)null, taint()); sink(sb64.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb65 = new TextStringBuilder(); sb65.replaceFirst("search", taint()); sink(sb65.toString()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb66 = new TextStringBuilder(); sb66.replaceFirst(taint(), "replace"); sink(sb66.toString()); // GOOD (search string doesn't convey taint)
|
||||
TextStringBuilder sb67 = new TextStringBuilder(); sb67.append(taint()); sink(sb67.rightString(0)); // $hasTaintFlow=y
|
||||
TextStringBuilder sb68 = new TextStringBuilder(); sb68.append(taint()); sink(sb68.subSequence(0, 0)); // $hasTaintFlow=y
|
||||
TextStringBuilder sb69 = new TextStringBuilder(); sb69.append(taint()); sink(sb69.substring(0)); // $hasTaintFlow=y
|
||||
TextStringBuilder sb70 = new TextStringBuilder(); sb70.append(taint()); sink(sb70.substring(0, 0)); // $hasTaintFlow=y
|
||||
TextStringBuilder sb71 = new TextStringBuilder(); sb71.append(taint()); sink(sb71.toCharArray()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb72 = new TextStringBuilder(); sb72.append(taint()); sink(sb72.toCharArray(0, 0)); // $hasTaintFlow=y
|
||||
TextStringBuilder sb73 = new TextStringBuilder(); sb73.append(taint()); sink(sb73.toStringBuffer()); // $hasTaintFlow=y
|
||||
TextStringBuilder sb74 = new TextStringBuilder(); sb74.append(taint()); sink(sb74.toStringBuilder()); // $hasTaintFlow=y
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/apache-commons-lang3-3.7
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/apache-commons-lang3-3.7:${testdir}/../../../stubs/apache-commons-text-1.9
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.builder;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The Builder interface is designed to designate a class as a <em>builder</em>
|
||||
* object in the Builder design pattern. Builders are capable of creating and
|
||||
* configuring objects or results that normally take multiple steps to construct
|
||||
* or are very complex to derive.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The builder interface defines a single method, {@link #build()}, that
|
||||
* classes must implement. The result of this method should be the final
|
||||
* configured object or result after all building operations are performed.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* It is a recommended practice that the methods supplied to configure the
|
||||
* object or result being built return a reference to {@code this} so that
|
||||
* method calls can be chained together.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Example Builder:
|
||||
* <pre><code>
|
||||
* class FontBuilder implements Builder<Font> {
|
||||
* private Font font;
|
||||
*
|
||||
* public FontBuilder(String fontName) {
|
||||
* this.font = new Font(fontName, Font.PLAIN, 12);
|
||||
* }
|
||||
*
|
||||
* public FontBuilder bold() {
|
||||
* this.font = this.font.deriveFont(Font.BOLD);
|
||||
* return this; // Reference returned so calls can be chained
|
||||
* }
|
||||
*
|
||||
* public FontBuilder size(float pointSize) {
|
||||
* this.font = this.font.deriveFont(pointSize);
|
||||
* return this; // Reference returned so calls can be chained
|
||||
* }
|
||||
*
|
||||
* // Other Font construction methods
|
||||
*
|
||||
* public Font build() {
|
||||
* return this.font;
|
||||
* }
|
||||
* }
|
||||
* </code></pre>
|
||||
*
|
||||
* Example Builder Usage:
|
||||
* <pre><code>
|
||||
* Font bold14ptSansSerifFont = new FontBuilder(Font.SANS_SERIF).bold()
|
||||
* .size(14.0f)
|
||||
* .build();
|
||||
* </code></pre>
|
||||
*
|
||||
*
|
||||
* @param <T> the type of object that the builder will construct or compute.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface Builder<T> {
|
||||
T build();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,614 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.text;
|
||||
|
||||
import org.apache.commons.lang3.builder.Builder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Serializable;
|
||||
import java.io.Writer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class StrBuilder implements CharSequence, Appendable, Serializable, Builder<String> {
|
||||
public StrBuilder() {
|
||||
}
|
||||
|
||||
public StrBuilder(int initialCapacity) {
|
||||
}
|
||||
|
||||
public StrBuilder(final String str) {
|
||||
}
|
||||
|
||||
public String getNewLineText() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder setNewLineText(final String newLine) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getNullText() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder setNullText(String nullText) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public StrBuilder setLength(final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int capacity() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public StrBuilder ensureCapacity(final int capacity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder minimizeCapacity() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public StrBuilder clear() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(final int index) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public StrBuilder setCharAt(final int index, final char ch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder deleteCharAt(final int index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public char[] toCharArray() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public char[] toCharArray(final int startIndex, int endIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public char[] getChars(char[] destination) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void getChars(final int startIndex, final int endIndex, final char destination[], final int destinationIndex) {
|
||||
}
|
||||
|
||||
public int readFrom(final Readable readable) throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public StrBuilder appendNewLine() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendNull() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final Object obj) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StrBuilder append(final CharSequence seq) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StrBuilder append(final CharSequence seq, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final String str, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final String format, final Object... objs) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final CharBuffer buf) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final CharBuffer buf, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final StringBuffer str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final StringBuffer str, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final StringBuilder str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final StringBuilder str, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final StrBuilder str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final StrBuilder str, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final char[] chars) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final char[] chars, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final boolean value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StrBuilder append(final char ch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final int value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final long value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final float value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final double value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final Object obj) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final String str, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final String format, final Object... objs) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final StringBuffer str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final StringBuilder str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final StringBuilder str, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final StringBuffer str, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final StrBuilder str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final StrBuilder str, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final char[] chars) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final char[] chars, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final boolean value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final char ch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final int value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final long value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final float value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final double value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> StrBuilder appendAll(final T... array) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendAll(final Iterable<?> iterable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendAll(final Iterator<?> it) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendWithSeparators(final Object[] array, final String separator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendWithSeparators(final Iterable<?> iterable, final String separator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendWithSeparators(final Iterator<?> it, final String separator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendSeparator(final String separator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendSeparator(final String standard, final String defaultIfEmpty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendSeparator(final char separator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendSeparator(final char standard, final char defaultIfEmpty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendSeparator(final String separator, final int loopIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendSeparator(final char separator, final int loopIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendPadding(final int length, final char padChar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendFixedWidthPadLeft(final Object obj, final int width, final char padChar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendFixedWidthPadLeft(final int value, final int width, final char padChar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendFixedWidthPadRight(final Object obj, final int width, final char padChar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendFixedWidthPadRight(final int value, final int width, final char padChar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(final int index, final Object obj) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(final int index, String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(final int index, final char chars[]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(final int index, final char chars[], final int offset, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(int index, final boolean value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(final int index, final char value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(final int index, final int value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(final int index, final long value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(final int index, final float value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(final int index, final double value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder delete(final int startIndex, int endIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder deleteAll(final char ch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder deleteFirst(final char ch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder deleteAll(final String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder deleteFirst(final String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder deleteAll(final StrMatcher matcher) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder deleteFirst(final StrMatcher matcher) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder replace(final int startIndex, int endIndex, final String replaceStr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder replaceAll(final char search, final char replace) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder replaceFirst(final char search, final char replace) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder replaceAll(final String searchStr, final String replaceStr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder replaceFirst(final String searchStr, final String replaceStr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder replaceAll(final StrMatcher matcher, final String replaceStr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder replaceFirst(final StrMatcher matcher, final String replaceStr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder replace(
|
||||
final StrMatcher matcher, final String replaceStr,
|
||||
final int startIndex, int endIndex, final int replaceCount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder reverse() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder trim() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean startsWith(final String str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean endsWith(final String str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence subSequence(final int startIndex, final int endIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String substring(final int start) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String substring(final int startIndex, int endIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String leftString(final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String rightString(final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String midString(int index, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean contains(final char ch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean contains(final String str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean contains(final StrMatcher matcher) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int indexOf(final char ch) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int indexOf(final char ch, int startIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int indexOf(final String str) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int indexOf(final String str, int startIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int indexOf(final StrMatcher matcher) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int indexOf(final StrMatcher matcher, int startIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int lastIndexOf(final char ch) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int lastIndexOf(final char ch, int startIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int lastIndexOf(final String str) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int lastIndexOf(final String str, int startIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int lastIndexOf(final StrMatcher matcher) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int lastIndexOf(final StrMatcher matcher, int startIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public StrTokenizer asTokenizer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Reader asReader() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Writer asWriter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void appendTo(final Appendable appendable) throws IOException {
|
||||
}
|
||||
|
||||
public boolean equalsIgnoreCase(final StrBuilder other) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean equals(final StrBuilder other) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringBuffer toStringBuffer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringBuilder toStringBuilder() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String build() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.text;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
public abstract class StrMatcher {
|
||||
public static StrMatcher commaMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher tabMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher spaceMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher splitMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher trimMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher singleQuoteMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher doubleQuoteMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher quoteMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher noneMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher charMatcher(final char ch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher charSetMatcher(final char... chars) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher charSetMatcher(final String chars) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher stringMatcher(final String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd);
|
||||
|
||||
public int isMatch(final char[] buffer, final int pos) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.text;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
|
||||
public class StrTokenizer implements ListIterator<String>, Cloneable {
|
||||
public static StrTokenizer getCSVInstance() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrTokenizer getCSVInstance(final String input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrTokenizer getCSVInstance(final char[] input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrTokenizer getTSVInstance() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrTokenizer getTSVInstance(final String input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrTokenizer getTSVInstance(final char[] input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer() {
|
||||
}
|
||||
|
||||
public StrTokenizer(final String input) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final String input, final char delim) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final String input, final String delim) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final String input, final StrMatcher delim) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final String input, final char delim, final char quote) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final String input, final StrMatcher delim, final StrMatcher quote) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final char[] input) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final char[] input, final char delim) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final char[] input, final String delim) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final char[] input, final StrMatcher delim) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final char[] input, final char delim, final char quote) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final char[] input, final StrMatcher delim, final StrMatcher quote) {
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String nextToken() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String previousToken() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String[] getTokenArray() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<String> getTokenList() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer reset() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer reset(final String input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer reset(final char[] input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String next() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nextIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrevious() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String previous() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int previousIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final String obj) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(final String obj) {
|
||||
}
|
||||
|
||||
public StrMatcher getDelimiterMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer setDelimiterMatcher(final StrMatcher delim) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer setDelimiterChar(final char delim) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer setDelimiterString(final String delim) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrMatcher getQuoteMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer setQuoteMatcher(final StrMatcher quote) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer setQuoteChar(final char quote) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrMatcher getIgnoredMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer setIgnoredMatcher(final StrMatcher ignored) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer setIgnoredChar(final char ignored) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrMatcher getTrimmerMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer setTrimmerMatcher(final StrMatcher trimmer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isEmptyTokenAsNull() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public StrTokenizer setEmptyTokenAsNull(final boolean emptyAsNull) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isIgnoreEmptyTokens() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public StrTokenizer setIgnoreEmptyTokens(final boolean ignoreEmptyTokens) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.text;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The Builder interface is designed to designate a class as a <em>builder</em>
|
||||
* object in the Builder design pattern. Builders are capable of creating and
|
||||
* configuring objects or results that normally take multiple steps to construct
|
||||
* or are very complex to derive.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The builder interface defines a single method, {@link #build()}, that
|
||||
* classes must implement. The result of this method should be the final
|
||||
* configured object or result after all building operations are performed.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* It is a recommended practice that the methods supplied to configure the
|
||||
* object or result being built return a reference to {@code this} so that
|
||||
* method calls can be chained together.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Example Builder:
|
||||
* </p>
|
||||
* <pre><code>
|
||||
* class FontBuilder implements Builder<Font> {
|
||||
* private Font font;
|
||||
*
|
||||
* public FontBuilder(String fontName) {
|
||||
* this.font = new Font(fontName, Font.PLAIN, 12);
|
||||
* }
|
||||
*
|
||||
* public FontBuilder bold() {
|
||||
* this.font = this.font.deriveFont(Font.BOLD);
|
||||
* return this; // Reference returned so calls can be chained
|
||||
* }
|
||||
*
|
||||
* public FontBuilder size(float pointSize) {
|
||||
* this.font = this.font.deriveFont(pointSize);
|
||||
* return this; // Reference returned so calls can be chained
|
||||
* }
|
||||
*
|
||||
* // Other Font construction methods
|
||||
*
|
||||
* public Font build() {
|
||||
* return this.font;
|
||||
* }
|
||||
* }
|
||||
* </code></pre>
|
||||
*
|
||||
* Example Builder Usage:
|
||||
* <pre><code>
|
||||
* Font bold14ptSansSerifFont = new FontBuilder(Font.SANS_SERIF).bold()
|
||||
* .size(14.0f)
|
||||
* .build();
|
||||
* </code></pre>
|
||||
*
|
||||
*
|
||||
* @param <T> the type of object that the builder will construct or compute.
|
||||
* @since 1.0
|
||||
*
|
||||
*/
|
||||
public interface Builder<T> {
|
||||
T build();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,619 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.text;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Serializable;
|
||||
import java.io.Writer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class StrBuilder implements CharSequence, Appendable, Serializable, Builder<String> {
|
||||
public StrBuilder() {
|
||||
}
|
||||
|
||||
public StrBuilder(int initialCapacity) {
|
||||
}
|
||||
|
||||
public StrBuilder(final String str) {
|
||||
}
|
||||
|
||||
public StrBuilder append(final boolean value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StrBuilder append(final char ch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final char[] chars) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final char[] chars, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final CharBuffer buf) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final CharBuffer buf, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StrBuilder append(final CharSequence seq) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StrBuilder append(final CharSequence seq, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final double value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final float value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final int value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final long value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final Object obj) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final StrBuilder str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final StrBuilder str, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final String str, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final String format, final Object... objs) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final StringBuffer str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final StringBuffer str, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final StringBuilder str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder append(final StringBuilder str, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendAll(final Iterable<?> iterable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendAll(final Iterator<?> it) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> StrBuilder appendAll(@SuppressWarnings("unchecked") final T... array) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendFixedWidthPadLeft(final int value, final int width, final char padChar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendFixedWidthPadLeft(final Object obj, final int width, final char padChar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendFixedWidthPadRight(final int value, final int width, final char padChar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendFixedWidthPadRight(final Object obj, final int width, final char padChar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final boolean value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final char ch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final char[] chars) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final char[] chars, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final double value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final float value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final int value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final long value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final Object obj) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final StrBuilder str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final StrBuilder str, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final String str, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final String format, final Object... objs) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final StringBuffer str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final StringBuffer str, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final StringBuilder str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendln(final StringBuilder str, final int startIndex, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendNewLine() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendNull() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendPadding(final int length, final char padChar) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendSeparator(final char separator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendSeparator(final char standard, final char defaultIfEmpty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendSeparator(final char separator, final int loopIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendSeparator(final String separator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendSeparator(final String separator, final int loopIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendSeparator(final String standard, final String defaultIfEmpty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void appendTo(final Appendable appendable) throws IOException {
|
||||
}
|
||||
|
||||
public StrBuilder appendWithSeparators(final Iterable<?> iterable, final String separator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendWithSeparators(final Iterator<?> it, final String separator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder appendWithSeparators(final Object[] array, final String separator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Reader asReader() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer asTokenizer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Writer asWriter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String build() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int capacity() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(final int index) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public StrBuilder clear() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean contains(final char ch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean contains(final String str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean contains(final StrMatcher matcher) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public StrBuilder delete(final int startIndex, int endIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder deleteAll(final char ch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder deleteAll(final String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder deleteAll(final StrMatcher matcher) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder deleteCharAt(final int index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder deleteFirst(final char ch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder deleteFirst(final String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder deleteFirst(final StrMatcher matcher) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean endsWith(final String str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public StrBuilder ensureCapacity(final int capacity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean equals(final StrBuilder other) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean equalsIgnoreCase(final StrBuilder other) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public char[] getChars(char[] destination) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void getChars(final int startIndex,
|
||||
final int endIndex,
|
||||
final char[] destination,
|
||||
final int destinationIndex) {
|
||||
}
|
||||
|
||||
public String getNewLineText() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getNullText() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int indexOf(final char ch) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int indexOf(final char ch, int startIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int indexOf(final String str) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int indexOf(final String str, int startIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int indexOf(final StrMatcher matcher) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int indexOf(final StrMatcher matcher, int startIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public StrBuilder insert(int index, final boolean value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(final int index, final char value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(final int index, final char[] chars) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(final int index, final char[] chars, final int offset, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(final int index, final double value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(final int index, final float value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(final int index, final int value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(final int index, final long value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(final int index, final Object obj) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder insert(final int index, String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isNotEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int lastIndexOf(final char ch) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int lastIndexOf(final char ch, int startIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int lastIndexOf(final String str) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int lastIndexOf(final String str, int startIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int lastIndexOf(final StrMatcher matcher) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int lastIndexOf(final StrMatcher matcher, int startIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String leftString(final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String midString(int index, final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder minimizeCapacity() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int readFrom(final Readable readable) throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public StrBuilder replace(final int startIndex, int endIndex, final String replaceStr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder replace(
|
||||
final StrMatcher matcher, final String replaceStr,
|
||||
final int startIndex, int endIndex, final int replaceCount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder replaceAll(final char search, final char replace) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder replaceAll(final String searchStr, final String replaceStr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder replaceAll(final StrMatcher matcher, final String replaceStr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder replaceFirst(final char search, final char replace) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder replaceFirst(final String searchStr, final String replaceStr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder replaceFirst(final StrMatcher matcher, final String replaceStr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder reverse() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String rightString(final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder setCharAt(final int index, final char ch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder setLength(final int length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder setNewLineText(final String newLine) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder setNullText(String nullText) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean startsWith(final String str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence subSequence(final int startIndex, final int endIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String substring(final int start) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String substring(final int startIndex, int endIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public char[] toCharArray() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public char[] toCharArray(final int startIndex, int endIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringBuffer toStringBuffer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringBuilder toStringBuilder() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrBuilder trim() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.text;
|
||||
|
||||
public abstract class StrMatcher {
|
||||
public static StrMatcher commaMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher tabMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher spaceMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher splitMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher trimMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher singleQuoteMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher doubleQuoteMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher quoteMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher noneMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher charMatcher(final char ch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher charSetMatcher(final char... chars) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher charSetMatcher(final String chars) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrMatcher stringMatcher(final String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd);
|
||||
|
||||
public int isMatch(final char[] buffer, final int pos) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.text;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
public class StrTokenizer implements ListIterator<String>, Cloneable {
|
||||
public static StrTokenizer getCSVInstance() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrTokenizer getCSVInstance(final char[] input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrTokenizer getCSVInstance(final String input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrTokenizer getTSVInstance() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrTokenizer getTSVInstance(final char[] input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StrTokenizer getTSVInstance(final String input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer() {
|
||||
}
|
||||
|
||||
public StrTokenizer(final char[] input) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final char[] input, final char delim) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final char[] input, final char delim, final char quote) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final char[] input, final String delim) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final char[] input, final StrMatcher delim) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final char[] input, final StrMatcher delim, final StrMatcher quote) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final String input) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final String input, final char delim) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final String input, final char delim, final char quote) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final String input, final String delim) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final String input, final StrMatcher delim) {
|
||||
}
|
||||
|
||||
public StrTokenizer(final String input, final StrMatcher delim, final StrMatcher quote) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(final String obj) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrMatcher getDelimiterMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrMatcher getIgnoredMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrMatcher getQuoteMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String[] getTokenArray() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<String> getTokenList() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrMatcher getTrimmerMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrevious() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isEmptyTokenAsNull() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isIgnoreEmptyTokens() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String next() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nextIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String nextToken() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String previous() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int previousIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String previousToken() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
}
|
||||
|
||||
public StrTokenizer reset() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer reset(final char[] input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer reset(final String input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final String obj) {
|
||||
}
|
||||
|
||||
public StrTokenizer setDelimiterChar(final char delim) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer setDelimiterMatcher(final StrMatcher delim) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer setDelimiterString(final String delim) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer setEmptyTokenAsNull(final boolean emptyAsNull) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer setIgnoredChar(final char ignored) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer setIgnoredMatcher(final StrMatcher ignored) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer setIgnoreEmptyTokens(final boolean ignoreEmptyTokens) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer setQuoteChar(final char quote) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer setQuoteMatcher(final StrMatcher quote) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StrTokenizer setTrimmerMatcher(final StrMatcher trimmer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.text;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import org.apache.commons.text.matcher.StringMatcher;
|
||||
|
||||
public class StringTokenizer implements ListIterator<String>, Cloneable {
|
||||
public static StringTokenizer getCSVInstance() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StringTokenizer getCSVInstance(final char[] input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StringTokenizer getCSVInstance(final String input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StringTokenizer getTSVInstance() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StringTokenizer getTSVInstance(final char[] input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static StringTokenizer getTSVInstance(final String input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringTokenizer() {
|
||||
}
|
||||
|
||||
public StringTokenizer(final char[] input) {
|
||||
}
|
||||
|
||||
public StringTokenizer(final char[] input, final char delim) {
|
||||
}
|
||||
|
||||
public StringTokenizer(final char[] input, final char delim, final char quote) {
|
||||
}
|
||||
|
||||
public StringTokenizer(final char[] input, final String delim) {
|
||||
}
|
||||
|
||||
public StringTokenizer(final char[] input, final StringMatcher delim) {
|
||||
}
|
||||
|
||||
public StringTokenizer(final char[] input, final StringMatcher delim, final StringMatcher quote) {
|
||||
}
|
||||
|
||||
public StringTokenizer(final String input) {
|
||||
}
|
||||
|
||||
public StringTokenizer(final String input, final char delim) {
|
||||
}
|
||||
|
||||
public StringTokenizer(final String input, final char delim, final char quote) {
|
||||
}
|
||||
|
||||
public StringTokenizer(final String input, final String delim) {
|
||||
}
|
||||
|
||||
public StringTokenizer(final String input, final StringMatcher delim) {
|
||||
}
|
||||
|
||||
public StringTokenizer(final String input, final StringMatcher delim, final StringMatcher quote) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(final String obj) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringMatcher getDelimiterMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringMatcher getIgnoredMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringMatcher getQuoteMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String[] getTokenArray() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<String> getTokenList() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringMatcher getTrimmerMatcher() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrevious() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isEmptyTokenAsNull() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isIgnoreEmptyTokens() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String next() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nextIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String nextToken() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String previous() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int previousIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String previousToken() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
}
|
||||
|
||||
public StringTokenizer reset() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringTokenizer reset(final char[] input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringTokenizer reset(final String input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(final String obj) {
|
||||
}
|
||||
|
||||
public StringTokenizer setDelimiterChar(final char delim) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringTokenizer setDelimiterMatcher(final StringMatcher delim) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringTokenizer setDelimiterString(final String delim) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringTokenizer setEmptyTokenAsNull(final boolean emptyAsNull) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringTokenizer setIgnoredChar(final char ignored) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringTokenizer setIgnoredMatcher(final StringMatcher ignored) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringTokenizer setIgnoreEmptyTokens(final boolean ignoreEmptyTokens) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringTokenizer setQuoteChar(final char quote) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringTokenizer setQuoteMatcher(final StringMatcher quote) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringTokenizer setTrimmerMatcher(final StringMatcher trimmer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user