Merge branch 'main' into sj-patch-1

This commit is contained in:
Bas van Schaik
2021-02-24 15:10:26 +00:00
committed by GitHub
137 changed files with 13369 additions and 3691 deletions

21
.github/workflows/check-change-note.yml vendored Normal file
View 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

View File

@@ -5,10 +5,14 @@ on:
branches:
- main
- 'rc/*'
paths:
- 'csharp/**'
pull_request:
branches:
- main
- 'rc/*'
paths:
- 'csharp/**'
schedule:
- cron: '0 9 * * 1'

View File

@@ -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

View File

@@ -8,6 +8,7 @@
* @tags reliability
* security
* external/cwe/cwe-242
* external/cwe/cwe-676
*/
import cpp

View File

@@ -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

View 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() }
}

View 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() }
}

View 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() }
}

View 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
}

View File

@@ -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 |

View 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.

View File

@@ -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);

View File

@@ -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)) { }

View File

@@ -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));
}
}
}

View File

@@ -124,7 +124,7 @@ namespace Semmle.Extraction.Kinds
AND_PATTERN = 127,
OR_PATTERN = 128,
FUNCTION_POINTER_INVOCATION = 129,
WITH = 130,
DEFINE_SYMBOL = 999
}
}

View File

@@ -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.
*

View File

@@ -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" }
}

View File

@@ -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
)
}
}

View File

@@ -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) {

View File

@@ -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`).
*/

View File

@@ -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()
}
}

View File

@@ -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`).
*/

View File

@@ -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()
}
}
}

View File

@@ -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" }
}

View File

@@ -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()
}
}

View File

@@ -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) }
}
/**

View File

@@ -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

View File

@@ -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

View File

@@ -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" };
}
}

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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()

View 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>$() |

View 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)
)
}

View File

@@ -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 |

View 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

View File

@@ -0,0 +1,2 @@
description: Add 'with_expr' to 'expr' types.
compatibility: backwards

View File

@@ -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
-------------------

View File

@@ -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>`__."

View File

@@ -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

View File

@@ -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
==================================

View File

@@ -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() { ... }
}
```

View File

@@ -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
}

View File

@@ -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

View File

@@ -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

View File

@@ -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()
}
}

View File

@@ -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())
}
/**

View File

@@ -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())
)
}

View File

@@ -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)
}
/**

View File

@@ -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);
}
}

View File

@@ -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>

View File

@@ -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"

View File

@@ -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() |

View File

@@ -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 = "...?...:..." }

View File

@@ -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 |

View 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))
)
}

View File

@@ -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

View File

@@ -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) {

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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
)
}

View File

@@ -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

View File

@@ -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

View File

@@ -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
}
/**

View File

@@ -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
}

View File

@@ -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
}
}

View File

@@ -0,0 +1,2 @@
public class A {
}

View File

@@ -0,0 +1,2 @@
public class A {
}

View File

@@ -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 |

View File

@@ -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);
}
}

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-598/SensitiveGetQuery.ql

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1 @@
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4

View 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; }
}

View 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;
}

View 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) { }
}

View File

@@ -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 |

View 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

View File

@@ -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 |

View 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

View File

@@ -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 |

View 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

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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&lt;Font&gt; {
* 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();
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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&lt;Font&gt; {
* 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();
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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