Files
codeql/java/ql/lib/semmle/code/java/JDK.qll
Anders Schack-Mulligen a3fc463d0a Java: Minor perf improvement.
2022-08-11 14:21:10 +02:00

470 lines
13 KiB
Plaintext

/**
* Provides classes and predicates for working with standard classes and methods from the JDK.
*/
import Member
import semmle.code.java.security.ExternalProcess
private import semmle.code.java.dataflow.FlowSteps
// --- Standard types ---
/** The class `java.lang.Object`. */
class TypeObject extends Class {
pragma[noinline]
TypeObject() { this.hasQualifiedName("java.lang", "Object") }
}
/** The interface `java.lang.Cloneable`. */
class TypeCloneable extends Interface {
TypeCloneable() { this.hasQualifiedName("java.lang", "Cloneable") }
}
/** The class `java.lang.ProcessBuilder`. */
class TypeProcessBuilder extends Class {
TypeProcessBuilder() { this.hasQualifiedName("java.lang", "ProcessBuilder") }
}
/** The class `java.lang.Runtime`. */
class TypeRuntime extends Class {
TypeRuntime() { this.hasQualifiedName("java.lang", "Runtime") }
}
/** The class `java.lang.String`. */
class TypeString extends Class {
TypeString() { this.hasQualifiedName("java.lang", "String") }
}
/** The `length()` method of the class `java.lang.String`. */
class StringLengthMethod extends Method {
StringLengthMethod() { this.hasName("length") and this.getDeclaringType() instanceof TypeString }
}
/**
* The methods on the class `java.lang.String` that are used to perform partial matches with a specified substring or char.
*/
class StringPartialMatchMethod extends Method {
StringPartialMatchMethod() {
this.hasName([
"contains", "startsWith", "endsWith", "matches", "indexOf", "lastIndexOf", "regionMatches"
]) and
this.getDeclaringType() instanceof TypeString
}
/**
* Gets the index of the parameter that is being matched against.
*/
int getMatchParameterIndex() {
if this.hasName("regionMatches")
then this.getParameterType(result) instanceof TypeString
else result = 0
}
}
/** The class `java.lang.StringBuffer`. */
class TypeStringBuffer extends Class {
TypeStringBuffer() { this.hasQualifiedName("java.lang", "StringBuffer") }
}
/** The class `java.lang.StringBuilder`. */
class TypeStringBuilder extends Class {
TypeStringBuilder() { this.hasQualifiedName("java.lang", "StringBuilder") }
}
/** Class `java.lang.StringBuffer` or `java.lang.StringBuilder`. */
class StringBuildingType extends Class {
StringBuildingType() { this instanceof TypeStringBuffer or this instanceof TypeStringBuilder }
}
/** The class `java.lang.System`. */
class TypeSystem extends Class {
TypeSystem() { this.hasQualifiedName("java.lang", "System") }
}
/** The class `java.lang.Throwable`. */
class TypeThrowable extends Class {
TypeThrowable() { this.hasQualifiedName("java.lang", "Throwable") }
}
/** The class `java.lang.Exception`. */
class TypeException extends Class {
TypeException() { this.hasQualifiedName("java.lang", "Exception") }
}
/** The class `java.lang.Error`. */
class TypeError extends Class {
TypeError() { this.hasQualifiedName("java.lang", "Error") }
}
/** The class `java.lang.RuntimeException`. */
class TypeRuntimeException extends Class {
TypeRuntimeException() { this.hasQualifiedName("java.lang", "RuntimeException") }
}
/** The class `java.lang.ClassCastException`. */
class TypeClassCastException extends Class {
TypeClassCastException() { this.hasQualifiedName("java.lang", "ClassCastException") }
}
/** The class `java.lang.NullPointerException`. */
class TypeNullPointerException extends Class {
TypeNullPointerException() { this.hasQualifiedName("java.lang", "NullPointerException") }
}
/**
* The class `java.lang.Class`.
*
* This includes the generic source declaration, any parameterized instances and the raw type.
*/
class TypeClass extends Class {
TypeClass() { this.getSourceDeclaration().hasQualifiedName("java.lang", "Class") }
}
/**
* The class `java.lang.Constructor`.
*
* This includes the generic source declaration, any parameterized instances and the raw type.
*/
class TypeConstructor extends Class {
TypeConstructor() {
this.getSourceDeclaration().hasQualifiedName("java.lang.reflect", "Constructor")
}
}
/** The class `java.lang.Math`. */
class TypeMath extends Class {
TypeMath() { this.hasQualifiedName("java.lang", "Math") }
}
/** The class `java.lang.Number`. */
class TypeNumber extends RefType {
TypeNumber() { this.hasQualifiedName("java.lang", "Number") }
}
/** A (reflexive, transitive) subtype of `java.lang.Number`. */
class NumberType extends RefType {
pragma[nomagic]
NumberType() { this.getASupertype*() instanceof TypeNumber }
}
/** An immutable type. */
class ImmutableType extends Type {
ImmutableType() {
this instanceof PrimitiveType or
this instanceof NullType or
this instanceof VoidType or
this instanceof BoxedType or
this instanceof TypeString
}
}
// --- Java IO ---
/** The interface `java.io.Serializable`. */
class TypeSerializable extends Interface {
TypeSerializable() { this.hasQualifiedName("java.io", "Serializable") }
}
/** The interface `java.io.ObjectOutput`. */
class TypeObjectOutput extends Interface {
TypeObjectOutput() { this.hasQualifiedName("java.io", "ObjectOutput") }
}
/** The type `java.io.ObjectOutputStream`. */
class TypeObjectOutputStream extends RefType {
TypeObjectOutputStream() { this.hasQualifiedName("java.io", "ObjectOutputStream") }
}
/** The type `java.io.ObjectInputStream`. */
class TypeObjectInputStream extends RefType {
TypeObjectInputStream() { this.hasQualifiedName("java.io", "ObjectInputStream") }
}
/** The class `java.nio.file.Paths`. */
class TypePaths extends Class {
TypePaths() { this.hasQualifiedName("java.nio.file", "Paths") }
}
/** The type `java.nio.file.Path`. */
class TypePath extends RefType {
TypePath() { this.hasQualifiedName("java.nio.file", "Path") }
}
/** The class `java.nio.file.FileSystem`. */
class TypeFileSystem extends Class {
TypeFileSystem() { this.hasQualifiedName("java.nio.file", "FileSystem") }
}
/** The class `java.io.File`. */
class TypeFile extends Class {
TypeFile() { this.hasQualifiedName("java.io", "File") }
}
// --- Standard methods ---
/**
* Any constructor of class `java.lang.ProcessBuilder`.
*/
class ProcessBuilderConstructor extends Constructor, ExecCallable {
ProcessBuilderConstructor() { this.getDeclaringType() instanceof TypeProcessBuilder }
override int getAnExecutedArgument() { result = 0 }
}
/**
* Any of the methods named `command` on class `java.lang.ProcessBuilder`.
*/
class MethodProcessBuilderCommand extends Method, ExecCallable {
MethodProcessBuilderCommand() {
this.hasName("command") and
this.getDeclaringType() instanceof TypeProcessBuilder
}
override int getAnExecutedArgument() { result = 0 }
}
/**
* Any method named `exec` on class `java.lang.Runtime`.
*/
class MethodRuntimeExec extends Method, ExecCallable {
MethodRuntimeExec() {
this.hasName("exec") and
this.getDeclaringType() instanceof TypeRuntime
}
override int getAnExecutedArgument() { result = 0 }
}
/**
* Any method named `getenv` on class `java.lang.System`.
*/
class MethodSystemGetenv extends Method {
MethodSystemGetenv() {
this.hasName("getenv") and
this.getDeclaringType() instanceof TypeSystem
}
}
/**
* Any method named `getProperty` on class `java.lang.System`.
*/
class MethodSystemGetProperty extends ValuePreservingMethod {
MethodSystemGetProperty() {
this.hasName("getProperty") and
this.getDeclaringType() instanceof TypeSystem
}
override predicate returnsValue(int arg) { arg = 1 }
}
/**
* An access to a method named `getProperty` on class `java.lang.System`.
*/
class MethodAccessSystemGetProperty extends MethodAccess {
MethodAccessSystemGetProperty() { this.getMethod() instanceof MethodSystemGetProperty }
/**
* Holds if this call has a compile-time constant first argument with the value `propertyName`.
* For example: `System.getProperty("user.dir")`.
*
* Note: Better to use `semmle.code.java.environment.SystemProperty#getSystemProperty` instead
* as that predicate covers ways of accessing the same information via various libraries.
*/
predicate hasCompileTimeConstantGetPropertyName(string propertyName) {
this.getArgument(0).(CompileTimeConstantExpr).getStringValue() = propertyName
}
}
/**
* Any method named `exit` on class `java.lang.Runtime` or `java.lang.System`.
*/
class MethodExit extends Method {
MethodExit() {
this.hasName("exit") and
(
this.getDeclaringType() instanceof TypeRuntime or
this.getDeclaringType() instanceof TypeSystem
)
}
}
/**
* A method named `writeObject` on type `java.io.ObjectOutput`
* or `java.io.ObjectOutputStream`.
*/
class WriteObjectMethod extends Method {
WriteObjectMethod() {
this.hasName("writeObject") and
(
this.getDeclaringType() instanceof TypeObjectOutputStream or
this.getDeclaringType() instanceof TypeObjectOutput
)
}
}
/**
* A method that reads an object on type `java.io.ObjectInputStream`,
* including `readObject`, `readObjectOverride`, `readUnshared` and `resolveObject`.
*/
class ReadObjectMethod extends Method {
ReadObjectMethod() {
this.getDeclaringType() instanceof TypeObjectInputStream and
(
this.hasName("readObject") or
this.hasName("readObjectOverride") or
this.hasName("readUnshared") or
this.hasName("resolveObject")
)
}
}
/** The method `Class.getName()`. */
class ClassNameMethod extends Method {
ClassNameMethod() {
this.hasName("getName") and
this.getDeclaringType() instanceof TypeClass
}
}
/** The method `Class.getSimpleName()`. */
class ClassSimpleNameMethod extends Method {
ClassSimpleNameMethod() {
this.hasName("getSimpleName") and
this.getDeclaringType() instanceof TypeClass
}
}
/** The method `Math.abs`. */
class MethodAbs extends Method {
MethodAbs() {
this.getDeclaringType() instanceof TypeMath and
this.getName() = "abs"
}
}
/** The method `Math.min`. */
class MethodMathMin extends Method {
MethodMathMin() {
this.getDeclaringType() instanceof TypeMath and
this.getName() = "min"
}
}
/** The method `Math.min`. */
class MethodMathMax extends Method {
MethodMathMax() {
this.getDeclaringType() instanceof TypeMath and
this.getName() = "max"
}
}
// --- Standard fields ---
/** The field `System.in`. */
class SystemIn extends Field {
SystemIn() {
this.hasName("in") and
this.getDeclaringType() instanceof TypeSystem
}
}
/** The field `System.out`. */
class SystemOut extends Field {
SystemOut() {
this.hasName("out") and
this.getDeclaringType() instanceof TypeSystem
}
}
/** The field `System.err`. */
class SystemErr extends Field {
SystemErr() {
this.hasName("err") and
this.getDeclaringType() instanceof TypeSystem
}
}
// --- User-defined methods with a particular meaning ---
/** A method with the same signature as `java.lang.Object.equals`. */
class EqualsMethod extends Method {
EqualsMethod() {
this.hasName("equals") and
this.getNumberOfParameters() = 1 and
this.getParameter(0).getType().(RefType).hasQualifiedName("java.lang", "Object")
}
/** Gets the single parameter of this method. */
Parameter getParameter() { result = this.getAParameter() }
}
/** A method with the same signature as `java.lang.Object.hashCode`. */
class HashCodeMethod extends Method {
HashCodeMethod() {
this.hasName("hashCode") and
this.hasNoParameters()
}
}
/** A method with the same signature as `java.lang.Object.clone`. */
class CloneMethod extends Method {
CloneMethod() {
this.hasName("clone") and
this.hasNoParameters()
}
}
/** A method with the same signature as `java.lang.Object.toString`. */
class ToStringMethod extends Method {
ToStringMethod() {
this.hasName("toString") and
this.hasNoParameters()
}
}
/**
* The public static `main` method, with a single formal parameter
* of type `String[]` and return type `void`.
*/
class MainMethod extends Method {
MainMethod() {
this.isPublic() and
this.isStatic() and
this.getReturnType().hasName("void") and
this.hasName("main") and
this.getNumberOfParameters() = 1 and
exists(Array a |
a = this.getAParameter().getType() and
a.getDimension() = 1 and
a.getElementType() instanceof TypeString
)
}
}
/** A premain method is an agent entry-point. */
class PreMainMethod extends Method {
PreMainMethod() {
this.isPublic() and
this.isStatic() and
this.getReturnType().hasName("void") and
this.getNumberOfParameters() < 3 and
this.getParameter(0).getType() instanceof TypeString and
(exists(this.getParameter(1)) implies this.getParameter(1).getType().hasName("Instrumentation"))
}
}
/** The `length` field of the array type. */
class ArrayLengthField extends Field {
ArrayLengthField() {
this.getDeclaringType() instanceof Array and
this.hasName("length")
}
}
/** A (reflexive, transitive) subtype of `java.lang.Throwable`. */
class ThrowableType extends RefType {
ThrowableType() { exists(TypeThrowable throwable | hasDescendant(throwable, this)) }
}
/** An unchecked exception. That is, a (reflexive, transitive) subtype of `java.lang.Error` or `java.lang.RuntimeException`. */
class UncheckedThrowableType extends RefType {
UncheckedThrowableType() {
exists(TypeError e | hasDescendant(e, this)) or
exists(TypeRuntimeException e | hasDescendant(e, this))
}
}