mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge main into redsun82/swift-extraction
This commit is contained in:
9
.devcontainer/swift/Dockerfile
Normal file
9
.devcontainer/swift/Dockerfile
Normal file
@@ -0,0 +1,9 @@
|
||||
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.236.0/containers/cpp/.devcontainer/base.Dockerfile
|
||||
|
||||
# [Choice] Debian / Ubuntu version (use Debian 11, Ubuntu 18.04/22.04 on local arm64/Apple Silicon): debian-11, debian-10, ubuntu-22.04, ubuntu-20.04, ubuntu-18.04
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/cpp:0-ubuntu-22.04
|
||||
|
||||
USER root
|
||||
ADD root.sh /tmp/root.sh
|
||||
ADD update-codeql.sh /usr/local/bin/update-codeql
|
||||
RUN bash /tmp/root.sh && rm /tmp/root.sh
|
||||
25
.devcontainer/swift/devcontainer.json
Normal file
25
.devcontainer/swift/devcontainer.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"extensions": [
|
||||
"github.vscode-codeql",
|
||||
"hbenl.vscode-test-explorer",
|
||||
"ms-vscode.test-adapter-converter",
|
||||
"slevesque.vscode-zipexplorer",
|
||||
"ms-vscode.cpptools"
|
||||
],
|
||||
"settings": {
|
||||
"files.watcherExclude": {
|
||||
"**/target/**": true
|
||||
},
|
||||
"codeQL.runningQueries.memory": 2048
|
||||
},
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
},
|
||||
"runArgs": [
|
||||
"--cap-add=SYS_PTRACE",
|
||||
"--security-opt",
|
||||
"seccomp=unconfined"
|
||||
],
|
||||
"remoteUser": "vscode",
|
||||
"onCreateCommand": ".devcontainer/swift/user.sh"
|
||||
}
|
||||
22
.devcontainer/swift/root.sh
Normal file
22
.devcontainer/swift/root.sh
Normal file
@@ -0,0 +1,22 @@
|
||||
set -xe
|
||||
|
||||
BAZELISK_VERSION=v1.12.0
|
||||
BAZELISK_DOWNLOAD_SHA=6b0bcb2ea15bca16fffabe6fda75803440375354c085480fe361d2cbf32501db
|
||||
|
||||
apt-get update
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get -y install --no-install-recommends \
|
||||
zlib1g-dev \
|
||||
uuid-dev \
|
||||
python3-distutils \
|
||||
python3-pip \
|
||||
bash-completion
|
||||
|
||||
# Install Bazel
|
||||
curl -fSsL -o /usr/local/bin/bazelisk https://github.com/bazelbuild/bazelisk/releases/download/${BAZELISK_VERSION}/bazelisk-linux-amd64
|
||||
echo "${BAZELISK_DOWNLOAD_SHA} */usr/local/bin/bazelisk" | sha256sum --check -
|
||||
chmod 0755 /usr/local/bin/bazelisk
|
||||
ln -s bazelisk /usr/local/bin/bazel
|
||||
|
||||
# install latest codeql
|
||||
update-codeql
|
||||
20
.devcontainer/swift/update-codeql.sh
Executable file
20
.devcontainer/swift/update-codeql.sh
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
URL=https://github.com/github/codeql-cli-binaries/releases
|
||||
LATEST_VERSION=$(curl -L -s -H 'Accept: application/json' $URL/latest | sed -e 's/.*"tag_name":"\([^"]*\)".*/\1/')
|
||||
CURRENT_VERSION=v$(codeql version 2>/dev/null | sed -ne 's/.*release \([0-9.]*\)\./\1/p')
|
||||
if [[ $CURRENT_VERSION != $LATEST_VERSION ]]; then
|
||||
if [[ $UID != 0 ]]; then
|
||||
echo "update required, please run this script with sudo:"
|
||||
echo " sudo $0"
|
||||
exit 1
|
||||
fi
|
||||
ZIP=$(mktemp codeql.XXXX.zip)
|
||||
curl -fSqL -o $ZIP $URL/download/$LATEST_VERSION/codeql-linux64.zip
|
||||
unzip -q $ZIP -d /opt
|
||||
rm $ZIP
|
||||
ln -sf /opt/codeql/codeql /usr/local/bin/codeql
|
||||
echo installed version $LATEST_VERSION
|
||||
else
|
||||
echo current version $CURRENT_VERSION is up-to-date
|
||||
fi
|
||||
13
.devcontainer/swift/user.sh
Executable file
13
.devcontainer/swift/user.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
set -xe
|
||||
|
||||
# add the workspace to the codeql search path
|
||||
mkdir -p /home/vscode/.config/codeql
|
||||
echo "--search-path /workspaces/codeql" > /home/vscode/.config/codeql/config
|
||||
|
||||
# create a swift extractor pack with the current state
|
||||
cd /workspaces/codeql
|
||||
bazel run swift/create-extractor-pack
|
||||
|
||||
#install and set up pre-commit
|
||||
python3 -m pip install pre-commit --no-warn-script-location
|
||||
$HOME/.local/bin/pre-commit install
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* `UserType.getADeclarationEntry()` now yields all forward declarations when the user type is a `class`, `struct`, or `union`.
|
||||
@@ -48,8 +48,8 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @
|
||||
}
|
||||
|
||||
override TypeDeclarationEntry getADeclarationEntry() {
|
||||
if type_decls(_, underlyingElement(this), _)
|
||||
then type_decls(unresolveElement(result), underlyingElement(this), _)
|
||||
if type_decls(_, unresolveElement(this), _)
|
||||
then type_decls(underlyingElement(result), unresolveElement(this), _)
|
||||
else exists(Class t | this.(Class).isConstructedFrom(t) and result = t.getADeclarationEntry())
|
||||
}
|
||||
|
||||
|
||||
@@ -33,3 +33,11 @@ public:
|
||||
|
||||
myTemplateClass<int> mtc_int;
|
||||
myTemplateClass<short> mtc_short;
|
||||
|
||||
// Class (UserType)
|
||||
|
||||
class myClass
|
||||
{
|
||||
public:
|
||||
int myMemberVariable;
|
||||
};
|
||||
|
||||
@@ -27,5 +27,11 @@
|
||||
| declarationEntry.cpp:31:4:31:19 | myMemberVariable | declarationEntry.cpp:31:4:31:19 | definition of myMemberVariable | 1 | 1 |
|
||||
| declarationEntry.cpp:34:22:34:28 | mtc_int | declarationEntry.cpp:34:22:34:28 | definition of mtc_int | 1 | 1 |
|
||||
| declarationEntry.cpp:35:24:35:32 | mtc_short | declarationEntry.cpp:35:24:35:32 | definition of mtc_short | 1 | 1 |
|
||||
| declarationEntry.cpp:39:7:39:7 | operator= | declarationEntry.cpp:39:7:39:7 | declaration of operator= | 1 | 1 |
|
||||
| declarationEntry.cpp:39:7:39:7 | operator= | declarationEntry.cpp:39:7:39:7 | declaration of operator= | 1 | 1 |
|
||||
| declarationEntry.cpp:39:7:39:13 | myClass | declarationEntry.cpp:39:7:39:13 | definition of myClass | 1 | 1 |
|
||||
| declarationEntry.cpp:39:7:39:13 | myClass | forwardDeclaration.cpp:1:7:1:13 | declaration of myClass | 1 | 1 |
|
||||
| declarationEntry.cpp:42:6:42:21 | myMemberVariable | declarationEntry.cpp:42:6:42:21 | definition of myMemberVariable | 1 | 1 |
|
||||
| forwardDeclaration.cpp:3:10:3:19 | myClassPtr | forwardDeclaration.cpp:3:10:3:19 | definition of myClassPtr | 1 | 1 |
|
||||
| macro.c:2:1:2:3 | foo | macro.c:2:1:2:3 | declaration of foo | 1 | 1 |
|
||||
| macro.c:4:5:4:8 | main | macro.c:4:5:4:8 | definition of main | 1 | 1 |
|
||||
|
||||
@@ -10,5 +10,7 @@
|
||||
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | | 0 | |
|
||||
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | | 0 | |
|
||||
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | | 0 | |
|
||||
| declarationEntry.cpp:39:7:39:7 | declaration of operator= | | 0 | |
|
||||
| declarationEntry.cpp:39:7:39:7 | declaration of operator= | | 0 | |
|
||||
| macro.c:2:1:2:3 | declaration of foo | | 2 | c_linkage, static |
|
||||
| macro.c:4:5:4:8 | definition of main | | 1 | c_linkage |
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
class myClass;
|
||||
|
||||
myClass *myClassPtr;
|
||||
@@ -0,0 +1,45 @@
|
||||
| declarationEntry.c:2:6:2:20 | declaration of myFirstFunction | declarationEntry.c:2:6:2:20 | myFirstFunction | yes |
|
||||
| declarationEntry.c:4:6:4:21 | definition of mySecondFunction | declarationEntry.c:4:6:4:21 | mySecondFunction | yes |
|
||||
| declarationEntry.c:8:6:8:20 | definition of myThirdFunction | declarationEntry.c:8:6:8:20 | myThirdFunction | yes |
|
||||
| declarationEntry.c:13:2:13:2 | declaration of myFourthFunction | declarationEntry.c:13:2:13:2 | myFourthFunction | yes |
|
||||
| declarationEntry.c:13:2:13:2 | declaration of myFourthFunction | declarationEntry.c:17:6:17:21 | myFourthFunction | yes |
|
||||
| declarationEntry.c:14:2:14:2 | declaration of myFifthFunction | declarationEntry.c:14:2:14:2 | myFifthFunction | yes |
|
||||
| declarationEntry.c:17:6:17:21 | declaration of myFourthFunction | declarationEntry.c:13:2:13:2 | myFourthFunction | yes |
|
||||
| declarationEntry.c:17:6:17:21 | declaration of myFourthFunction | declarationEntry.c:17:6:17:21 | myFourthFunction | yes |
|
||||
| declarationEntry.cpp:3:12:3:21 | declaration of myVariable | declarationEntry.cpp:5:5:5:14 | myVariable | yes |
|
||||
| declarationEntry.cpp:5:5:5:14 | definition of myVariable | declarationEntry.cpp:5:5:5:14 | myVariable | yes |
|
||||
| declarationEntry.cpp:9:6:9:15 | declaration of myFunction | declarationEntry.cpp:11:6:11:15 | myFunction | yes |
|
||||
| declarationEntry.cpp:9:21:9:31 | declaration of myParameter | declarationEntry.cpp:11:21:11:31 | myParameter | yes |
|
||||
| declarationEntry.cpp:11:6:11:15 | definition of myFunction | declarationEntry.cpp:11:6:11:15 | myFunction | yes |
|
||||
| declarationEntry.cpp:11:21:11:31 | definition of myParameter | declarationEntry.cpp:11:21:11:31 | myParameter | yes |
|
||||
| declarationEntry.cpp:18:6:18:11 | declaration of myEnum | declarationEntry.cpp:20:6:20:11 | myEnum | yes |
|
||||
| declarationEntry.cpp:20:6:20:11 | definition of myEnum | declarationEntry.cpp:20:6:20:11 | myEnum | yes |
|
||||
| declarationEntry.cpp:27:20:27:20 | definition of T | declarationEntry.cpp:27:20:27:20 | T | yes |
|
||||
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | declarationEntry.cpp:28:7:28:7 | operator= | yes |
|
||||
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | declarationEntry.cpp:28:7:28:7 | operator= | yes |
|
||||
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | declarationEntry.cpp:28:7:28:7 | operator= | yes |
|
||||
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | declarationEntry.cpp:28:7:28:7 | operator= | yes |
|
||||
| declarationEntry.cpp:28:7:28:21 | definition of myTemplateClass<T> | declarationEntry.cpp:28:7:28:21 | myTemplateClass<T> | yes |
|
||||
| declarationEntry.cpp:31:4:31:19 | definition of myMemberVariable | declarationEntry.cpp:31:4:31:19 | myMemberVariable | yes |
|
||||
| declarationEntry.cpp:31:4:31:19 | definition of myMemberVariable | declarationEntry.cpp:31:4:31:19 | myMemberVariable | yes |
|
||||
| declarationEntry.cpp:31:4:31:19 | definition of myMemberVariable | declarationEntry.cpp:31:4:31:19 | myMemberVariable | yes |
|
||||
| declarationEntry.cpp:34:22:34:28 | definition of mtc_int | declarationEntry.cpp:34:22:34:28 | mtc_int | yes |
|
||||
| declarationEntry.cpp:35:24:35:32 | definition of mtc_short | declarationEntry.cpp:35:24:35:32 | mtc_short | yes |
|
||||
| declarationEntry.cpp:39:7:39:7 | declaration of operator= | declarationEntry.cpp:39:7:39:7 | operator= | yes |
|
||||
| declarationEntry.cpp:39:7:39:7 | declaration of operator= | declarationEntry.cpp:39:7:39:7 | operator= | yes |
|
||||
| declarationEntry.cpp:39:7:39:13 | definition of myClass | declarationEntry.cpp:39:7:39:13 | myClass | yes |
|
||||
| declarationEntry.cpp:42:6:42:21 | definition of myMemberVariable | declarationEntry.cpp:42:6:42:21 | myMemberVariable | yes |
|
||||
| file://:0:0:0:0 | declaration of 1st parameter | file://:0:0:0:0 | (unnamed parameter 0) | yes |
|
||||
| file://:0:0:0:0 | declaration of 1st parameter | file://:0:0:0:0 | (unnamed parameter 0) | yes |
|
||||
| file://:0:0:0:0 | declaration of 1st parameter | file://:0:0:0:0 | (unnamed parameter 0) | yes |
|
||||
| file://:0:0:0:0 | declaration of 1st parameter | file://:0:0:0:0 | (unnamed parameter 0) | yes |
|
||||
| file://:0:0:0:0 | declaration of 1st parameter | file://:0:0:0:0 | (unnamed parameter 0) | yes |
|
||||
| file://:0:0:0:0 | declaration of 1st parameter | file://:0:0:0:0 | (unnamed parameter 0) | yes |
|
||||
| file://:0:0:0:0 | definition of fp_offset | file://:0:0:0:0 | fp_offset | yes |
|
||||
| file://:0:0:0:0 | definition of gp_offset | file://:0:0:0:0 | gp_offset | yes |
|
||||
| file://:0:0:0:0 | definition of overflow_arg_area | file://:0:0:0:0 | overflow_arg_area | yes |
|
||||
| file://:0:0:0:0 | definition of reg_save_area | file://:0:0:0:0 | reg_save_area | yes |
|
||||
| forwardDeclaration.cpp:1:7:1:13 | declaration of myClass | declarationEntry.cpp:39:7:39:13 | myClass | yes |
|
||||
| forwardDeclaration.cpp:3:10:3:19 | definition of myClassPtr | forwardDeclaration.cpp:3:10:3:19 | myClassPtr | yes |
|
||||
| macro.c:2:1:2:3 | declaration of foo | macro.c:2:1:2:3 | foo | yes |
|
||||
| macro.c:4:5:4:8 | definition of main | macro.c:4:5:4:8 | main | yes |
|
||||
@@ -0,0 +1,7 @@
|
||||
import cpp
|
||||
|
||||
from DeclarationEntry de, Declaration d, string canRoundTrip
|
||||
where
|
||||
d = de.getDeclaration() and
|
||||
if d.getADeclarationEntry() = de then canRoundTrip = "yes" else canRoundTrip = "no"
|
||||
select de, d, canRoundTrip
|
||||
4
cpp/ql/test/library-tests/variables/global/d.cpp
Normal file
4
cpp/ql/test/library-tests/variables/global/d.cpp
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
namespace aNameSpace {
|
||||
int xs[] = { 1, 2 };
|
||||
}
|
||||
4
cpp/ql/test/library-tests/variables/global/d.h
Normal file
4
cpp/ql/test/library-tests/variables/global/d.h
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
namespace aNameSpace {
|
||||
extern int xs[2];
|
||||
}
|
||||
2
cpp/ql/test/library-tests/variables/global/e.cpp
Normal file
2
cpp/ql/test/library-tests/variables/global/e.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
#include "d.h"
|
||||
@@ -10,6 +10,8 @@
|
||||
| c.h:6:12:6:13 | declaration of ls | array of 4 {int} | 1 |
|
||||
| c.h:8:12:8:14 | declaration of iss | array of {array of 2 {int}} | 1 |
|
||||
| c.h:10:12:10:12 | declaration of i | int | 1 |
|
||||
| d.cpp:3:7:3:8 | definition of xs | array of {int} | 1 |
|
||||
| d.h:3:14:3:15 | declaration of xs | array of 2 {int} | 1 |
|
||||
| file://:0:0:0:0 | definition of fp_offset | unsigned int | 1 |
|
||||
| file://:0:0:0:0 | definition of gp_offset | unsigned int | 1 |
|
||||
| file://:0:0:0:0 | definition of overflow_arg_area | pointer to {void} | 1 |
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
| c.h:4:12:4:13 | ks | array of {int} | 1 |
|
||||
| c.h:8:12:8:14 | iss | array of {array of 2 {int}} | 1 |
|
||||
| c.h:10:12:10:12 | i | int | 1 |
|
||||
| d.cpp:3:7:3:8 | xs | array of {int} | 1 |
|
||||
| d.h:3:14:3:15 | xs | array of 2 {int} | 1 |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | reference to {const {struct __va_list_tag}} | 1 |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | rvalue reference to {struct __va_list_tag} | 1 |
|
||||
| file://:0:0:0:0 | fp_offset | unsigned int | 1 |
|
||||
| file://:0:0:0:0 | gp_offset | unsigned int | 1 |
|
||||
| file://:0:0:0:0 | overflow_arg_area | pointer to {void} | 1 |
|
||||
|
||||
@@ -507,6 +507,9 @@ open class KotlinFileExtractor(
|
||||
return FieldResult(instanceId, instanceName)
|
||||
}
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
private fun hasSynthesizedParameterNames(f: IrFunction) = f.descriptor.hasSynthesizedParameterNames()
|
||||
|
||||
private fun extractValueParameter(vp: IrValueParameter, parent: Label<out DbCallable>, idx: Int, typeSubstitution: TypeSubstitution?, parentSourceDeclaration: Label<out DbCallable>, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, extractTypeAccess: Boolean, locOverride: Label<DbLocation>? = null): TypeResults {
|
||||
with("value parameter", vp) {
|
||||
val location = locOverride ?: getLocation(vp, classTypeArgsIncludingOuterClasses)
|
||||
@@ -523,16 +526,19 @@ open class KotlinFileExtractor(
|
||||
if (extractTypeAccess) {
|
||||
extractTypeAccessRecursive(substitutedType, location, id, -1)
|
||||
}
|
||||
return extractValueParameter(id, substitutedType, vp.name.asString(), location, parent, idx, useValueParameter(vp, parentSourceDeclaration), vp.isVararg)
|
||||
val syntheticParameterNames = (vp.parent as? IrFunction)?.let { hasSynthesizedParameterNames(it) } ?: true
|
||||
return extractValueParameter(id, substitutedType, vp.name.asString(), location, parent, idx, useValueParameter(vp, parentSourceDeclaration), vp.isVararg, syntheticParameterNames)
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractValueParameter(id: Label<out DbParam>, t: IrType, name: String, locId: Label<DbLocation>, parent: Label<out DbCallable>, idx: Int, paramSourceDeclaration: Label<out DbParam>, isVararg: Boolean): TypeResults {
|
||||
private fun extractValueParameter(id: Label<out DbParam>, t: IrType, name: String, locId: Label<DbLocation>, parent: Label<out DbCallable>, idx: Int, paramSourceDeclaration: Label<out DbParam>, isVararg: Boolean, syntheticParameterNames: Boolean): TypeResults {
|
||||
val type = useType(t)
|
||||
tw.writeParams(id, type.javaResult.id, idx, parent, paramSourceDeclaration)
|
||||
tw.writeParamsKotlinType(id, type.kotlinResult.id)
|
||||
tw.writeHasLocation(id, locId)
|
||||
tw.writeParamName(id, name)
|
||||
if (!syntheticParameterNames) {
|
||||
tw.writeParamName(id, name)
|
||||
}
|
||||
if (isVararg) {
|
||||
tw.writeIsVarargsParam(id)
|
||||
}
|
||||
@@ -2952,7 +2958,7 @@ open class KotlinFileExtractor(
|
||||
stmtIdx: Int
|
||||
) {
|
||||
val paramId = tw.getFreshIdLabel<DbParam>()
|
||||
val paramTypeRes = extractValueParameter(paramId, paramType, paramName, locId, ids.constructor, paramIdx, paramId, false)
|
||||
val paramTypeRes = extractValueParameter(paramId, paramType, paramName, locId, ids.constructor, paramIdx, paramId, isVararg = false, syntheticParameterNames = false)
|
||||
|
||||
val assignmentStmtId = tw.getFreshIdLabel<DbExprstmt>()
|
||||
tw.writeStmts_exprstmt(assignmentStmtId, ids.constructorBlock, stmtIdx, ids.constructor)
|
||||
@@ -3588,7 +3594,7 @@ open class KotlinFileExtractor(
|
||||
|
||||
val parameters = parameterTypes.mapIndexed { idx, p ->
|
||||
val paramId = tw.getFreshIdLabel<DbParam>()
|
||||
val paramType = extractValueParameter(paramId, p, "a$idx", locId, methodId, idx, paramId, false)
|
||||
val paramType = extractValueParameter(paramId, p, "a$idx", locId, methodId, idx, paramId, isVararg = false, syntheticParameterNames = false)
|
||||
|
||||
Pair(paramId, paramType)
|
||||
}
|
||||
|
||||
@@ -637,14 +637,31 @@ open class KotlinUsesExtractor(
|
||||
)
|
||||
|
||||
(s.isBoxedArray && s.arguments.isNotEmpty()) || s.isPrimitiveArray() -> {
|
||||
var dimensions = 1
|
||||
var isPrimitiveArray = s.isPrimitiveArray()
|
||||
val componentType = s.getArrayElementType(pluginContext.irBuiltIns)
|
||||
var elementType = componentType
|
||||
|
||||
fun replaceComponentTypeWithAny(t: IrSimpleType, dimensions: Int): IrSimpleType =
|
||||
if (dimensions == 0)
|
||||
pluginContext.irBuiltIns.anyType as IrSimpleType
|
||||
else
|
||||
t.toBuilder().also { it.arguments = (it.arguments[0] as IrTypeProjection)
|
||||
.let { oldArg ->
|
||||
listOf(makeTypeProjection(replaceComponentTypeWithAny(oldArg.type as IrSimpleType, dimensions - 1), oldArg.variance))
|
||||
}
|
||||
}.buildSimpleType()
|
||||
|
||||
var componentType = s.getArrayElementType(pluginContext.irBuiltIns)
|
||||
var isPrimitiveArray = false
|
||||
var dimensions = 0
|
||||
var elementType: IrType = s
|
||||
while (elementType.isBoxedArray || elementType.isPrimitiveArray()) {
|
||||
dimensions++
|
||||
if(elementType.isPrimitiveArray())
|
||||
if (elementType.isPrimitiveArray())
|
||||
isPrimitiveArray = true
|
||||
if (((elementType as IrSimpleType).arguments.singleOrNull() as? IrTypeProjection)?.variance == Variance.IN_VARIANCE) {
|
||||
// Because Java's arrays are covariant, Kotlin will render Array<in X> as Object[], Array<Array<in X>> as Object[][] etc.
|
||||
componentType = replaceComponentTypeWithAny(s, dimensions - 1)
|
||||
elementType = pluginContext.irBuiltIns.anyType as IrSimpleType
|
||||
break
|
||||
}
|
||||
elementType = elementType.getArrayElementType(pluginContext.irBuiltIns)
|
||||
}
|
||||
|
||||
@@ -857,13 +874,33 @@ open class KotlinUsesExtractor(
|
||||
private val jvmWildcardAnnotation = FqName("kotlin.jvm.JvmWildcard")
|
||||
private val jvmWildcardSuppressionAnnotaton = FqName("kotlin.jvm.JvmSuppressWildcards")
|
||||
|
||||
private fun arrayExtendsAdditionAllowed(t: IrSimpleType): Boolean =
|
||||
// Note the array special case includes Array<*>, which does permit adding `? extends ...` (making `? extends Object[]` in that case)
|
||||
// Surprisingly Array<in X> does permit this as well, though the contravariant array lowers to Object[] so this ends up `? extends Object[]` as well.
|
||||
t.arguments[0].let {
|
||||
when (it) {
|
||||
is IrTypeProjection -> when (it.variance) {
|
||||
Variance.INVARIANT -> false
|
||||
Variance.IN_VARIANCE -> !(it.type.isAny() || it.type.isNullableAny())
|
||||
Variance.OUT_VARIANCE -> extendsAdditionAllowed(it.type)
|
||||
}
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
||||
private fun extendsAdditionAllowed(t: IrType) =
|
||||
if (t.isBoxedArray)
|
||||
arrayExtendsAdditionAllowed(t as IrSimpleType)
|
||||
else
|
||||
((t as? IrSimpleType)?.classOrNull?.owner?.isFinalClass) != true
|
||||
|
||||
private fun wildcardAdditionAllowed(v: Variance, t: IrType, addByDefault: Boolean) =
|
||||
when {
|
||||
t.hasAnnotation(jvmWildcardAnnotation) -> true
|
||||
!addByDefault -> false
|
||||
t.hasAnnotation(jvmWildcardSuppressionAnnotaton) -> false
|
||||
v == Variance.IN_VARIANCE -> !(t.isNullableAny() || t.isAny())
|
||||
v == Variance.OUT_VARIANCE -> ((t as? IrSimpleType)?.classOrNull?.owner?.isFinalClass) != true
|
||||
v == Variance.OUT_VARIANCE -> extendsAdditionAllowed(t)
|
||||
else -> false
|
||||
}
|
||||
|
||||
|
||||
22
java/ql/consistency-queries/visibility.ql
Normal file
22
java/ql/consistency-queries/visibility.ql
Normal file
@@ -0,0 +1,22 @@
|
||||
import java
|
||||
|
||||
string visibility(Method m) {
|
||||
result = "public" and m.isPublic()
|
||||
or
|
||||
result = "protected" and m.isProtected()
|
||||
or
|
||||
result = "private" and m.isPrivate()
|
||||
or
|
||||
result = "internal" and m.isInternal()
|
||||
}
|
||||
|
||||
// TODO: This ought to check more than just methods
|
||||
from Method m
|
||||
where
|
||||
// TODO: This ought to work for everything, but for now we
|
||||
// restrict to things in Kotlin source files
|
||||
m.getFile().isKotlinSourceFile() and
|
||||
// TODO: This ought to have visibility information
|
||||
not m.getName() = "<clinit>" and
|
||||
count(visibility(m)) != 1
|
||||
select m, concat(visibility(m), ", ")
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
Added a flow step for `String.valueOf` calls on tainted `android.text.Editable` objects.
|
||||
@@ -29,7 +29,8 @@ class Stmt extends StmtParent, ExprParent, @stmt {
|
||||
*/
|
||||
Stmt getEnclosingStmt() {
|
||||
result = this.getParent() or
|
||||
result = this.getParent().(SwitchExpr).getEnclosingStmt()
|
||||
result = this.getParent().(SwitchExpr).getEnclosingStmt() or
|
||||
result = this.getParent().(WhenExpr).getEnclosingStmt()
|
||||
}
|
||||
|
||||
/** Holds if this statement is the child of the specified parent at the specified (zero-based) position. */
|
||||
|
||||
@@ -18,12 +18,20 @@ private class DefaultAndroidWidgetSources extends RemoteFlowSource {
|
||||
|
||||
private class EditableToStringStep extends AdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
exists(MethodAccess toString |
|
||||
toString.getMethod().hasName("toString") and
|
||||
toString.getReceiverType().hasQualifiedName("android.text", "Editable")
|
||||
|
|
||||
n1.asExpr() = toString.getQualifier() and
|
||||
n2.asExpr() = toString
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod().hasName("toString") and
|
||||
ma.getReceiverType().getASourceSupertype*().hasQualifiedName("android.text", "Editable") and
|
||||
n1.asExpr() = ma.getQualifier() and
|
||||
n2.asExpr() = ma
|
||||
or
|
||||
ma.getMethod().hasQualifiedName("java.lang", "String", "valueOf") and
|
||||
ma.getArgument(0)
|
||||
.getType()
|
||||
.(RefType)
|
||||
.getASourceSupertype*()
|
||||
.hasQualifiedName("android.text", "Editable") and
|
||||
n1.asExpr() = ma.getArgument(0) and
|
||||
n2.asExpr() = ma
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,5 +17,5 @@ import DataFlow::PathGraph
|
||||
|
||||
from LogInjectionConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "This $@ flows to a log entry.", source.getNode(),
|
||||
"user-provided value"
|
||||
select source.getNode(), source, sink, "This user-provided value flows to a $@.", sink.getNode(),
|
||||
"log entry"
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The query `java/log-injection` now reports problems at the source (user-controlled data) instead of at the ultimate logging call. This was changed because user functions that wrap the ultimate logging call could result in most alerts being reported in an uninformative location.
|
||||
@@ -0,0 +1,11 @@
|
||||
public class User {
|
||||
|
||||
public static void test() {
|
||||
|
||||
TakesArrayList tal = new TakesArrayList();
|
||||
tal.invarArray(null);
|
||||
// Using one method suffices to get the extractor to describe all the methods defined on takesArrayList.
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
public class TakesArrayList {
|
||||
|
||||
// There is a Java user to flag up any problems, as if the .class file differs from my
|
||||
// claimed types above we'll see two overloads and two parameter types instead of one.
|
||||
|
||||
// Test how Array types with a variance should be lowered:
|
||||
fun invarArray(a: Array<CharSequence>) { }
|
||||
fun outArray(a: Array<out CharSequence>) { }
|
||||
fun inArray(a: Array<in CharSequence>) { }
|
||||
|
||||
fun invarInvarArray(a: Array<Array<CharSequence>>) { }
|
||||
fun invarOutArray(a: Array<Array<out CharSequence>>) { }
|
||||
fun invarInArray(a: Array<Array<in CharSequence>>) { }
|
||||
|
||||
fun outInvarArray(a: Array<out Array<CharSequence>>) { }
|
||||
fun outOutArray(a: Array<out Array<out CharSequence>>) { }
|
||||
fun outInArray(a: Array<out Array<in CharSequence>>) { }
|
||||
|
||||
fun inInvarArray(a: Array<in Array<CharSequence>>) { }
|
||||
fun inOutArray(a: Array<in Array<out CharSequence>>) { }
|
||||
fun inInArray(a: Array<in Array<in CharSequence>>) { }
|
||||
|
||||
// Test how Array type arguments with a variance should acquire implicit wildcards:
|
||||
fun invarArrayList(l: List<Array<CharSequence>>) { }
|
||||
fun outArrayList(l: List<Array<out CharSequence>>) { }
|
||||
fun inArrayList(l: List<Array<in CharSequence>>) { }
|
||||
|
||||
// Check the cases of nested arrays:
|
||||
fun invarInvarArrayList(l: List<Array<Array<CharSequence>>>) { }
|
||||
fun invarOutArrayList(l: List<Array<Array<out CharSequence>>>) { }
|
||||
fun invarInArrayList(l: List<Array<Array<in CharSequence>>>) { }
|
||||
fun outInvarArrayList(l: List<Array<out Array<CharSequence>>>) { }
|
||||
fun outOutArrayList(l: List<Array<out Array<out CharSequence>>>) { }
|
||||
fun outInArrayList(l: List<Array<out Array<in CharSequence>>>) { }
|
||||
fun inInvarArrayList(l: List<Array<in Array<CharSequence>>>) { }
|
||||
fun inOutArrayList(l: List<Array<in Array<out CharSequence>>>) { }
|
||||
fun inInArrayList(l: List<Array<in Array<in CharSequence>>>) { }
|
||||
|
||||
// Now check all of that again for Comparable, whose type parameter is contravariant:
|
||||
fun invarArrayComparable(c: Comparable<Array<CharSequence>>) { }
|
||||
fun outArrayComparable(c: Comparable<Array<out CharSequence>>) { }
|
||||
fun inArrayComparable(c: Comparable<Array<in CharSequence>>) { }
|
||||
|
||||
fun invarInvarArrayComparable(c: Comparable<Array<Array<CharSequence>>>) { }
|
||||
fun invarOutArrayComparable(c: Comparable<Array<Array<out CharSequence>>>) { }
|
||||
fun invarInArrayComparable(c: Comparable<Array<Array<in CharSequence>>>) { }
|
||||
fun outInvarArrayComparable(c: Comparable<Array<out Array<CharSequence>>>) { }
|
||||
fun outOutArrayComparable(c: Comparable<Array<out Array<out CharSequence>>>) { }
|
||||
fun outInArrayComparable(c: Comparable<Array<out Array<in CharSequence>>>) { }
|
||||
fun inInvarArrayComparable(c: Comparable<Array<in Array<CharSequence>>>) { }
|
||||
fun inOutArrayComparable(c: Comparable<Array<in Array<out CharSequence>>>) { }
|
||||
fun inInArrayComparable(c: Comparable<Array<in Array<in CharSequence>>>) { }
|
||||
|
||||
// ... duplicate all of that for a final array element (I choose String as a final type), which sometimes suppresses addition of `? extends ...`
|
||||
fun invarArrayListFinal(l: List<Array<String>>) { }
|
||||
fun outArrayListFinal(l: List<Array<out String>>) { }
|
||||
fun inArrayListFinal(l: List<Array<in String>>) { }
|
||||
|
||||
fun invarInvarArrayListFinal(l: List<Array<Array<String>>>) { }
|
||||
fun invarOutArrayListFinal(l: List<Array<Array<out String>>>) { }
|
||||
fun invarInArrayListFinal(l: List<Array<Array<in String>>>) { }
|
||||
fun outInvarArrayListFinal(l: List<Array<out Array<String>>>) { }
|
||||
fun outOutArrayListFinal(l: List<Array<out Array<out String>>>) { }
|
||||
fun outInArrayListFinal(l: List<Array<out Array<in String>>>) { }
|
||||
fun inInvarArrayListFinal(l: List<Array<in Array<String>>>) { }
|
||||
fun inOutArrayListFinal(l: List<Array<in Array<out String>>>) { }
|
||||
fun inInArrayListFinal(l: List<Array<in Array<in String>>>) { }
|
||||
|
||||
fun invarArrayComparableFinal(c: Comparable<Array<String>>) { }
|
||||
fun outArrayComparableFinal(c: Comparable<Array<out String>>) { }
|
||||
fun inArrayComparableFinal(c: Comparable<Array<in String>>) { }
|
||||
|
||||
fun invarInvarArrayComparableFinal(c: Comparable<Array<Array<String>>>) { }
|
||||
fun invarOutArrayComparableFinal(c: Comparable<Array<Array<out String>>>) { }
|
||||
fun invarInArrayComparableFinal(c: Comparable<Array<Array<in String>>>) { }
|
||||
fun outInvarArrayComparableFinal(c: Comparable<Array<out Array<String>>>) { }
|
||||
fun outOutArrayComparableFinal(c: Comparable<Array<out Array<out String>>>) { }
|
||||
fun outInArrayComparableFinal(c: Comparable<Array<out Array<in String>>>) { }
|
||||
fun inInvarArrayComparableFinal(c: Comparable<Array<in Array<String>>>) { }
|
||||
fun inOutArrayComparableFinal(c: Comparable<Array<in Array<out String>>>) { }
|
||||
fun inInArrayComparableFinal(c: Comparable<Array<in Array<in String>>>) { }
|
||||
|
||||
// ... and duplicate it once more with Any as the array element, which can suppress adding `? super ...`
|
||||
fun invarArrayListAny(l: List<Array<Any>>) { }
|
||||
fun outArrayListAny(l: List<Array<out Any>>) { }
|
||||
fun inArrayListAny(l: List<Array<in Any>>) { }
|
||||
|
||||
fun invarInvarArrayListAny(l: List<Array<Array<Any>>>) { }
|
||||
fun invarOutArrayListAny(l: List<Array<Array<out Any>>>) { }
|
||||
fun invarInArrayListAny(l: List<Array<Array<in Any>>>) { }
|
||||
fun outInvarArrayListAny(l: List<Array<out Array<Any>>>) { }
|
||||
fun outOutArrayListAny(l: List<Array<out Array<out Any>>>) { }
|
||||
fun outInArrayListAny(l: List<Array<out Array<in Any>>>) { }
|
||||
fun inInvarArrayListAny(l: List<Array<in Array<Any>>>) { }
|
||||
fun inOutArrayListAny(l: List<Array<in Array<out Any>>>) { }
|
||||
fun inInArrayListAny(l: List<Array<in Array<in Any>>>) { }
|
||||
|
||||
fun invarArrayComparableAny(c: Comparable<Array<Any>>) { }
|
||||
fun outArrayComparableAny(c: Comparable<Array<out Any>>) { }
|
||||
fun inArrayComparableAny(c: Comparable<Array<in Any>>) { }
|
||||
|
||||
fun invarInvarArrayComparableAny(c: Comparable<Array<Array<Any>>>) { }
|
||||
fun invarOutArrayComparableAny(c: Comparable<Array<Array<out Any>>>) { }
|
||||
fun invarInArrayComparableAny(c: Comparable<Array<Array<in Any>>>) { }
|
||||
fun outInvarArrayComparableAny(c: Comparable<Array<out Array<Any>>>) { }
|
||||
fun outOutArrayComparableAny(c: Comparable<Array<out Array<out Any>>>) { }
|
||||
fun outInArrayComparableAny(c: Comparable<Array<out Array<in Any>>>) { }
|
||||
fun inInvarArrayComparableAny(c: Comparable<Array<in Array<Any>>>) { }
|
||||
fun inOutArrayComparableAny(c: Comparable<Array<in Array<out Any>>>) { }
|
||||
fun inInArrayComparableAny(c: Comparable<Array<in Array<in Any>>>) { }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
broken
|
||||
#select
|
||||
| inArray | Object[] |
|
||||
| inArrayComparable | Comparable<? super Object[]> |
|
||||
| inArrayComparableAny | Comparable<? super Object[]> |
|
||||
| inArrayComparableFinal | Comparable<? super Object[]> |
|
||||
| inArrayList | List<? extends Object[]> |
|
||||
| inArrayListAny | List<Object[]> |
|
||||
| inArrayListFinal | List<? extends Object[]> |
|
||||
| inInArray | Object[] |
|
||||
| inInArrayComparable | Comparable<? super Object[]> |
|
||||
| inInArrayComparableAny | Comparable<? super Object[]> |
|
||||
| inInArrayComparableFinal | Comparable<? super Object[]> |
|
||||
| inInArrayList | List<? extends Object[]> |
|
||||
| inInArrayListAny | List<? extends Object[]> |
|
||||
| inInArrayListFinal | List<? extends Object[]> |
|
||||
| inInvarArray | Object[] |
|
||||
| inInvarArrayComparable | Comparable<? super Object[]> |
|
||||
| inInvarArrayComparableAny | Comparable<? super Object[]> |
|
||||
| inInvarArrayComparableFinal | Comparable<? super Object[]> |
|
||||
| inInvarArrayList | List<? extends Object[]> |
|
||||
| inInvarArrayListAny | List<? extends Object[]> |
|
||||
| inInvarArrayListFinal | List<? extends Object[]> |
|
||||
| inOutArray | Object[] |
|
||||
| inOutArrayComparable | Comparable<? super Object[]> |
|
||||
| inOutArrayComparableAny | Comparable<? super Object[]> |
|
||||
| inOutArrayComparableFinal | Comparable<? super Object[]> |
|
||||
| inOutArrayList | List<? extends Object[]> |
|
||||
| inOutArrayListAny | List<? extends Object[]> |
|
||||
| inOutArrayListFinal | List<? extends Object[]> |
|
||||
| invarArray | CharSequence[] |
|
||||
| invarArrayComparable | Comparable<? super CharSequence[]> |
|
||||
| invarArrayComparableAny | Comparable<? super Object[]> |
|
||||
| invarArrayComparableFinal | Comparable<? super String[]> |
|
||||
| invarArrayList | List<CharSequence[]> |
|
||||
| invarArrayListAny | List<Object[]> |
|
||||
| invarArrayListFinal | List<String[]> |
|
||||
| invarInArray | Object[][] |
|
||||
| invarInArrayComparable | Comparable<? super Object[][]> |
|
||||
| invarInArrayComparableAny | Comparable<? super Object[][]> |
|
||||
| invarInArrayComparableFinal | Comparable<? super Object[][]> |
|
||||
| invarInArrayList | List<Object[][]> |
|
||||
| invarInArrayListAny | List<Object[][]> |
|
||||
| invarInArrayListFinal | List<Object[][]> |
|
||||
| invarInvarArray | CharSequence[][] |
|
||||
| invarInvarArrayComparable | Comparable<? super CharSequence[][]> |
|
||||
| invarInvarArrayComparableAny | Comparable<? super Object[][]> |
|
||||
| invarInvarArrayComparableFinal | Comparable<? super String[][]> |
|
||||
| invarInvarArrayList | List<CharSequence[][]> |
|
||||
| invarInvarArrayListAny | List<Object[][]> |
|
||||
| invarInvarArrayListFinal | List<String[][]> |
|
||||
| invarOutArray | CharSequence[][] |
|
||||
| invarOutArrayComparable | Comparable<? super CharSequence[][]> |
|
||||
| invarOutArrayComparableAny | Comparable<? super Object[][]> |
|
||||
| invarOutArrayComparableFinal | Comparable<? super String[][]> |
|
||||
| invarOutArrayList | List<CharSequence[][]> |
|
||||
| invarOutArrayListAny | List<Object[][]> |
|
||||
| invarOutArrayListFinal | List<String[][]> |
|
||||
| outArray | CharSequence[] |
|
||||
| outArrayComparable | Comparable<? super CharSequence[]> |
|
||||
| outArrayComparableAny | Comparable<? super Object[]> |
|
||||
| outArrayComparableFinal | Comparable<? super String[]> |
|
||||
| outArrayList | List<? extends CharSequence[]> |
|
||||
| outArrayListAny | List<? extends Object[]> |
|
||||
| outArrayListFinal | List<String[]> |
|
||||
| outInArray | Object[][] |
|
||||
| outInArrayComparable | Comparable<? super Object[][]> |
|
||||
| outInArrayComparableAny | Comparable<? super Object[][]> |
|
||||
| outInArrayComparableFinal | Comparable<? super Object[][]> |
|
||||
| outInArrayList | List<? extends Object[][]> |
|
||||
| outInArrayListAny | List<Object[][]> |
|
||||
| outInArrayListFinal | List<? extends Object[][]> |
|
||||
| outInvarArray | CharSequence[][] |
|
||||
| outInvarArrayComparable | Comparable<? super CharSequence[][]> |
|
||||
| outInvarArrayComparableAny | Comparable<? super Object[][]> |
|
||||
| outInvarArrayComparableFinal | Comparable<? super String[][]> |
|
||||
| outInvarArrayList | List<CharSequence[][]> |
|
||||
| outInvarArrayListAny | List<Object[][]> |
|
||||
| outInvarArrayListFinal | List<String[][]> |
|
||||
| outOutArray | CharSequence[][] |
|
||||
| outOutArrayComparable | Comparable<? super CharSequence[][]> |
|
||||
| outOutArrayComparableAny | Comparable<? super Object[][]> |
|
||||
| outOutArrayComparableFinal | Comparable<? super String[][]> |
|
||||
| outOutArrayList | List<? extends CharSequence[][]> |
|
||||
| outOutArrayListAny | List<? extends Object[][]> |
|
||||
| outOutArrayListFinal | List<String[][]> |
|
||||
@@ -0,0 +1,13 @@
|
||||
import java
|
||||
|
||||
class InterestingMethod extends Method {
|
||||
InterestingMethod() { this.getDeclaringType().getName() = "TakesArrayList" }
|
||||
}
|
||||
|
||||
query predicate broken(string methodName) {
|
||||
methodName = any(InterestingMethod m).getName() and
|
||||
count(Type t, InterestingMethod m | methodName = m.getName() and t = m.getAParamType() | t) != 1
|
||||
}
|
||||
|
||||
from InterestingMethod m
|
||||
select m.getName(), m.getAParamType().toString()
|
||||
@@ -1,3 +1,53 @@
|
||||
enclosing
|
||||
| stmts.kt:3:5:6:5 | <Expr>; | stmts.kt:2:41:20:1 | { ... } |
|
||||
| stmts.kt:3:8:4:5 | ... -> ... | stmts.kt:3:5:6:5 | <Expr>; |
|
||||
| stmts.kt:3:15:4:5 | { ... } | stmts.kt:3:8:4:5 | ... -> ... |
|
||||
| stmts.kt:4:15:5:5 | ... -> ... | stmts.kt:3:5:6:5 | <Expr>; |
|
||||
| stmts.kt:4:22:5:5 | { ... } | stmts.kt:4:15:5:5 | ... -> ... |
|
||||
| stmts.kt:5:12:6:5 | ... -> ... | stmts.kt:3:5:6:5 | <Expr>; |
|
||||
| stmts.kt:5:12:6:5 | { ... } | stmts.kt:5:12:6:5 | ... -> ... |
|
||||
| stmts.kt:7:5:8:16 | while (...) | stmts.kt:2:41:20:1 | { ... } |
|
||||
| stmts.kt:8:9:8:16 | return ... | stmts.kt:7:5:8:16 | while (...) |
|
||||
| stmts.kt:9:5:11:5 | while (...) | stmts.kt:2:41:20:1 | { ... } |
|
||||
| stmts.kt:9:18:11:5 | { ... } | stmts.kt:9:5:11:5 | while (...) |
|
||||
| stmts.kt:10:9:10:16 | return ... | stmts.kt:9:18:11:5 | { ... } |
|
||||
| stmts.kt:12:5:14:18 | do ... while (...) | stmts.kt:12:5:14:18 | { ... } |
|
||||
| stmts.kt:12:5:14:18 | { ... } | stmts.kt:2:41:20:1 | { ... } |
|
||||
| stmts.kt:12:8:14:5 | { ... } | stmts.kt:12:5:14:18 | do ... while (...) |
|
||||
| stmts.kt:13:9:13:16 | return ... | stmts.kt:12:8:14:5 | { ... } |
|
||||
| stmts.kt:15:5:15:13 | var ...; | stmts.kt:2:41:20:1 | { ... } |
|
||||
| stmts.kt:17:5:17:58 | var ...; | stmts.kt:2:41:20:1 | { ... } |
|
||||
| stmts.kt:17:26:17:58 | ... -> ... | stmts.kt:17:5:17:58 | var ...; |
|
||||
| stmts.kt:17:26:17:58 | ... -> ... | stmts.kt:17:5:17:58 | var ...; |
|
||||
| stmts.kt:17:35:17:43 | { ... } | stmts.kt:17:26:17:58 | ... -> ... |
|
||||
| stmts.kt:17:37:17:37 | <Expr>; | stmts.kt:17:35:17:43 | { ... } |
|
||||
| stmts.kt:17:50:17:58 | { ... } | stmts.kt:17:26:17:58 | ... -> ... |
|
||||
| stmts.kt:17:52:17:52 | <Expr>; | stmts.kt:17:50:17:58 | { ... } |
|
||||
| stmts.kt:18:5:18:56 | var ...; | stmts.kt:2:41:20:1 | { ... } |
|
||||
| stmts.kt:18:26:18:56 | ... -> ... | stmts.kt:18:5:18:56 | var ...; |
|
||||
| stmts.kt:18:26:18:56 | ... -> ... | stmts.kt:18:5:18:56 | var ...; |
|
||||
| stmts.kt:18:37:18:37 | <Expr>; | stmts.kt:18:26:18:56 | ... -> ... |
|
||||
| stmts.kt:18:52:18:52 | <Expr>; | stmts.kt:18:26:18:56 | ... -> ... |
|
||||
| stmts.kt:19:5:19:16 | return ... | stmts.kt:2:41:20:1 | { ... } |
|
||||
| stmts.kt:23:11:27:5 | while (...) | stmts.kt:22:27:30:1 | { ... } |
|
||||
| stmts.kt:23:27:27:5 | { ... } | stmts.kt:23:11:27:5 | while (...) |
|
||||
| stmts.kt:24:9:26:25 | do ... while (...) | stmts.kt:24:9:26:25 | { ... } |
|
||||
| stmts.kt:24:9:26:25 | { ... } | stmts.kt:23:27:27:5 | { ... } |
|
||||
| stmts.kt:24:13:26:9 | { ... } | stmts.kt:24:9:26:25 | do ... while (...) |
|
||||
| stmts.kt:25:13:25:33 | ... -> ... | stmts.kt:25:13:25:33 | <Expr>; |
|
||||
| stmts.kt:25:13:25:33 | <Expr>; | stmts.kt:24:13:26:9 | { ... } |
|
||||
| stmts.kt:25:24:25:33 | break | stmts.kt:25:13:25:33 | ... -> ... |
|
||||
| stmts.kt:28:5:29:16 | while (...) | stmts.kt:22:27:30:1 | { ... } |
|
||||
| stmts.kt:29:9:29:16 | continue | stmts.kt:28:5:29:16 | while (...) |
|
||||
| stmts.kt:33:5:41:5 | try ... | stmts.kt:32:23:42:1 | { ... } |
|
||||
| stmts.kt:33:9:35:5 | { ... } | stmts.kt:33:5:41:5 | try ... |
|
||||
| stmts.kt:34:9:34:30 | throw ... | stmts.kt:33:9:35:5 | { ... } |
|
||||
| stmts.kt:36:5:38:5 | catch (...) | stmts.kt:33:5:41:5 | try ... |
|
||||
| stmts.kt:36:26:38:5 | { ... } | stmts.kt:36:5:38:5 | catch (...) |
|
||||
| stmts.kt:37:9:37:16 | return ... | stmts.kt:36:26:38:5 | { ... } |
|
||||
| stmts.kt:39:13:41:5 | { ... } | stmts.kt:33:5:41:5 | try ... |
|
||||
| stmts.kt:40:9:40:16 | return ... | stmts.kt:39:13:41:5 | { ... } |
|
||||
#select
|
||||
| stmts.kt:2:41:20:1 | { ... } | BlockStmt |
|
||||
| stmts.kt:3:5:6:5 | <Expr>; | ExprStmt |
|
||||
| stmts.kt:3:8:4:5 | ... -> ... | WhenBranch |
|
||||
|
||||
@@ -2,3 +2,5 @@ import java
|
||||
|
||||
from Stmt s
|
||||
select s, s.getPrimaryQlClasses()
|
||||
|
||||
query predicate enclosing(Stmt s, Stmt encl) { s.getEnclosingStmt() = encl }
|
||||
|
||||
@@ -2,10 +2,14 @@ import android.widget.EditText;
|
||||
|
||||
public class TestWidget {
|
||||
|
||||
private EditText source() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void sink(Object sink) {}
|
||||
|
||||
public void test(EditText t) {
|
||||
sink(t.getText().toString()); // $ hasTaintFlow
|
||||
public void test() {
|
||||
sink(source().getText().toString()); // $ hasTaintFlow
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import android.text.Editable
|
||||
|
||||
class TestWidgetKt {
|
||||
|
||||
fun source() : Editable? { return null }
|
||||
fun sink(sink : String) {}
|
||||
|
||||
fun test() {
|
||||
val t = source()
|
||||
sink(t.toString()); // $ hasTaintFlow
|
||||
|
||||
val t2 : Any? = source()
|
||||
sink(t2.toString()); // $ MISSING: hasTaintFlow
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/google-android-9.0.0
|
||||
//codeql-extractor-kotlin-options: ${testdir}/../../../../stubs/google-android-9.0.0
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
failures
|
||||
valueOf
|
||||
| TestWidgetKt.kt:10:16:10:25 | valueOf(...) |
|
||||
| TestWidgetKt.kt:13:17:13:26 | valueOf(...) |
|
||||
@@ -2,6 +2,6 @@ import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
class SourceTaintFlowConf extends DefaultTaintFlowConf {
|
||||
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
|
||||
query predicate valueOf(MethodAccess ma) {
|
||||
ma.getMethod().hasQualifiedName("java.lang", "String", "valueOf")
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ private import internal.FlowSummaryImplSpecific
|
||||
* ensuring that they are visible to the taint tracking / data flow library.
|
||||
*/
|
||||
private module Frameworks {
|
||||
/* TODO */
|
||||
private import codeql.swift.frameworks.StandardLibrary.String
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -344,11 +344,86 @@ private predicate elementSpec(
|
||||
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _)
|
||||
}
|
||||
|
||||
private string paramsStringPart(AbstractFunctionDecl c, int i) {
|
||||
i = -1 and result = "(" and exists(c)
|
||||
or
|
||||
exists(int n, string p | c.getParam(n).getType().toString() = p |
|
||||
i = 2 * n and result = p
|
||||
or
|
||||
i = 2 * n - 1 and result = "," and n != 0
|
||||
)
|
||||
or
|
||||
i = 2 * c.getNumberOfParams() and result = ")"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a parenthesized string containing all parameter types of this callable, separated by a comma.
|
||||
*
|
||||
* Returns the empty string if the callable has no parameters.
|
||||
* Parameter types are represented by their type erasure.
|
||||
*/
|
||||
cached
|
||||
string paramsString(AbstractFunctionDecl c) {
|
||||
result = concat(int i | | paramsStringPart(c, i) order by i)
|
||||
}
|
||||
|
||||
bindingset[func]
|
||||
predicate matchesSignature(AbstractFunctionDecl func, string signature) {
|
||||
signature = "" or
|
||||
paramsString(func) = signature
|
||||
}
|
||||
|
||||
private NominalType getDeclType(IterableDeclContext decl) {
|
||||
result = decl.(ClassDecl).getType()
|
||||
or
|
||||
result = decl.(StructDecl).getType()
|
||||
or
|
||||
result = getDeclType(decl.(ExtensionDecl).getExtendedTypeDecl())
|
||||
or
|
||||
result = decl.(EnumDecl).getType()
|
||||
or
|
||||
result = decl.(ProtocolDecl).getType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the element in module `namespace` that satisfies the following properties:
|
||||
* 1. If the element is a member of a class-like type, then the class-like type has name `type`
|
||||
* 2. If `subtypes = true` and the element is a member of a class-like type, then overrides of the element
|
||||
* are also returned.
|
||||
* 3. The element has name `name`
|
||||
* 4. If `signature` is non-empty, then the element has a list of parameter types described by `signature`.
|
||||
*
|
||||
* NOTE: `namespace` is currently not used (since we don't properly extract modules yet).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private Element interpretElement0(
|
||||
string namespace, string type, boolean subtypes, string name, string signature
|
||||
) {
|
||||
none() // TODO
|
||||
namespace = "" and // TODO: Fill out when we properly extract modules.
|
||||
(
|
||||
exists(AbstractFunctionDecl func |
|
||||
func.getName() = name and
|
||||
type = "" and
|
||||
matchesSignature(func, signature) and
|
||||
subtypes = false and
|
||||
not result instanceof MethodDecl and
|
||||
result = func
|
||||
)
|
||||
or
|
||||
exists(NominalType nomType, IterableDeclContext decl, MethodDecl method |
|
||||
method.getName() = name and
|
||||
method = decl.getAMember() and
|
||||
nomType.getName() = type and
|
||||
matchesSignature(method, signature) and
|
||||
result = method
|
||||
|
|
||||
subtypes = true and
|
||||
getDeclType(decl) = nomType.getADerivedType*()
|
||||
or
|
||||
subtypes = false and
|
||||
getDeclType(decl) = nomType
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the source/sink/summary element corresponding to the supplied parameters. */
|
||||
|
||||
18
swift/ql/lib/codeql/swift/dataflow/FlowSources.qll
Normal file
18
swift/ql/lib/codeql/swift/dataflow/FlowSources.qll
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Provides classes representing various flow sources for taint tracking.
|
||||
*/
|
||||
|
||||
private import ExternalFlow
|
||||
private import internal.DataFlowPublic
|
||||
|
||||
/** A data flow source of remote user input. */
|
||||
abstract class RemoteFlowSource extends Node {
|
||||
/** Gets a string that describes the type of this remote flow source. */
|
||||
abstract string getSourceType();
|
||||
}
|
||||
|
||||
private class ExternalRemoteFlowSource extends RemoteFlowSource {
|
||||
ExternalRemoteFlowSource() { sourceNode(this, "remote") }
|
||||
|
||||
override string getSourceType() { result = "external" }
|
||||
}
|
||||
@@ -181,6 +181,12 @@ class ParameterPosition extends TParameterPosition {
|
||||
|
||||
class PositionalParameterPosition extends ParameterPosition, TPositionalParameter {
|
||||
int getIndex() { this = TPositionalParameter(result) }
|
||||
|
||||
override string toString() { result = this.getIndex().toString() }
|
||||
}
|
||||
|
||||
class ThisParameterPosition extends ParameterPosition, TThisParameter {
|
||||
override string toString() { result = "this" }
|
||||
}
|
||||
|
||||
/** An argument position. */
|
||||
@@ -191,6 +197,12 @@ class ArgumentPosition extends TArgumentPosition {
|
||||
|
||||
class PositionalArgumentPosition extends ArgumentPosition, TPositionalArgument {
|
||||
int getIndex() { this = TPositionalArgument(result) }
|
||||
|
||||
override string toString() { result = this.getIndex().toString() }
|
||||
}
|
||||
|
||||
class ThisArgumentPosition extends ArgumentPosition, TThisArgument {
|
||||
override string toString() { result = "this" }
|
||||
}
|
||||
|
||||
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||
|
||||
@@ -17,7 +17,7 @@ class SummarizedCallableBase = AbstractFunctionDecl;
|
||||
DataFlowCallable inject(SummarizedCallable c) { result = TDataFlowFunc(c) }
|
||||
|
||||
/** Gets the parameter position of the instance parameter. */
|
||||
ArgumentPosition instanceParameterPosition() { none() } // disables implicit summary flow to `this` for callbacks
|
||||
ArgumentPosition instanceParameterPosition() { result instanceof ThisArgumentPosition }
|
||||
|
||||
/** Gets the synthesized summary data-flow node for the given values. */
|
||||
Node summaryNode(SummarizedCallable c, SummaryNodeState state) { result = TSummaryNode(c, state) }
|
||||
@@ -31,7 +31,7 @@ DataFlowType getContentType(Content c) { any() }
|
||||
/** Gets the return type of kind `rk` for callable `c`. */
|
||||
bindingset[c]
|
||||
DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) {
|
||||
any() // TODO
|
||||
any() // TODO once we have type pruning
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,7 +39,7 @@ DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) {
|
||||
* synthesized call that targets a callback of type `t`.
|
||||
*/
|
||||
DataFlowType getCallbackParameterType(DataFlowType t, ArgumentPosition pos) {
|
||||
none() // TODO
|
||||
any() // TODO once we have type pruning
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,7 +47,7 @@ DataFlowType getCallbackParameterType(DataFlowType t, ArgumentPosition pos) {
|
||||
* callback of type `t`.
|
||||
*/
|
||||
DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) {
|
||||
none() // TODO
|
||||
any() // TODO once we have type pruning
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,12 +97,12 @@ predicate sinkElement(Element e, string input, string kind, boolean generated) {
|
||||
/** Gets the summary component for specification component `c`, if any. */
|
||||
bindingset[c]
|
||||
SummaryComponent interpretComponentSpecific(AccessPathToken c) {
|
||||
none() // TODO
|
||||
none() // TODO once we have field flow
|
||||
}
|
||||
|
||||
/** Gets the textual representation of the content in the format used for flow summaries. */
|
||||
private string getContentSpecificCsv(Content c) {
|
||||
none() // TODO
|
||||
none() // TODO once we have field flow
|
||||
}
|
||||
|
||||
/** Gets the textual representation of a summary component in the format used for flow summaries. */
|
||||
@@ -117,14 +117,10 @@ string getComponentSpecificCsv(SummaryComponent sc) {
|
||||
}
|
||||
|
||||
/** Gets the textual representation of a parameter position in the format used for flow summaries. */
|
||||
string getParameterPositionCsv(ParameterPosition pos) {
|
||||
none() // TODO
|
||||
}
|
||||
string getParameterPositionCsv(ParameterPosition pos) { result = pos.toString() }
|
||||
|
||||
/** Gets the textual representation of an argument position in the format used for flow summaries. */
|
||||
string getArgumentPositionCsv(ArgumentPosition pos) {
|
||||
none() // TODO
|
||||
}
|
||||
string getArgumentPositionCsv(ArgumentPosition pos) { result = pos.toString() }
|
||||
|
||||
/** Holds if input specification component `c` needs a reference. */
|
||||
predicate inputNeedsReferenceSpecific(string c) { none() }
|
||||
@@ -187,11 +183,21 @@ predicate interpretInputSpecific(string c, InterpretNode mid, InterpretNode n) {
|
||||
/** Gets the argument position obtained by parsing `X` in `Parameter[X]`. */
|
||||
bindingset[s]
|
||||
ArgumentPosition parseParamBody(string s) {
|
||||
none() // TODO
|
||||
exists(int index | index = AccessPath::parseInt(s) |
|
||||
result.(PositionalArgumentPosition).getIndex() = index
|
||||
or
|
||||
index = -1 and
|
||||
result instanceof ThisArgumentPosition
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the parameter position obtained by parsing `X` in `Argument[X]`. */
|
||||
bindingset[s]
|
||||
ParameterPosition parseArgBody(string s) {
|
||||
none() // TODO
|
||||
exists(int index | index = AccessPath::parseInt(s) |
|
||||
result.(PositionalParameterPosition).getIndex() = index
|
||||
or
|
||||
index = -1 and
|
||||
result instanceof ThisParameterPosition
|
||||
)
|
||||
}
|
||||
|
||||
24
swift/ql/lib/codeql/swift/elements/decl/MethodDecl.qll
Normal file
24
swift/ql/lib/codeql/swift/elements/decl/MethodDecl.qll
Normal file
@@ -0,0 +1,24 @@
|
||||
private import swift
|
||||
|
||||
private Decl getAMember(IterableDeclContext ctx) {
|
||||
ctx.getAMember() = result
|
||||
or
|
||||
exists(VarDecl var |
|
||||
ctx.getAMember() = var and
|
||||
var.getAnAccessorDecl() = result
|
||||
)
|
||||
}
|
||||
|
||||
class MethodDecl extends AbstractFunctionDecl {
|
||||
MethodDecl() {
|
||||
this = getAMember(any(ClassDecl c))
|
||||
or
|
||||
this = getAMember(any(StructDecl c))
|
||||
or
|
||||
this = getAMember(any(ExtensionDecl c))
|
||||
or
|
||||
this = getAMember(any(EnumDecl c))
|
||||
or
|
||||
this = getAMember(any(ProtocolDecl c))
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
private import codeql.swift.generated.expr.ApplyExpr
|
||||
private import codeql.swift.elements.decl.FuncDecl
|
||||
private import codeql.swift.elements.decl.AbstractFunctionDecl
|
||||
private import codeql.swift.elements.expr.DeclRefExpr
|
||||
|
||||
class ApplyExpr extends ApplyExprBase {
|
||||
FuncDecl getStaticTarget() { result = this.getFunction().(DeclRefExpr).getDecl() }
|
||||
AbstractFunctionDecl getStaticTarget() { result = this.getFunction().(DeclRefExpr).getDecl() }
|
||||
|
||||
override string toString() {
|
||||
result = "call to " + this.getStaticTarget().toString()
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
|
||||
private import codeql.swift.generated.type.AnyGenericType
|
||||
private import codeql.swift.elements.decl.GenericTypeDecl
|
||||
|
||||
class AnyGenericType extends AnyGenericTypeBase { }
|
||||
class AnyGenericType extends AnyGenericTypeBase {
|
||||
string getName() { result = this.getDeclaration().(GenericTypeDecl).getName() }
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
|
||||
private import codeql.swift.generated.type.NominalType
|
||||
private import codeql.swift.elements.decl.NominalTypeDecl
|
||||
|
||||
class NominalType extends NominalTypeBase { }
|
||||
class NominalType extends NominalTypeBase {
|
||||
NominalType getABaseType() { result = this.getDeclaration().(NominalTypeDecl).getABaseType() }
|
||||
|
||||
NominalType getADerivedType() { result.getABaseType() = this }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import swift
|
||||
private import codeql.swift.dataflow.ExternalFlow
|
||||
|
||||
private class StringSource extends SourceModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
// String(contentsOf:) is a remote flow source
|
||||
";String;true;init(contentsOf:);(URL);;ReturnValue;remote"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -2,3 +2,4 @@
|
||||
|
||||
import codeql.swift.elements
|
||||
import codeql.swift.elements.expr.LogicalOperation
|
||||
import codeql.swift.elements.decl.MethodDecl
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* @name String length conflation
|
||||
* @description TODO
|
||||
* @kind problem
|
||||
* @problem.severity TODO
|
||||
* @security-severity TODO
|
||||
* @precision TODO
|
||||
* @id swift/string-length-conflation
|
||||
* @tags security
|
||||
* external/cwe/cwe-135
|
||||
*/
|
||||
|
||||
import swift
|
||||
|
||||
select "TODO"
|
||||
@@ -44,7 +44,7 @@
|
||||
| expressions.swift:21:6:21:16 | call to failure(_:) | CallExpr |
|
||||
| expressions.swift:21:14:21:14 | 11 | IntegerLiteralExpr |
|
||||
| expressions.swift:27:13:27:13 | Klass.Type | TypeExpr |
|
||||
| expressions.swift:27:13:27:13 | call to ... | ConstructorRefCallExpr |
|
||||
| expressions.swift:27:13:27:13 | call to init | ConstructorRefCallExpr |
|
||||
| expressions.swift:27:13:27:13 | init | DeclRefExpr |
|
||||
| expressions.swift:27:13:27:19 | call to ... | CallExpr |
|
||||
| expressions.swift:29:9:29:19 | [...] | DictionaryExpr |
|
||||
@@ -164,7 +164,7 @@
|
||||
| expressions.swift:79:11:79:11 | init | OtherConstructorDeclRefExpr |
|
||||
| expressions.swift:79:19:79:19 | 22 | IntegerLiteralExpr |
|
||||
| expressions.swift:83:15:83:15 | Derived.Type | TypeExpr |
|
||||
| expressions.swift:83:15:83:15 | call to ... | ConstructorRefCallExpr |
|
||||
| expressions.swift:83:15:83:15 | call to init | ConstructorRefCallExpr |
|
||||
| expressions.swift:83:15:83:15 | init | DeclRefExpr |
|
||||
| expressions.swift:83:15:83:23 | call to ... | CallExpr |
|
||||
| expressions.swift:84:1:84:1 | _ | DiscardAssignmentExpr |
|
||||
@@ -185,7 +185,7 @@
|
||||
| expressions.swift:92:14:92:55 | call to ... | CallExpr |
|
||||
| expressions.swift:92:24:92:24 | passRetained(_:) | DeclRefExpr |
|
||||
| expressions.swift:92:37:92:37 | ToPtr.Type | TypeExpr |
|
||||
| expressions.swift:92:37:92:37 | call to ... | ConstructorRefCallExpr |
|
||||
| expressions.swift:92:37:92:37 | call to init | ConstructorRefCallExpr |
|
||||
| expressions.swift:92:37:92:37 | init | DeclRefExpr |
|
||||
| expressions.swift:92:37:92:43 | call to ... | CallExpr |
|
||||
| expressions.swift:92:46:92:46 | toOpaque() | DeclRefExpr |
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
| main.swift:5:6:5:8 | ... .x | getBase: | main.swift:5:6:5:6 | (no string representation) | getName: | x |
|
||||
| main.swift:11:6:11:8 | ... .a | getBase: | main.swift:11:6:11:6 | (no string representation) | getName: | a |
|
||||
| main.swift:11:6:11:10 | ... .x | getBase: | main.swift:11:6:11:8 | ... .a | getName: | x |
|
||||
| unresolved_dot_expr.swift:5:6:5:8 | ... .x | getBase: | unresolved_dot_expr.swift:5:6:5:6 | (no string representation) | getName: | x |
|
||||
| unresolved_dot_expr.swift:11:6:11:8 | ... .a | getBase: | unresolved_dot_expr.swift:11:6:11:6 | (no string representation) | getName: | a |
|
||||
| unresolved_dot_expr.swift:11:6:11:10 | ... .x | getBase: | unresolved_dot_expr.swift:11:6:11:8 | ... .a | getName: | x |
|
||||
|
||||
@@ -13,15 +13,15 @@
|
||||
| types.swift:3:9:3:9 | call to +(_:_:) | (Int, Int) -> Int |
|
||||
| types.swift:3:11:3:11 | 10 | Int |
|
||||
| types.swift:7:16:7:16 | X.Type | X.Type |
|
||||
| types.swift:7:16:7:16 | call to ... | () -> X |
|
||||
| types.swift:7:16:7:16 | call to init | () -> X |
|
||||
| types.swift:7:16:7:16 | init | (X.Type) -> () -> X |
|
||||
| types.swift:7:16:7:18 | call to ... | X |
|
||||
| types.swift:13:17:13:17 | C.Type | C.Type |
|
||||
| types.swift:13:17:13:17 | call to ... | () -> C |
|
||||
| types.swift:13:17:13:17 | call to init | () -> C |
|
||||
| types.swift:13:17:13:17 | init | (C.Type) -> () -> C |
|
||||
| types.swift:13:17:13:19 | call to ... | C |
|
||||
| types.swift:14:22:14:24 | C.Nested.Type | C.Nested.Type |
|
||||
| types.swift:14:22:14:24 | call to ... | () -> C.Nested |
|
||||
| types.swift:14:22:14:24 | call to init | () -> C.Nested |
|
||||
| types.swift:14:22:14:31 | call to ... | C.Nested |
|
||||
| types.swift:14:24:14:24 | init | (C.Nested.Type) -> () -> C.Nested |
|
||||
| types.swift:17:10:17:10 | x | Int |
|
||||
|
||||
@@ -613,9 +613,9 @@ cfg.swift:
|
||||
#-----| match -> init
|
||||
|
||||
# 71| Int.Type
|
||||
#-----| -> call to ...
|
||||
#-----| -> call to init
|
||||
|
||||
# 71| call to ...
|
||||
# 71| call to init
|
||||
#-----| -> s
|
||||
|
||||
# 71| init
|
||||
@@ -903,9 +903,9 @@ cfg.swift:
|
||||
#-----| -> n1
|
||||
|
||||
# 110| C.Type
|
||||
#-----| -> call to ...
|
||||
#-----| -> call to init
|
||||
|
||||
# 110| call to ...
|
||||
# 110| call to init
|
||||
#-----| -> 42
|
||||
|
||||
# 110| init
|
||||
|
||||
@@ -148,8 +148,8 @@
|
||||
| declarations.swift:76:19:79:1 | { ... } | BraceStmt | declarations.swift:77:20:77:20 | x | ConcreteVarDecl |
|
||||
| declarations.swift:76:19:79:1 | { ... } | BraceStmt | declarations.swift:78:3:78:10 | return ... | ReturnStmt |
|
||||
| declarations.swift:77:4:77:4 | ZeroWrapper.Type | TypeExpr | declarations.swift:77:4:77:4 | FixedTypeRepr | FixedTypeRepr |
|
||||
| declarations.swift:77:4:77:4 | call to ... | CallExpr | declarations.swift:77:4:77:4 | call to ... | ConstructorRefCallExpr |
|
||||
| declarations.swift:77:4:77:4 | call to ... | ConstructorRefCallExpr | declarations.swift:77:4:77:4 | init | DeclRefExpr |
|
||||
| declarations.swift:77:4:77:4 | call to ... | CallExpr | declarations.swift:77:4:77:4 | call to init | ConstructorRefCallExpr |
|
||||
| declarations.swift:77:4:77:4 | call to init | ConstructorRefCallExpr | declarations.swift:77:4:77:4 | init | DeclRefExpr |
|
||||
| declarations.swift:77:16:77:23 | var ... = ... | PatternBindingDecl | declarations.swift:77:20:77:23 | ... as ... | TypedPattern |
|
||||
| declarations.swift:77:20:77:20 | ... as ... | TypedPattern | declarations.swift:77:20:77:20 | _x | NamedPattern |
|
||||
| declarations.swift:77:20:77:20 | get | AccessorDecl | declarations.swift:77:20:77:20 | { ... } | BraceStmt |
|
||||
@@ -414,8 +414,8 @@
|
||||
| expressions.swift:27:1:27:19 | { ... } | BraceStmt | expressions.swift:27:1:27:19 | var ... = ... | PatternBindingDecl |
|
||||
| expressions.swift:27:1:27:19 | { ... } | TopLevelCodeDecl | expressions.swift:27:1:27:19 | { ... } | BraceStmt |
|
||||
| expressions.swift:27:13:27:13 | Klass.Type | TypeExpr | expressions.swift:27:13:27:13 | SimpleIdentTypeRepr | SimpleIdentTypeRepr |
|
||||
| expressions.swift:27:13:27:13 | call to ... | ConstructorRefCallExpr | expressions.swift:27:13:27:13 | init | DeclRefExpr |
|
||||
| expressions.swift:27:13:27:19 | call to ... | CallExpr | expressions.swift:27:13:27:13 | call to ... | ConstructorRefCallExpr |
|
||||
| expressions.swift:27:13:27:13 | call to init | ConstructorRefCallExpr | expressions.swift:27:13:27:13 | init | DeclRefExpr |
|
||||
| expressions.swift:27:13:27:19 | call to ... | CallExpr | expressions.swift:27:13:27:13 | call to init | ConstructorRefCallExpr |
|
||||
| expressions.swift:29:1:29:19 | var ... = ... | PatternBindingDecl | expressions.swift:29:5:29:5 | d | NamedPattern |
|
||||
| expressions.swift:29:1:29:19 | var ... = ... | PatternBindingDecl | expressions.swift:29:9:29:19 | [...] | DictionaryExpr |
|
||||
| expressions.swift:29:1:29:19 | { ... } | BraceStmt | expressions.swift:29:1:29:19 | var ... = ... | PatternBindingDecl |
|
||||
@@ -578,8 +578,8 @@
|
||||
| expressions.swift:83:1:83:23 | { ... } | BraceStmt | expressions.swift:83:1:83:23 | var ... = ... | PatternBindingDecl |
|
||||
| expressions.swift:83:1:83:23 | { ... } | TopLevelCodeDecl | expressions.swift:83:1:83:23 | { ... } | BraceStmt |
|
||||
| expressions.swift:83:15:83:15 | Derived.Type | TypeExpr | expressions.swift:83:15:83:15 | SimpleIdentTypeRepr | SimpleIdentTypeRepr |
|
||||
| expressions.swift:83:15:83:15 | call to ... | ConstructorRefCallExpr | expressions.swift:83:15:83:15 | init | DeclRefExpr |
|
||||
| expressions.swift:83:15:83:23 | call to ... | CallExpr | expressions.swift:83:15:83:15 | call to ... | ConstructorRefCallExpr |
|
||||
| expressions.swift:83:15:83:15 | call to init | ConstructorRefCallExpr | expressions.swift:83:15:83:15 | init | DeclRefExpr |
|
||||
| expressions.swift:83:15:83:23 | call to ... | CallExpr | expressions.swift:83:15:83:15 | call to init | ConstructorRefCallExpr |
|
||||
| expressions.swift:84:1:84:13 | ... = ... | AssignExpr | expressions.swift:84:1:84:1 | _ | DiscardAssignmentExpr |
|
||||
| expressions.swift:84:1:84:13 | ... = ... | AssignExpr | expressions.swift:84:5:84:13 | .xx | MemberRefExpr |
|
||||
| expressions.swift:84:1:84:13 | { ... } | BraceStmt | expressions.swift:84:1:84:13 | ... = ... | AssignExpr |
|
||||
@@ -612,8 +612,8 @@
|
||||
| expressions.swift:92:14:92:46 | call to toOpaque() | DotSyntaxCallExpr | expressions.swift:92:46:92:46 | toOpaque() | DeclRefExpr |
|
||||
| expressions.swift:92:14:92:55 | call to ... | CallExpr | expressions.swift:92:14:92:46 | call to toOpaque() | DotSyntaxCallExpr |
|
||||
| expressions.swift:92:37:92:37 | ToPtr.Type | TypeExpr | expressions.swift:92:37:92:37 | SimpleIdentTypeRepr | SimpleIdentTypeRepr |
|
||||
| expressions.swift:92:37:92:37 | call to ... | ConstructorRefCallExpr | expressions.swift:92:37:92:37 | init | DeclRefExpr |
|
||||
| expressions.swift:92:37:92:43 | call to ... | CallExpr | expressions.swift:92:37:92:37 | call to ... | ConstructorRefCallExpr |
|
||||
| expressions.swift:92:37:92:37 | call to init | ConstructorRefCallExpr | expressions.swift:92:37:92:37 | init | DeclRefExpr |
|
||||
| expressions.swift:92:37:92:43 | call to ... | CallExpr | expressions.swift:92:37:92:37 | call to init | ConstructorRefCallExpr |
|
||||
| expressions.swift:93:1:93:16 | Unmanaged<ToPtr>.Type | TypeExpr | expressions.swift:93:1:93:16 | ...<...> | GenericIdentTypeRepr |
|
||||
| expressions.swift:93:1:93:18 | call to fromOpaque(_:) | DotSyntaxCallExpr | expressions.swift:93:18:93:18 | fromOpaque(_:) | DeclRefExpr |
|
||||
| expressions.swift:93:1:93:35 | call to ... | CallExpr | expressions.swift:93:1:93:18 | call to fromOpaque(_:) | DotSyntaxCallExpr |
|
||||
|
||||
@@ -2,5 +2,6 @@ name: codeql-swift-tests
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
codeql/swift-all: "*"
|
||||
codeql/swift-queries: "*"
|
||||
tests: .
|
||||
extractor: swift
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
| TODO |
|
||||
@@ -0,0 +1 @@
|
||||
queries/Security/CWE-135/StringLengthConflation.ql
|
||||
@@ -0,0 +1,125 @@
|
||||
|
||||
// --- stubs ---
|
||||
|
||||
func print(_ items: Any...) {}
|
||||
|
||||
typealias unichar = UInt16
|
||||
|
||||
class NSObject
|
||||
{
|
||||
}
|
||||
|
||||
class NSString : NSObject
|
||||
{
|
||||
init(string: String) { length = string.count }
|
||||
|
||||
func character(at: Int) -> unichar { return 0 }
|
||||
func substring(from: Int) -> String { return "" }
|
||||
func substring(to: Int) -> String { return "" }
|
||||
|
||||
private(set) var length: Int
|
||||
}
|
||||
|
||||
class NSMutableString : NSString
|
||||
{
|
||||
func insert(_: String, at: Int) {}
|
||||
}
|
||||
|
||||
class NSRange
|
||||
{
|
||||
init(location: Int, length: Int) { self.description = "" }
|
||||
|
||||
private(set) var description: String
|
||||
}
|
||||
|
||||
func NSMakeRange(_ loc: Int, _ len: Int) -> NSRange { return NSRange(location: loc, length: len) }
|
||||
|
||||
|
||||
|
||||
|
||||
// --- tests ---
|
||||
|
||||
func test(s: String) {
|
||||
let ns = NSString(string: s)
|
||||
let nms = NSMutableString(string: s)
|
||||
|
||||
print("'\(s)'")
|
||||
print("count \(s.count) length \(ns.length)")
|
||||
print("utf8.count \(s.utf8.count) utf16.count \(s.utf16.count) unicodeScalars.count \(s.unicodeScalars.count)")
|
||||
|
||||
// --- constructing a String.Index from integer ---
|
||||
|
||||
let ix1 = String.Index(encodedOffset: s.count) // GOOD
|
||||
let ix2 = String.Index(encodedOffset: ns.length) // BAD: NSString length used in String.Index
|
||||
let ix3 = String.Index(encodedOffset: s.utf8.count) // BAD: String.utf8 length used in String.Index
|
||||
let ix4 = String.Index(encodedOffset: s.utf16.count) // BAD: String.utf16 length used in String.Index
|
||||
let ix5 = String.Index(encodedOffset: s.unicodeScalars.count) // BAD: string.unicodeScalars length used in String.Index
|
||||
print("String.Index '\(ix1.encodedOffset)' / '\(ix2.encodedOffset)' '\(ix3.encodedOffset)' '\(ix4.encodedOffset)' '\(ix5.encodedOffset)'")
|
||||
|
||||
let ix6 = s.index(s.startIndex, offsetBy: s.count / 2) // GOOD
|
||||
let ix7 = s.index(s.startIndex, offsetBy: ns.length / 2) // BAD: NSString length used in String.Index
|
||||
print("index '\(ix6.encodedOffset)' / '\(ix7.encodedOffset)'")
|
||||
|
||||
var ix8 = s.startIndex
|
||||
s.formIndex(&ix8, offsetBy: s.count / 2) // GOOD
|
||||
var ix9 = s.startIndex
|
||||
s.formIndex(&ix9, offsetBy: ns.length / 2) // BAD: NSString length used in String.Index
|
||||
print("formIndex '\(ix8.encodedOffset)' / '\(ix9.encodedOffset)'")
|
||||
|
||||
// --- constructing an NSRange from integers ---
|
||||
|
||||
let range1 = NSMakeRange(0, ns.length) // GOOD
|
||||
let range2 = NSMakeRange(0, s.count) // BAD: String length used in NSMakeRange
|
||||
let range3 = NSMakeRange(0, s.reversed().count) // BAD: String length used in NSMakeRange
|
||||
let range4 = NSMakeRange(0, s.distance(from: s.startIndex, to: s.endIndex)) // BAD: String length used in NSMakeRange
|
||||
print("NSMakeRange '\(range1.description)' / '\(range2.description)' '\(range3.description)' '\(range4.description)'")
|
||||
|
||||
let range5 = NSRange(location: 0, length: ns.length) // GOOD
|
||||
let range6 = NSRange(location: 0, length: s.count) // BAD: String length used in NSMakeRange
|
||||
print("NSRange '\(range5.description)' / '\(range6.description)'")
|
||||
|
||||
// --- String operations using an integer directly ---
|
||||
|
||||
let str1 = s.dropFirst(s.count - 1) // GOOD
|
||||
let str2 = s.dropFirst(ns.length - 1) // BAD: NSString length used in String
|
||||
print("dropFirst '\(str1)' / '\(str2)'")
|
||||
|
||||
let str3 = s.dropLast(s.count - 1) // GOOD
|
||||
let str4 = s.dropLast(ns.length - 1) // BAD: NSString length used in String
|
||||
print("dropLast '\(str3)' / '\(str4)'")
|
||||
|
||||
let str5 = s.prefix(s.count - 1) // GOOD
|
||||
let str6 = s.prefix(ns.length - 1) // BAD: NSString length used in String
|
||||
print("prefix '\(str5)' / '\(str6)'")
|
||||
|
||||
let str7 = s.suffix(s.count - 1) // GOOD
|
||||
let str8 = s.suffix(ns.length - 1) // BAD: NSString length used in String
|
||||
print("suffix '\(str7)' / '\(str8)'")
|
||||
|
||||
let nstr1 = ns.character(at: ns.length - 1) // GOOD
|
||||
let nmstr1 = nms.character(at: nms.length - 1) // GOOD
|
||||
let nstr2 = ns.character(at: s.count - 1) // BAD: String length used in NSString
|
||||
let nmstr2 = nms.character(at: s.count - 1) // BAD: String length used in NString
|
||||
print("character '\(nstr1)' '\(nmstr1)' / '\(nstr2)' '\(nmstr2)'")
|
||||
|
||||
let nstr3 = ns.substring(from: ns.length - 1) // GOOD
|
||||
let nmstr3 = nms.substring(from: nms.length - 1) // GOOD
|
||||
let nstr4 = ns.substring(from: s.count - 1) // BAD: String length used in NSString
|
||||
let nmstr4 = nms.substring(from: s.count - 1) // BAD: String length used in NString
|
||||
print("substring from '\(nstr3)' '\(nmstr3)' / '\(nstr4)' '\(nmstr4)'")
|
||||
|
||||
let nstr5 = ns.substring(to: ns.length - 1) // GOOD
|
||||
let nmstr5 = nms.substring(to: nms.length - 1) // GOOD
|
||||
let nstr6 = ns.substring(to: s.count - 1) // BAD: String length used in NSString
|
||||
let nmstr6 = nms.substring(to: s.count - 1) // BAD: String length used in NString
|
||||
print("substring to '\(nstr5)' '\(nmstr5)' / '\(nstr6)' '\(nmstr6)'")
|
||||
|
||||
let nmstr7 = NSMutableString(string: s)
|
||||
nmstr7.insert("*", at: nms.length - 1) // GOOD
|
||||
let nmstr8 = NSMutableString(string: s)
|
||||
nmstr8.insert("*", at: s.count - 1) // BAD: String length used in NSString
|
||||
print("insert '\(nmstr7)' / '\(nmstr8)'")
|
||||
}
|
||||
|
||||
// `begin :thumbsup: end`, with thumbs up emoji and skin tone modifier
|
||||
test(s: "begin \u{0001F44D}\u{0001F3FF} end")
|
||||
Reference in New Issue
Block a user