Merge branch 'main' of https://github.com/github/codeql into oscarsj/merge-back-rc-3.21

This commit is contained in:
Óscar San José
2026-03-06 16:20:36 +01:00
846 changed files with 87321 additions and 58588 deletions

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Inline expectations test comments, which are of the form `# $ tag` or `# $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the `$` symbol.

View File

@@ -5,7 +5,7 @@ class SOURCE(object):
@staticmethod
def block_flow(): pass
check("SOURCE", SOURCE, SOURCE, globals()) #$ prints=SOURCE
check("SOURCE", SOURCE, SOURCE, globals()) # $ prints=SOURCE
SOURCE.block_flow()

View File

@@ -8,7 +8,7 @@ foo_attr = "foo_attr"
__private_foo_attr = "__private_foo_attr"
# A reexport of bar under a new name. Used in main.py
import bar as bar_reexported #$ imports=bar as=bar_reexported
check("bar_reexported.bar_attr", bar_reexported.bar_attr, "bar_attr", globals()) #$ prints=bar_attr
import bar as bar_reexported # $ imports=bar as=bar_reexported
check("bar_reexported.bar_attr", bar_reexported.bar_attr, "bar_attr", globals()) # $ prints=bar_attr
exit(__file__)

View File

@@ -5,7 +5,7 @@ class SOURCE(object):
@staticmethod
def block_flow(): pass
check("SOURCE", SOURCE, SOURCE, globals()) #$ prints=SOURCE
check("SOURCE", SOURCE, SOURCE, globals()) # $ prints=SOURCE
if eval("False"):
# With our current import resolution, this value for SOURCE will be considered to be

View File

@@ -14,6 +14,6 @@ else:
src.foo = 42
check("src", src, src, globals()) #$ prints=SOURCE
check("src", src, src, globals()) # $ prints=SOURCE
exit(__file__)

View File

@@ -24,76 +24,76 @@ from trace import *
enter(__file__)
# A simple import. Binds foo to the foo module
import foo #$ imports=foo as=foo
check("foo.foo_attr", foo.foo_attr, "foo_attr", globals()) #$ prints=foo_attr
import foo # $ imports=foo as=foo
check("foo.foo_attr", foo.foo_attr, "foo_attr", globals()) # $ prints=foo_attr
# Private attributes are still accessible.
check("foo.__private_foo_attr", foo.__private_foo_attr, "__private_foo_attr", globals()) #$ prints=__private_foo_attr
check("foo.__private_foo_attr", foo.__private_foo_attr, "__private_foo_attr", globals()) # $ prints=__private_foo_attr
# An aliased import, binding foo to foo_alias
import foo as foo_alias #$ imports=foo as=foo_alias
check("foo_alias.foo_attr", foo_alias.foo_attr, "foo_attr", globals()) #$ prints=foo_attr
import foo as foo_alias # $ imports=foo as=foo_alias
check("foo_alias.foo_attr", foo_alias.foo_attr, "foo_attr", globals()) # $ prints=foo_attr
# A reference to a reexported module
check("foo.bar_reexported", foo.bar_reexported, "<module bar>", globals()) #$ prints="<module bar>"
check("foo.bar_reexported.bar_attr", foo.bar_reexported.bar_attr, "bar_attr", globals()) #$ prints=bar_attr
check("foo.bar_reexported", foo.bar_reexported, "<module bar>", globals()) # $ prints="<module bar>"
check("foo.bar_reexported.bar_attr", foo.bar_reexported.bar_attr, "bar_attr", globals()) # $ prints=bar_attr
# A simple "import from" statement.
from bar import bar_attr
check("bar_attr", bar_attr, "bar_attr", globals()) #$ prints=bar_attr
check("bar_attr", bar_attr, "bar_attr", globals()) # $ prints=bar_attr
# Importing an attribute from a subpackage of a package.
from package.subpackage import subpackage_attr
check("subpackage_attr", subpackage_attr, "subpackage_attr", globals()) #$ prints=subpackage_attr
check("subpackage_attr", subpackage_attr, "subpackage_attr", globals()) # $ prints=subpackage_attr
# Importing a package attribute under an alias.
from package import package_attr as package_attr_alias
check("package_attr_alias", package_attr_alias, "package_attr", globals()) #$ prints=package_attr
check("package_attr_alias", package_attr_alias, "package_attr", globals()) # $ prints=package_attr
# Importing a subpackage under an alias.
from package import subpackage as aliased_subpackage #$ imports=package.subpackage.__init__ as=aliased_subpackage
check("aliased_subpackage.subpackage_attr", aliased_subpackage.subpackage_attr, "subpackage_attr", globals()) #$ prints=subpackage_attr
from package import subpackage as aliased_subpackage # $ imports=package.subpackage.__init__ as=aliased_subpackage
check("aliased_subpackage.subpackage_attr", aliased_subpackage.subpackage_attr, "subpackage_attr", globals()) # $ prints=subpackage_attr
def local_import():
# Same as above, but in a local scope.
import package.subpackage as local_subpackage #$ imports=package.subpackage.__init__ as=local_subpackage
check("local_subpackage.subpackage_attr", local_subpackage.subpackage_attr, "subpackage_attr", locals()) #$ prints=subpackage_attr
import package.subpackage as local_subpackage # $ imports=package.subpackage.__init__ as=local_subpackage
check("local_subpackage.subpackage_attr", local_subpackage.subpackage_attr, "subpackage_attr", locals()) # $ prints=subpackage_attr
local_import()
# Importing a subpacking using `import` and binding it to a name.
import package.subpackage as aliased_subpackage #$ imports=package.subpackage.__init__ as=aliased_subpackage
check("aliased_subpackage.subpackage_attr", aliased_subpackage.subpackage_attr, "subpackage_attr", globals()) #$ prints=subpackage_attr
import package.subpackage as aliased_subpackage # $ imports=package.subpackage.__init__ as=aliased_subpackage
check("aliased_subpackage.subpackage_attr", aliased_subpackage.subpackage_attr, "subpackage_attr", globals()) # $ prints=subpackage_attr
# Importing without binding instead binds the top level name.
import package.subpackage #$ imports=package.__init__ as=package
check("package.package_attr", package.package_attr, "package_attr", globals()) #$ prints=package_attr
import package.subpackage # $ imports=package.__init__ as=package
check("package.package_attr", package.package_attr, "package_attr", globals()) # $ prints=package_attr
# Deep imports
import package.subpackage.submodule #$ imports=package.__init__ as=package
check("package.subpackage.submodule.submodule_attr", package.subpackage.submodule.submodule_attr, "submodule_attr", globals()) #$ prints=submodule_attr
import package.subpackage.submodule # $ imports=package.__init__ as=package
check("package.subpackage.submodule.submodule_attr", package.subpackage.submodule.submodule_attr, "submodule_attr", globals()) # $ prints=submodule_attr
if sys.version_info[0] == 3:
# Importing from a namespace module.
from namespace_package.namespace_module import namespace_module_attr
check("namespace_module_attr", namespace_module_attr, "namespace_module_attr", globals()) #$ prints3=namespace_module_attr
check("namespace_module_attr", namespace_module_attr, "namespace_module_attr", globals()) # $ prints3=namespace_module_attr
from attr_clash import clashing_attr, non_clashing_submodule #$ imports=attr_clash.clashing_attr as=clashing_attr imports=attr_clash.non_clashing_submodule as=non_clashing_submodule
check("clashing_attr", clashing_attr, "clashing_attr", globals()) #$ prints=clashing_attr SPURIOUS: prints="<module attr_clash.clashing_attr>"
check("non_clashing_submodule", non_clashing_submodule, "<module attr_clash.non_clashing_submodule>", globals()) #$ prints="<module attr_clash.non_clashing_submodule>"
from attr_clash import clashing_attr, non_clashing_submodule # $ imports=attr_clash.clashing_attr as=clashing_attr imports=attr_clash.non_clashing_submodule as=non_clashing_submodule
check("clashing_attr", clashing_attr, "clashing_attr", globals()) # $ prints=clashing_attr SPURIOUS: prints="<module attr_clash.clashing_attr>"
check("non_clashing_submodule", non_clashing_submodule, "<module attr_clash.non_clashing_submodule>", globals()) # $ prints="<module attr_clash.non_clashing_submodule>"
import attr_clash.clashing_attr as _doesnt_matter #$ imports=attr_clash.clashing_attr as=_doesnt_matter
from attr_clash import clashing_attr, non_clashing_submodule #$ imports=attr_clash.clashing_attr as=clashing_attr imports=attr_clash.non_clashing_submodule as=non_clashing_submodule
check("clashing_attr", clashing_attr, "<module attr_clash.clashing_attr>", globals()) #$ prints="<module attr_clash.clashing_attr>" SPURIOUS: prints=clashing_attr
import attr_clash.clashing_attr as _doesnt_matter # $ imports=attr_clash.clashing_attr as=_doesnt_matter
from attr_clash import clashing_attr, non_clashing_submodule # $ imports=attr_clash.clashing_attr as=clashing_attr imports=attr_clash.non_clashing_submodule as=non_clashing_submodule
check("clashing_attr", clashing_attr, "<module attr_clash.clashing_attr>", globals()) # $ prints="<module attr_clash.clashing_attr>" SPURIOUS: prints=clashing_attr
# check that import * only imports the __all__ attributes
from has_defined_all import *
check("all_defined_foo", all_defined_foo, "all_defined_foo", globals()) #$ prints=all_defined_foo
check("all_defined_foo", all_defined_foo, "all_defined_foo", globals()) # $ prints=all_defined_foo
try:
check("all_defined_bar", all_defined_bar, "all_defined_bar", globals()) #$ SPURIOUS: prints=all_defined_bar
check("all_defined_bar", all_defined_bar, "all_defined_bar", globals()) # $ SPURIOUS: prints=all_defined_bar
raise Exception("Did not get expected NameError")
except NameError as e:
if "all_defined_bar" in str(e):
@@ -102,15 +102,15 @@ except NameError as e:
raise
import has_defined_all # $ imports=has_defined_all as=has_defined_all
check("has_defined_all.all_defined_foo", has_defined_all.all_defined_foo, "all_defined_foo", globals()) #$ prints=all_defined_foo
check("has_defined_all.all_defined_bar", has_defined_all.all_defined_bar, "all_defined_bar", globals()) #$ prints=all_defined_bar
check("has_defined_all.all_defined_foo", has_defined_all.all_defined_foo, "all_defined_foo", globals()) # $ prints=all_defined_foo
check("has_defined_all.all_defined_bar", has_defined_all.all_defined_bar, "all_defined_bar", globals()) # $ prints=all_defined_bar
# same check as above, but going through one level of indirection (which can make a difference)
from has_defined_all_indirection import *
check("all_defined_foo_copy", all_defined_foo_copy, "all_defined_foo_copy", globals()) #$ prints=all_defined_foo_copy
check("all_defined_foo_copy", all_defined_foo_copy, "all_defined_foo_copy", globals()) # $ prints=all_defined_foo_copy
try:
check("all_defined_bar_copy", all_defined_bar_copy, "all_defined_bar_copy", globals()) #$ SPURIOUS: prints=all_defined_bar_copy
check("all_defined_bar_copy", all_defined_bar_copy, "all_defined_bar_copy", globals()) # $ SPURIOUS: prints=all_defined_bar_copy
raise Exception("Did not get expected NameError")
except NameError as e:
if "all_defined_bar_copy" in str(e):
@@ -120,7 +120,7 @@ except NameError as e:
# same check as above, but going through one level of indirection (which can make a difference)
import has_defined_all_indirection # $ imports=has_defined_all_indirection as=has_defined_all_indirection
check("has_defined_all_indirection.all_defined_foo_copy", has_defined_all_indirection.all_defined_foo_copy, "all_defined_foo_copy", globals()) #$ prints=all_defined_foo_copy
check("has_defined_all_indirection.all_defined_foo_copy", has_defined_all_indirection.all_defined_foo_copy, "all_defined_foo_copy", globals()) # $ prints=all_defined_foo_copy
try:
check("has_defined_all_indirection.all_defined_bar_copy", has_defined_all_indirection.all_defined_bar_copy, "all_defined_bar_copy", globals())
@@ -133,30 +133,30 @@ except AttributeError as e:
# check that import * from an __init__ file works
from package.subpackage2 import *
check("subpackage2_attr", subpackage2_attr, "subpackage2_attr", globals()) #$ prints=subpackage2_attr
check("subpackage2_attr", subpackage2_attr, "subpackage2_attr", globals()) # $ prints=subpackage2_attr
# check that definitions from within if-then-else are found
from if_then_else import if_then_else_defined
check("if_then_else_defined", if_then_else_defined, "if_defined", globals()) #$ prints=if_defined prints=else_defined_1 prints=else_defined_2
check("if_then_else_defined", if_then_else_defined, "if_defined", globals()) # $ prints=if_defined prints=else_defined_1 prints=else_defined_2
# check that refined definitions are handled correctly
import refined # $ imports=refined as=refined
check("refined.SOURCE", refined.SOURCE, refined.SOURCE, globals()) #$ prints=SOURCE
check("refined.SOURCE", refined.SOURCE, refined.SOURCE, globals()) # $ prints=SOURCE
import if_then_else_refined # $ imports=if_then_else_refined as=if_then_else_refined
check("if_then_else_refined.src", if_then_else_refined.src, if_then_else_refined.src, globals()) #$ prints=SOURCE
check("if_then_else_refined.src", if_then_else_refined.src, if_then_else_refined.src, globals()) # $ prints=SOURCE
import simplistic_reexport # $ imports=simplistic_reexport as=simplistic_reexport
check("simplistic_reexport.bar_attr", simplistic_reexport.bar_attr, "overwritten", globals()) #$ prints=overwritten SPURIOUS: prints=bar_attr
check("simplistic_reexport.baz_attr", simplistic_reexport.baz_attr, "overwritten", globals()) #$ prints=overwritten SPURIOUS: prints=baz_attr
check("simplistic_reexport.bar_attr", simplistic_reexport.bar_attr, "overwritten", globals()) # $ prints=overwritten SPURIOUS: prints=bar_attr
check("simplistic_reexport.baz_attr", simplistic_reexport.baz_attr, "overwritten", globals()) # $ prints=overwritten SPURIOUS: prints=baz_attr
# check that we don't treat all assignments as being exports
import block_flow_check #$ imports=block_flow_check as=block_flow_check
import block_flow_check # $ imports=block_flow_check as=block_flow_check
check("block_flow_check.SOURCE", block_flow_check.SOURCE, block_flow_check.SOURCE, globals())
# show that import resolution is a bit too generous with definitions
import generous_export #$ imports=generous_export as=generous_export
check("generous_export.SOURCE", generous_export.SOURCE, generous_export.SOURCE, globals()) #$ SPURIOUS: prints=SOURCE
import generous_export # $ imports=generous_export as=generous_export
check("generous_export.SOURCE", generous_export.SOURCE, generous_export.SOURCE, globals()) # $ SPURIOUS: prints=SOURCE
exit(__file__)

View File

@@ -5,10 +5,10 @@ subpackage_attr = "subpackage_attr"
# Importing an attribute from the parent package.
from .. import attr_used_in_subpackage as imported_attr
check("imported_attr", imported_attr, "attr_used_in_subpackage", globals()) #$ prints=attr_used_in_subpackage
check("imported_attr", imported_attr, "attr_used_in_subpackage", globals()) # $ prints=attr_used_in_subpackage
# Importing an irrelevant attribute from a sibling module binds the name to the module.
from .submodule import irrelevant_attr
check("submodule.submodule_attr", submodule.submodule_attr, "submodule_attr", globals()) #$ MISSING:prints=submodule_attr
check("submodule.submodule_attr", submodule.submodule_attr, "submodule_attr", globals()) # $ MISSING:prints=submodule_attr
exit(__file__)

View File

@@ -3,12 +3,12 @@ enter(__file__)
class SOURCE(object): pass
check("SOURCE", SOURCE, SOURCE, globals()) #$ prints=SOURCE
check("SOURCE", SOURCE, SOURCE, globals()) # $ prints=SOURCE
SOURCE.foo = 42
SOURCE.bar = 43
SOURCE.baz = 44
check("SOURCE", SOURCE, SOURCE, globals()) #$ prints=SOURCE
check("SOURCE", SOURCE, SOURCE, globals()) # $ prints=SOURCE
exit(__file__)

View File

@@ -4,16 +4,16 @@ from trace import *
enter(__file__)
from bar import bar_attr
check("bar_attr", bar_attr, "bar_attr", globals()) #$ prints=bar_attr
check("bar_attr", bar_attr, "bar_attr", globals()) # $ prints=bar_attr
bar_attr = "overwritten"
check("bar_attr", bar_attr, "overwritten", globals()) #$ prints=overwritten
check("bar_attr", bar_attr, "overwritten", globals()) # $ prints=overwritten
from baz import *
check("baz_attr", baz_attr, "baz_attr", globals()) #$ MISSING: prints=baz_attr
check("baz_attr", baz_attr, "baz_attr", globals()) # $ MISSING: prints=baz_attr
baz_attr = "overwritten"
check("baz_attr", baz_attr, "overwritten", globals()) #$ prints=overwritten
check("baz_attr", baz_attr, "overwritten", globals()) # $ prints=overwritten
exit(__file__)

View File

@@ -3,7 +3,7 @@ class Foo:
pass
def test_parameter_annotation(x: Foo):
x.method() #$ tt=Foo.method
x.method() # $ tt=Foo.method
def test_no_parameter_annotation(x):
x.method()
@@ -12,21 +12,21 @@ def function_with_return_annotation() -> Foo:
return eval("Foo()")
def test_return_annotation():
x = function_with_return_annotation() #$ pt,tt=function_with_return_annotation
x.method() #$ tt=Foo.method
x = function_with_return_annotation() # $ pt,tt=function_with_return_annotation
x.method() # $ tt=Foo.method
def function_without_return_annotation():
return eval("Foo()")
def test_no_return_annotation():
x = function_without_return_annotation() #$ pt,tt=function_without_return_annotation
x = function_without_return_annotation() # $ pt,tt=function_without_return_annotation
x.method()
def test_variable_annotation():
x = eval("Foo()")
x : Foo
# Currently fails because there is no flow from the class definition to the type annotation.
x.method() #$ MISSING: tt=Foo.method
x.method() # $ MISSING: tt=Foo.method
def test_no_variable_annotation():
x = eval("Foo()")

View File

@@ -24,7 +24,7 @@ class A(Base):
self.bar() # $ pt,tt=A.bar
def not_called(self):
self.bar() #$ pt,tt=A.bar
self.bar() # $ pt,tt=A.bar
def bar(self):
print("A.bar")

View File

@@ -1,6 +1,6 @@
import requests
import shutil
import os
import os
from flask import Flask, request
app = Flask(__name__)
@@ -16,8 +16,8 @@ def download_from_url():
with open(tarpath, "wb") as f:
f.write(response.raw.read())
untarredpath = "/tmp/tmp123"
shutil.unpack_archive(tarpath, untarredpath) # $result=BAD
shutil.unpack_archive(tarpath, untarredpath) # $ result=BAD
# A source catching an S3 filename download
# see boto3: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.download_file
@@ -31,7 +31,7 @@ bucket_name = "mybucket"
s3 = boto3.client('s3')
s3.download_file(bucket_name, remote_ziped_name, local_ziped_path)
shutil.unpack_archive(local_ziped_path, base_dir) # $result=BAD
shutil.unpack_archive(local_ziped_path, base_dir) # $ result=BAD
# wget
@@ -45,11 +45,11 @@ base_dir = "/tmp/basedir"
# download(url, out, bar) contains out parameter
wget.download(url, compressed_file)
shutil.unpack_archive(compressed_file, base_dir) # $result=BAD
shutil.unpack_archive(compressed_file, base_dir) # $ result=BAD
# download(url) returns filename
compressed_file = wget.download(url)
shutil.unpack_archive(compressed_file, base_dir) # $result=BAD
shutil.unpack_archive(compressed_file, base_dir) # $ result=BAD
# A source coming from a CLI argparse module
@@ -63,7 +63,7 @@ parser.add_argument('filename', help='filename to be provided')
args = parser.parse_args()
compressed_file = args.filename
shutil.unpack_archive(compressed_file, base_dir) # $result=BAD
shutil.unpack_archive(compressed_file, base_dir) # $ result=BAD
# A source coming from a CLI and downloaded
@@ -83,8 +83,8 @@ response = requests.get(url_filename, stream=True)
tarpath = "/tmp/tmp456/tarball.tar.gz"
with open(tarpath, "wb") as f:
f.write(response.raw.read())
shutil.unpack_archive(tarpath, base_dir) # $result=BAD
shutil.unpack_archive(tarpath, base_dir) # $ result=BAD
# the django upload functionality
# see HttpRequest.FILES: https://docs.djangoproject.com/en/4.1/ref/request-response/#django.http.HttpRequest.FILES
@@ -97,19 +97,19 @@ def simple_upload(request):
base_dir = "/tmp/baase_dir"
if request.method == 'POST':
# Read uploaded files by chunks of data
# see chunks(): https://docs.djangoproject.com/en/4.1/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile.chunks
# see chunks(): https://docs.djangoproject.com/en/4.1/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile.chunks
savepath = os.path.join(base_dir, "tarball_compressed.tar.gz")
with open(savepath, 'wb+') as wfile:
for chunk in request.FILES["ufile1"].chunks():
wfile.write(chunk)
shutil.unpack_archive(savepath, base_dir) # $result=BAD
shutil.unpack_archive(savepath, base_dir) # $ result=BAD
# Write in binary the uploaded tarball
myfile = request.FILES.get("ufile1")
file_path = os.path.join(base_dir, "tarball.tar")
with file_path.open('wb') as f:
f.write(myfile.read())
shutil.unpack_archive(file_path, base_dir) # $result=BAD
shutil.unpack_archive(file_path, base_dir) # $ result=BAD
# Save uploaded files using FileSystemStorage Django API
# see FileSystemStorage: https://docs.djangoproject.com/en/4.1/ref/files/storage/#django.core.files.storage.FileSystemStorage
@@ -117,8 +117,8 @@ def simple_upload(request):
fs = FileSystemStorage()
filename = fs.save(ufile.name, ufile)
uploaded_file_path = fs.path(filename)
shutil.unpack_archive(uploaded_file_path, base_dir) # $result=BAD
shutil.unpack_archive(uploaded_file_path, base_dir) # $ result=BAD
return render(request, 'simple_upload.html')
elif request.method == 'GET':
@@ -126,7 +126,7 @@ def simple_upload(request):
import shutil
import os
import os
import tarfile
import tempfile
import argparse
@@ -139,8 +139,8 @@ parser.add_argument('filename', help='filename to be provided')
args = parser.parse_args()
unsafe_filename_tar = args.filename
with tarfile.TarFile(unsafe_filename_tar, mode="r") as tar:
tar.extractall(path="/tmp/unpack/", members=tar) # $result=BAD
tar = tarfile.open(unsafe_filename_tar)
tar.extractall(path="/tmp/unpack/", members=tar) # $ result=BAD
tar = tarfile.open(unsafe_filename_tar)
from django.shortcuts import render
@@ -152,7 +152,7 @@ def simple_upload(request):
base_dir = "/tmp/baase_dir"
if request.method == 'POST':
# Read uploaded files by chunks of data
# see chunks(): https://docs.djangoproject.com/en/4.1/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile.chunks
# see chunks(): https://docs.djangoproject.com/en/4.1/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile.chunks
savepath = os.path.join(base_dir, "tarball_compressed.tar.gz")
with open(savepath, 'wb+') as wfile:
for chunk in request.FILES["ufile1"].chunks():
@@ -160,11 +160,11 @@ def simple_upload(request):
tar = tarfile.open(savepath)
result = []
for member in tar:
if member.issym():
raise ValueError("But it is a symlink")
result.append(member)
tar.extractall(path=tempfile.mkdtemp(), members=result) # $result=BAD
for member in tar:
if member.issym():
raise ValueError("But it is a symlink")
result.append(member)
tar.extractall(path=tempfile.mkdtemp(), members=result) # $ result=BAD
tar.close()
@@ -173,7 +173,7 @@ tarpath = "/tmp/tmp456/tarball.tar.gz"
with open(tarpath, "wb") as f:
f.write(response.raw.read())
target_dir = "/tmp/unpack"
tarfile.TarFile(tarpath, mode="r").extractall(path=target_dir) # $result=BAD
tarfile.TarFile(tarpath, mode="r").extractall(path=target_dir) # $ result=BAD
from pathlib import Path
@@ -183,7 +183,7 @@ import boto3
def default_session() -> boto3.Session:
_SESSION = None
if _SESSION is None:
_SESSION = boto3.Session()
_SESSION = boto3.Session()
return _SESSION
cache = False
@@ -198,4 +198,4 @@ with tempfile.NamedTemporaryFile(suffix=".tar.gz") as tmp:
target = cache_dir
else:
target = Path(tempfile.mkdtemp())
shutil.unpack_archive(tmp.name, target) # $result=BAD
shutil.unpack_archive(tmp.name, target) # $ result=BAD

View File

@@ -6,7 +6,7 @@ app = Flask(__name__)
def get_input1():
input = request.args.get("input")
agent = Agent(name="Assistant", instructions="This prompt is customized for " + input) # $Alert[py/prompt-injection]
agent = Agent(name="Assistant", instructions="This prompt is customized for " + input) # $ Alert[py/prompt-injection]
result = Runner.run_sync(agent, "This is a user message.")
print(result.final_output)
@@ -22,9 +22,9 @@ def get_input2():
input=[
{
"role": "user",
"content": input, # $Alert[py/prompt-injection]
"content": input, # $ Alert[py/prompt-injection]
}
]
]
)
result2 = Runner.run_sync(
@@ -32,7 +32,7 @@ def get_input2():
[
{
"role": "user",
"content": input, # $Alert[py/prompt-injection]
"content": input, # $ Alert[py/prompt-injection]
}
]
]
)

View File

@@ -7,7 +7,7 @@ app = Flask(__name__)
@app.route("/unsafe1")
def unsafe1():
user_input = escape(request.args.get("ui"))
normalized_user_input = unicodedata.normalize("NFKC", user_input) # $result=BAD
normalized_user_input = unicodedata.normalize("NFKC", user_input) # $ result=BAD
return render_template("result.html", normalized_user_input=normalized_user_input)
@@ -17,7 +17,7 @@ def unsafe1bis():
if user_input.isascii():
normalized_user_input = user_input
else:
normalized_user_input = unicodedata.normalize("NFC", user_input) # $result=BAD
normalized_user_input = unicodedata.normalize("NFC", user_input) # $ result=BAD
return render_template("result.html", normalized_user_input=normalized_user_input)
@@ -25,6 +25,6 @@ def unsafe1bis():
def safe1():
normalized_user_input = unicodedata.normalize(
"NFKC", request.args.get("ui")
) # $result=OK
) # $ result=OK
user_input = escape(normalized_user_input)
return render_template("result.html", normalized_user_input=user_input)

View File

@@ -1,3 +1,3 @@
def python2_style():
from __builtin__ import open #$ use=moduleImport("builtins").getMember("open")
open("hello.txt") #$ use=moduleImport("builtins").getMember("open").getReturn()
from __builtin__ import open # $ use=moduleImport("builtins").getMember("open")
open("hello.txt") # $ use=moduleImport("builtins").getMember("open").getReturn()

View File

@@ -1,29 +1,29 @@
from mypkg import foo #$ use=moduleImport("mypkg").getMember("foo")
from mypkg import foo # $ use=moduleImport("mypkg").getMember("foo")
def callback(x): #$ use=moduleImport("mypkg").getMember("foo").getMember("bar").getParameter(0).getParameter(0)
x.baz() #$ use=moduleImport("mypkg").getMember("foo").getMember("bar").getParameter(0).getParameter(0).getMember("baz").getReturn()
def callback(x): # $ use=moduleImport("mypkg").getMember("foo").getMember("bar").getParameter(0).getParameter(0)
x.baz() # $ use=moduleImport("mypkg").getMember("foo").getMember("bar").getParameter(0).getParameter(0).getMember("baz").getReturn()
foo.bar(callback) #$ def=moduleImport("mypkg").getMember("foo").getMember("bar").getParameter(0) use=moduleImport("mypkg").getMember("foo").getMember("bar").getReturn()
foo.bar(callback) # $ def=moduleImport("mypkg").getMember("foo").getMember("bar").getParameter(0) use=moduleImport("mypkg").getMember("foo").getMember("bar").getReturn()
def callback2(x): #$ use=moduleImport("mypkg").getMember("foo").getMember("baz").getParameter(0).getASubscript().getParameter(0)
x.baz2() #$ use=moduleImport("mypkg").getMember("foo").getMember("baz").getParameter(0).getASubscript().getParameter(0).getMember("baz2").getReturn()
def callback2(x): # $ use=moduleImport("mypkg").getMember("foo").getMember("baz").getParameter(0).getASubscript().getParameter(0)
x.baz2() # $ use=moduleImport("mypkg").getMember("foo").getMember("baz").getParameter(0).getASubscript().getParameter(0).getMember("baz2").getReturn()
mydict = {
"c": callback2, #$ def=moduleImport("mypkg").getMember("foo").getMember("baz").getParameter(0).getASubscript()
"other": "whatever" #$ def=moduleImport("mypkg").getMember("foo").getMember("baz").getParameter(0).getASubscript()
"c": callback2, # $ def=moduleImport("mypkg").getMember("foo").getMember("baz").getParameter(0).getASubscript()
"other": "whatever" # $ def=moduleImport("mypkg").getMember("foo").getMember("baz").getParameter(0).getASubscript()
}
foo.baz(mydict) #$ def=moduleImport("mypkg").getMember("foo").getMember("baz").getParameter(0) use=moduleImport("mypkg").getMember("foo").getMember("baz").getReturn()
foo.baz(mydict) # $ def=moduleImport("mypkg").getMember("foo").getMember("baz").getParameter(0) use=moduleImport("mypkg").getMember("foo").getMember("baz").getReturn()
def callback3(x): #$ use=moduleImport("mypkg").getMember("foo").getMember("baz").getParameter(0).getMember("third").getParameter(0)
x.baz3() #$ use=moduleImport("mypkg").getMember("foo").getMember("baz").getParameter(0).getMember("third").getParameter(0).getMember("baz3").getReturn()
def callback3(x): # $ use=moduleImport("mypkg").getMember("foo").getMember("baz").getParameter(0).getMember("third").getParameter(0)
x.baz3() # $ use=moduleImport("mypkg").getMember("foo").getMember("baz").getParameter(0).getMember("third").getParameter(0).getMember("baz3").getReturn()
mydict.third = callback3 #$ def=moduleImport("mypkg").getMember("foo").getMember("baz").getParameter(0).getMember("third")
mydict.third = callback3 # $ def=moduleImport("mypkg").getMember("foo").getMember("baz").getParameter(0).getMember("third")
foo.blab(mydict) #$ def=moduleImport("mypkg").getMember("foo").getMember("blab").getParameter(0) use=moduleImport("mypkg").getMember("foo").getMember("blab").getReturn()
foo.blab(mydict) # $ def=moduleImport("mypkg").getMember("foo").getMember("blab").getParameter(0) use=moduleImport("mypkg").getMember("foo").getMember("blab").getReturn()
def callback4(x): #$ use=moduleImport("mypkg").getMember("foo").getMember("quack").getParameter(0).getParameter(0)
x.baz4() #$ use=moduleImport("mypkg").getMember("foo").getMember("quack").getParameter(0).getParameter(0).getMember("baz4").getReturn()
def callback4(x): # $ use=moduleImport("mypkg").getMember("foo").getMember("quack").getParameter(0).getParameter(0)
x.baz4() # $ use=moduleImport("mypkg").getMember("foo").getMember("quack").getParameter(0).getParameter(0).getMember("baz4").getReturn()
otherDict = {
# TODO: Backtracking through a property set using a dict doesn't work, but I can backtrack through explicit property writes, e.g. the `otherDict.fourth` below.
@@ -32,30 +32,30 @@ otherDict = {
}
otherDict.fourth = callback4
foo.quack(otherDict.fourth) #$ def=moduleImport("mypkg").getMember("foo").getMember("quack").getParameter(0) use=moduleImport("mypkg").getMember("foo").getMember("quack").getReturn()
foo.quack(otherDict.fourth) # $ def=moduleImport("mypkg").getMember("foo").getMember("quack").getParameter(0) use=moduleImport("mypkg").getMember("foo").getMember("quack").getReturn()
def namedCallback(myName, otherName):
# Using named parameters:
myName() #$ use=moduleImport("mypkg").getMember("foo").getMember("blob").getParameter(0).getKeywordParameter("myName").getReturn()
otherName() #$ use=moduleImport("mypkg").getMember("foo").getMember("blob").getParameter(0).getKeywordParameter("otherName").getReturn()
myName() # $ use=moduleImport("mypkg").getMember("foo").getMember("blob").getParameter(0).getKeywordParameter("myName").getReturn()
otherName() # $ use=moduleImport("mypkg").getMember("foo").getMember("blob").getParameter(0).getKeywordParameter("otherName").getReturn()
# Using numbered parameters:
myName() #$ use=moduleImport("mypkg").getMember("foo").getMember("blob").getParameter(0).getParameter(0).getReturn()
otherName() #$ use=moduleImport("mypkg").getMember("foo").getMember("blob").getParameter(0).getParameter(1).getReturn()
myName() # $ use=moduleImport("mypkg").getMember("foo").getMember("blob").getParameter(0).getParameter(0).getReturn()
otherName() # $ use=moduleImport("mypkg").getMember("foo").getMember("blob").getParameter(0).getParameter(1).getReturn()
foo.blob(namedCallback) #$ use=moduleImport("mypkg").getMember("foo").getMember("blob").getReturn()
foo.blob(namedCallback) # $ use=moduleImport("mypkg").getMember("foo").getMember("blob").getReturn()
foo.named(myName = 2) #$ def=moduleImport("mypkg").getMember("foo").getMember("named").getKeywordParameter("myName")
foo.named(myName = 2) # $ def=moduleImport("mypkg").getMember("foo").getMember("named").getKeywordParameter("myName")
def recusisionCallback(x):
x.recursion() #$ use=moduleImport("mypkg").getMember("foo").getMember("rec").getParameter(0).getMember("callback").getParameter(0).getMember("recursion").getReturn()
x.recursion() #$ use=moduleImport("mypkg").getMember("foo").getMember("rec").getParameter(0).getMember("rec1").getMember("callback").getParameter(0).getMember("recursion").getReturn()
x.recursion() #$ use=moduleImport("mypkg").getMember("foo").getMember("rec").getParameter(0).getMember("rec1").getMember("rec2").getMember("callback").getParameter(0).getMember("recursion").getReturn()
x.recursion() #$ use=moduleImport("mypkg").getMember("foo").getMember("rec").getParameter(0).getMember("rec1").getMember("rec2").getMember("rec1").getMember("callback").getParameter(0).getMember("recursion").getReturn()
x.recursion() # $ use=moduleImport("mypkg").getMember("foo").getMember("rec").getParameter(0).getMember("callback").getParameter(0).getMember("recursion").getReturn()
x.recursion() # $ use=moduleImport("mypkg").getMember("foo").getMember("rec").getParameter(0).getMember("rec1").getMember("callback").getParameter(0).getMember("recursion").getReturn()
x.recursion() # $ use=moduleImport("mypkg").getMember("foo").getMember("rec").getParameter(0).getMember("rec1").getMember("rec2").getMember("callback").getParameter(0).getMember("recursion").getReturn()
x.recursion() # $ use=moduleImport("mypkg").getMember("foo").getMember("rec").getParameter(0).getMember("rec1").getMember("rec2").getMember("rec1").getMember("callback").getParameter(0).getMember("recursion").getReturn()
recursiveDict = {};
recursiveDict.callback = recusisionCallback;
recursiveDict.rec1 = recursiveDict;
recursiveDict.rec2 = recursiveDict;
foo.rec(recursiveDict); #$ def=moduleImport("mypkg").getMember("foo").getMember("rec").getParameter(0)
foo.rec(recursiveDict); # $ def=moduleImport("mypkg").getMember("foo").getMember("rec").getParameter(0)

View File

@@ -1,22 +1,22 @@
# Subclasses
from flask.views import View #$ use=moduleImport("flask").getMember("views").getMember("View")
from flask.views import View # $ use=moduleImport("flask").getMember("views").getMember("View")
class MyView(View): #$ use=moduleImport("flask").getMember("views").getMember("View").getASubclass()
myvar = 45 #$ def=moduleImport("flask").getMember("views").getMember("View").getASubclass().getMember("myvar")
def my_method(self): #$ def=moduleImport("flask").getMember("views").getMember("View").getASubclass().getMember("my_method")
return 3 #$ def=moduleImport("flask").getMember("views").getMember("View").getASubclass().getMember("my_method").getReturn()
class MyView(View): # $ use=moduleImport("flask").getMember("views").getMember("View").getASubclass()
myvar = 45 # $ def=moduleImport("flask").getMember("views").getMember("View").getASubclass().getMember("myvar")
def my_method(self): # $ def=moduleImport("flask").getMember("views").getMember("View").getASubclass().getMember("my_method")
return 3 # $ def=moduleImport("flask").getMember("views").getMember("View").getASubclass().getMember("my_method").getReturn()
instance = MyView() #$ use=moduleImport("flask").getMember("views").getMember("View").getASubclass().getReturn()
instance = MyView() # $ use=moduleImport("flask").getMember("views").getMember("View").getASubclass().getReturn()
def internal():
from pflask.views import View #$ use=moduleImport("pflask").getMember("views").getMember("View")
class IntMyView(View): #$ use=moduleImport("pflask").getMember("views").getMember("View").getASubclass()
my_internal_var = 35 #$ def=moduleImport("pflask").getMember("views").getMember("View").getASubclass().getMember("my_internal_var")
def my_internal_method(self): #$ def=moduleImport("pflask").getMember("views").getMember("View").getASubclass().getMember("my_internal_method")
from pflask.views import View # $ use=moduleImport("pflask").getMember("views").getMember("View")
class IntMyView(View): # $ use=moduleImport("pflask").getMember("views").getMember("View").getASubclass()
my_internal_var = 35 # $ def=moduleImport("pflask").getMember("views").getMember("View").getASubclass().getMember("my_internal_var")
def my_internal_method(self): # $ def=moduleImport("pflask").getMember("views").getMember("View").getASubclass().getMember("my_internal_method")
pass
int_instance = IntMyView() #$ use=moduleImport("pflask").getMember("views").getMember("View").getASubclass().getReturn()
int_instance = IntMyView() # $ use=moduleImport("pflask").getMember("views").getMember("View").getASubclass().getReturn()
# ------------------------------------------------------------------------------
# Class decorator
@@ -27,8 +27,8 @@ def my_class_decorator(cls):
return cls
@my_class_decorator
class MyViewWithDecorator(View): #$ use=moduleImport("flask").getMember("views").getMember("View").getASubclass()
class MyViewWithDecorator(View): # $ use=moduleImport("flask").getMember("views").getMember("View").getASubclass()
pass
class SubclassFromDecorated(MyViewWithDecorator): #$ use=moduleImport("flask").getMember("views").getMember("View").getASubclass().getASubclass()
class SubclassFromDecorated(MyViewWithDecorator): # $ use=moduleImport("flask").getMember("views").getMember("View").getASubclass().getASubclass()
pass

View File

@@ -1,44 +1,44 @@
import a1 #$ use=moduleImport("a1")
import a1 # $ use=moduleImport("a1")
x = a1.blah1 #$ use=moduleImport("a1").getMember("blah1")
x = a1.blah1 # $ use=moduleImport("a1").getMember("blah1")
import a2 as m2 #$ use=moduleImport("a2")
import a2 as m2 # $ use=moduleImport("a2")
x2 = m2.blah2 #$ use=moduleImport("a2").getMember("blah2")
x2 = m2.blah2 # $ use=moduleImport("a2").getMember("blah2")
import a3.b3 as m3 #$ use=moduleImport("a3").getMember("b3")
import a3.b3 as m3 # $ use=moduleImport("a3").getMember("b3")
x3 = m3.blah3 #$ use=moduleImport("a3").getMember("b3").getMember("blah3")
x3 = m3.blah3 # $ use=moduleImport("a3").getMember("b3").getMember("blah3")
from a4.b4 import c4 as m4 #$ use=moduleImport("a4").getMember("b4").getMember("c4")
from a4.b4 import c4 as m4 # $ use=moduleImport("a4").getMember("b4").getMember("c4")
x4 = m4.blah4 #$ use=moduleImport("a4").getMember("b4").getMember("c4").getMember("blah4")
x4 = m4.blah4 # $ use=moduleImport("a4").getMember("b4").getMember("c4").getMember("blah4")
import a.b.c.d #$ use=moduleImport("a")
import a.b.c.d # $ use=moduleImport("a")
ab = a.b #$ use=moduleImport("a").getMember("b")
ab = a.b # $ use=moduleImport("a").getMember("b")
abc = ab.c #$ use=moduleImport("a").getMember("b").getMember("c")
abc = ab.c # $ use=moduleImport("a").getMember("b").getMember("c")
abcd = abc.d #$ use=moduleImport("a").getMember("b").getMember("c").getMember("d")
abcd = abc.d # $ use=moduleImport("a").getMember("b").getMember("c").getMember("d")
x5 = abcd.method() #$ use=moduleImport("a").getMember("b").getMember("c").getMember("d").getMember("method").getReturn()
x5 = abcd.method() # $ use=moduleImport("a").getMember("b").getMember("c").getMember("d").getMember("method").getReturn()
from a.b.c.d import method
x5_alt = method() #$ use=moduleImport("a").getMember("b").getMember("c").getMember("d").getMember("method").getReturn()
x5_alt = method() # $ use=moduleImport("a").getMember("b").getMember("c").getMember("d").getMember("method").getReturn()
from a6 import m6 #$ use=moduleImport("a6").getMember("m6")
from a6 import m6 # $ use=moduleImport("a6").getMember("m6")
x6 = m6().foo().bar() #$ use=moduleImport("a6").getMember("m6").getReturn().getMember("foo").getReturn().getMember("bar").getReturn()
x6 = m6().foo().bar() # $ use=moduleImport("a6").getMember("m6").getReturn().getMember("foo").getReturn().getMember("bar").getReturn()
import foo.baz.baz as fbb #$ use=moduleImport("foo").getMember("baz").getMember("baz")
from foo.bar.baz import quux as fbbq #$ use=moduleImport("foo").getMember("bar").getMember("baz").getMember("quux")
from ham.bar.eggs import spam as hbes #$ use=moduleImport("ham").getMember("bar").getMember("eggs").getMember("spam")
fbb.quux #$ use=moduleImport("foo").getMember("baz").getMember("baz").getMember("quux")
fbbq #$ use=moduleImport("foo").getMember("bar").getMember("baz").getMember("quux")
hbes #$ use=moduleImport("ham").getMember("bar").getMember("eggs").getMember("spam")
import foo.baz.baz as fbb # $ use=moduleImport("foo").getMember("baz").getMember("baz")
from foo.bar.baz import quux as fbbq # $ use=moduleImport("foo").getMember("bar").getMember("baz").getMember("quux")
from ham.bar.eggs import spam as hbes # $ use=moduleImport("ham").getMember("bar").getMember("eggs").getMember("spam")
fbb.quux # $ use=moduleImport("foo").getMember("baz").getMember("baz").getMember("quux")
fbbq # $ use=moduleImport("foo").getMember("bar").getMember("baz").getMember("quux")
hbes # $ use=moduleImport("ham").getMember("bar").getMember("eggs").getMember("spam")
import foo.bar.baz #$ use=moduleImport("foo")
import foo.bar.baz # $ use=moduleImport("foo")
# Relative imports. These are ignored
@@ -50,51 +50,51 @@ from ..foobar import baz
# Use of imports across scopes
def use_m4():
x = m4.blah4 #$ use=moduleImport("a4").getMember("b4").getMember("c4").getMember("blah4")
x = m4.blah4 # $ use=moduleImport("a4").getMember("b4").getMember("c4").getMember("blah4")
def local_import_use():
from foo import bar #$ use=moduleImport("foo").getMember("bar")
from foo import bar # $ use=moduleImport("foo").getMember("bar")
x = bar() #$ use=moduleImport("foo").getMember("bar").getReturn()
x = bar() # $ use=moduleImport("foo").getMember("bar").getReturn()
from eggs import ham as spam #$ use=moduleImport("eggs").getMember("ham")
from eggs import ham as spam # $ use=moduleImport("eggs").getMember("ham")
def bbb():
f = spam #$ use=moduleImport("eggs").getMember("ham")
f = spam # $ use=moduleImport("eggs").getMember("ham")
from danger import SOURCE #$ use=moduleImport("danger").getMember("SOURCE")
from danger import SOURCE # $ use=moduleImport("danger").getMember("SOURCE")
foo = SOURCE #$ use=moduleImport("danger").getMember("SOURCE")
foo = SOURCE # $ use=moduleImport("danger").getMember("SOURCE")
def change_foo():
global foo
foo = SOURCE #$ use=moduleImport("danger").getMember("SOURCE")
foo = SOURCE # $ use=moduleImport("danger").getMember("SOURCE")
def f():
global foo
sink(foo) #$ use=moduleImport("danger").getMember("SOURCE")
sink(foo) # $ use=moduleImport("danger").getMember("SOURCE")
foo = NONSOURCE
change_foo()
sink(foo) #$ use=moduleImport("danger").getMember("SOURCE")
sink(foo) # $ use=moduleImport("danger").getMember("SOURCE")
# Built-ins
def use_of_builtins():
for x in range(5): #$ use=moduleImport("builtins").getMember("range").getReturn()
if x < len([]): #$ use=moduleImport("builtins").getMember("len").getReturn()
print("Hello") #$ use=moduleImport("builtins").getMember("print").getReturn()
raise Exception("Farewell") #$ use=moduleImport("builtins").getMember("Exception").getReturn()
for x in range(5): # $ use=moduleImport("builtins").getMember("range").getReturn()
if x < len([]): # $ use=moduleImport("builtins").getMember("len").getReturn()
print("Hello") # $ use=moduleImport("builtins").getMember("print").getReturn()
raise Exception("Farewell") # $ use=moduleImport("builtins").getMember("Exception").getReturn()
def imported_builtins():
import builtins #$ use=moduleImport("builtins")
import builtins # $ use=moduleImport("builtins")
def open(f):
return builtins.open(f) #$ use=moduleImport("builtins").getMember("open").getReturn()
return builtins.open(f) # $ use=moduleImport("builtins").getMember("open").getReturn()
def redefine_print():
def my_print(x):
import builtins #$ use=moduleImport("builtins")
builtins.print("I'm printing", x) #$ use=moduleImport("builtins").getMember("print").getReturn()
import builtins # $ use=moduleImport("builtins")
builtins.print("I'm printing", x) # $ use=moduleImport("builtins").getMember("print").getReturn()
print = my_print
print("these words")
@@ -109,13 +109,13 @@ def global_redefine_chr():
def what_is_chr_now():
# If global_redefine_chr has been run, then the following is _not_ a reference to the built-in chr
return chr(123) #$ MISSING: use=moduleImport("builtins").getMember("chr").getReturn()
return chr(123) # $ MISSING: use=moduleImport("builtins").getMember("chr").getReturn()
def obscured_print():
p = print #$ use=moduleImport("builtins").getMember("print")
p("Can you see me?") #$ use=moduleImport("builtins").getMember("print").getReturn()
p = print # $ use=moduleImport("builtins").getMember("print")
p("Can you see me?") # $ use=moduleImport("builtins").getMember("print").getReturn()
def python2_style():
# In Python 3, `__builtin__` has no special meaning.
from __builtin__ import open #$ use=moduleImport("__builtin__").getMember("open")
open("hello.txt") #$ use=moduleImport("__builtin__").getMember("open").getReturn()
from __builtin__ import open # $ use=moduleImport("__builtin__").getMember("open")
open("hello.txt") # $ use=moduleImport("__builtin__").getMember("open").getReturn()

View File

@@ -1,6 +1,6 @@
import mypkg #$ use=moduleImport("mypkg")
print(mypkg.foo) #$ use=moduleImport("mypkg").getMember("foo") // 42
import mypkg # $ use=moduleImport("mypkg")
print(mypkg.foo) # $ use=moduleImport("mypkg").getMember("foo") // 42
try:
print(mypkg.bar) #$ use=moduleImport("mypkg").getMember("bar")
except AttributeError as e: #$ use=moduleImport("builtins").getMember("AttributeError")
print(e) #$ use=moduleImport("builtins").getMember("print").getReturn() // module 'mypkg' has no attribute 'bar'
print(mypkg.bar) # $ use=moduleImport("mypkg").getMember("bar")
except AttributeError as e: # $ use=moduleImport("builtins").getMember("AttributeError")
print(e) # $ use=moduleImport("builtins").getMember("print").getReturn() // module 'mypkg' has no attribute 'bar'

View File

@@ -1,4 +1,4 @@
from mypkg import foo #$ use=moduleImport("mypkg").getMember("foo")
from mypkg import bar #$ use=moduleImport("mypkg").getMember("bar")
print(foo) #$ use=moduleImport("mypkg").getMember("foo")
print(bar) #$ use=moduleImport("mypkg").getMember("bar")
from mypkg import foo # $ use=moduleImport("mypkg").getMember("foo")
from mypkg import bar # $ use=moduleImport("mypkg").getMember("bar")
print(foo) # $ use=moduleImport("mypkg").getMember("foo")
print(bar) # $ use=moduleImport("mypkg").getMember("bar")

View File

@@ -1,4 +1,4 @@
import mypkg.foo #$ use=moduleImport("mypkg")
import mypkg.bar #$ use=moduleImport("mypkg")
print(mypkg.foo) #$ use=moduleImport("mypkg").getMember("foo") // <module 'mypkg.foo' ...
print(mypkg.bar) #$ use=moduleImport("mypkg").getMember("bar") // <module 'mypkg.bar' ...
import mypkg.foo # $ use=moduleImport("mypkg")
import mypkg.bar # $ use=moduleImport("mypkg")
print(mypkg.foo) # $ use=moduleImport("mypkg").getMember("foo") // <module 'mypkg.foo' ...
print(mypkg.bar) # $ use=moduleImport("mypkg").getMember("bar") // <module 'mypkg.bar' ...

View File

@@ -1,4 +1,4 @@
import mypkg.foo as _foo #$ use=moduleImport("mypkg").getMember("foo")
import mypkg.bar as _bar #$ use=moduleImport("mypkg").getMember("bar")
print(_foo) #$ use=moduleImport("mypkg").getMember("foo") // <module 'mypkg.foo' ...
print(_bar) #$ use=moduleImport("mypkg").getMember("bar") // <module 'mypkg.bar' ...
import mypkg.foo as _foo # $ use=moduleImport("mypkg").getMember("foo")
import mypkg.bar as _bar # $ use=moduleImport("mypkg").getMember("bar")
print(_foo) # $ use=moduleImport("mypkg").getMember("foo") // <module 'mypkg.foo' ...
print(_bar) # $ use=moduleImport("mypkg").getMember("bar") // <module 'mypkg.bar' ...

View File

@@ -1,10 +1,10 @@
import mypkg #$ use=moduleImport("mypkg")
import mypkg # $ use=moduleImport("mypkg")
print(mypkg.foo) #$ use=moduleImport("mypkg").getMember("foo") // 42
print(mypkg.foo) # $ use=moduleImport("mypkg").getMember("foo") // 42
try:
print(mypkg.bar) #$ use=moduleImport("mypkg").getMember("bar")
except AttributeError as e: #$ use=moduleImport("builtins").getMember("AttributeError")
print(e) #$ use=moduleImport("builtins").getMember("print").getReturn() // module 'mypkg' has no attribute 'bar'
print(mypkg.bar) # $ use=moduleImport("mypkg").getMember("bar")
except AttributeError as e: # $ use=moduleImport("builtins").getMember("AttributeError")
print(e) # $ use=moduleImport("builtins").getMember("print").getReturn() // module 'mypkg' has no attribute 'bar'
from mypkg import bar as _bar #$ use=moduleImport("mypkg").getMember("bar")
print(mypkg.bar) #$ use=moduleImport("mypkg").getMember("bar") // <module 'mypkg.bar' ...
from mypkg import bar as _bar # $ use=moduleImport("mypkg").getMember("bar")
print(mypkg.bar) # $ use=moduleImport("mypkg").getMember("bar") // <module 'mypkg.bar' ...

View File

@@ -1,6 +1,6 @@
import mypkg #$ use=moduleImport("mypkg")
import mypkg # $ use=moduleImport("mypkg")
print(mypkg.foo) #$ use=moduleImport("mypkg").getMember("foo") // 42
print(mypkg.foo) # $ use=moduleImport("mypkg").getMember("foo") // 42
import mypkg.foo #$ use=moduleImport("mypkg")
print(mypkg.foo) #$ use=moduleImport("mypkg").getMember("foo") // <module 'mypkg.foo' ...
import mypkg.foo # $ use=moduleImport("mypkg")
print(mypkg.foo) # $ use=moduleImport("mypkg").getMember("foo") // <module 'mypkg.foo' ...

View File

@@ -1,10 +1,10 @@
from mypkg import foo #$ use=moduleImport("mypkg").getMember("foo")
from mypkg import foo # $ use=moduleImport("mypkg").getMember("foo")
print(foo) #$ use=moduleImport("mypkg").getMember("foo") // 42
print(foo) # $ use=moduleImport("mypkg").getMember("foo") // 42
import mypkg.foo #$ use=moduleImport("mypkg")
print(foo) #$ use=moduleImport("mypkg").getMember("foo") // 42
print(mypkg.foo) #$ use=moduleImport("mypkg").getMember("foo") // <module 'mypkg.foo' ...
import mypkg.foo # $ use=moduleImport("mypkg")
print(foo) # $ use=moduleImport("mypkg").getMember("foo") // 42
print(mypkg.foo) # $ use=moduleImport("mypkg").getMember("foo") // <module 'mypkg.foo' ...
from mypkg import foo #$ use=moduleImport("mypkg").getMember("foo")
print(foo) #$ use=moduleImport("mypkg").getMember("foo") // <module 'mypkg.foo' ...
from mypkg import foo # $ use=moduleImport("mypkg").getMember("foo")
print(foo) # $ use=moduleImport("mypkg").getMember("foo") // <module 'mypkg.foo' ...

View File

@@ -1,25 +1,25 @@
from types import AssignmentAnnotation, ParameterAnnotation
def test_annotated_assignment():
local_x : AssignmentAnnotation = create_x() #$ MISSING: use=moduleImport("types").getMember("AssignmentAnnotation")
local_x #$ MISSING: use=moduleImport("types").getMember("AssignmentAnnotation").getAnnotatedInstance()
local_x : AssignmentAnnotation = create_x() # $ MISSING: use=moduleImport("types").getMember("AssignmentAnnotation")
local_x # $ MISSING: use=moduleImport("types").getMember("AssignmentAnnotation").getAnnotatedInstance()
global_x : AssignmentAnnotation #$ use=moduleImport("types").getMember("AssignmentAnnotation")
global_x #$ MISSING: use=moduleImport("types").getMember("AssignmentAnnotation").getAnnotatedInstance()
global_x : AssignmentAnnotation # $ use=moduleImport("types").getMember("AssignmentAnnotation")
global_x # $ MISSING: use=moduleImport("types").getMember("AssignmentAnnotation").getAnnotatedInstance()
def test_parameter_annotation(parameter_y: ParameterAnnotation): #$ use=moduleImport("types").getMember("ParameterAnnotation")
parameter_y #$ use=moduleImport("types").getMember("ParameterAnnotation").getAnnotatedInstance()
def test_parameter_annotation(parameter_y: ParameterAnnotation): # $ use=moduleImport("types").getMember("ParameterAnnotation")
parameter_y # $ use=moduleImport("types").getMember("ParameterAnnotation").getAnnotatedInstance()
type Alias = AssignmentAnnotation
global_z : Alias #$ MISSING: use=moduleImport("types").getMember("AssignmentAnnotation")
global_z #$ MISSING: use=moduleImport("types").getMember("AssignmentAnnotation").getAnnotatedInstance()
global_z : Alias # $ MISSING: use=moduleImport("types").getMember("AssignmentAnnotation")
global_z # $ MISSING: use=moduleImport("types").getMember("AssignmentAnnotation").getAnnotatedInstance()
def test_parameter_alias(parameter_z: Alias): #$ MISSING: use=moduleImport("types").getMember("AssignmentAnnotation")
parameter_z #$ MISSING: use=moduleImport("types").getMember("AssignmentAnnotation").getAnnotatedInstance()
def test_parameter_alias(parameter_z: Alias): # $ MISSING: use=moduleImport("types").getMember("AssignmentAnnotation")
parameter_z # $ MISSING: use=moduleImport("types").getMember("AssignmentAnnotation").getAnnotatedInstance()
# local type aliases
def test_local_type_alias():
type LocalAlias = AssignmentAnnotation
local_alias : LocalAlias = create_value() #$ MISSING: use=moduleImport("types").getMember("AssignmentAnnotation")
local_alias #$ MISSING: use=moduleImport("types").getMember("AssignmentAnnotation").getAnnotatedInstance()
local_alias : LocalAlias = create_value() # $ MISSING: use=moduleImport("types").getMember("AssignmentAnnotation")
local_alias # $ MISSING: use=moduleImport("types").getMember("AssignmentAnnotation").getAnnotatedInstance()

View File

@@ -1,14 +1,14 @@
from html import escape
def p(x):
return escape(x) #$ use=moduleImport("html").getMember("escape").getReturn()
return escape(x) # $ use=moduleImport("html").getMember("escape").getReturn()
def p_list(l):
return ", ".join(p(x) for x in l) #$ use=moduleImport("html").getMember("escape").getReturn()
return ", ".join(p(x) for x in l) # $ use=moduleImport("html").getMember("escape").getReturn()
def pp_list(l):
def pp(x):
return escape(x) #$ use=moduleImport("html").getMember("escape").getReturn()
return escape(x) # $ use=moduleImport("html").getMember("escape").getReturn()
def pp_list_inner(l):
return ", ".join(pp(x) for x in l) #$ use=moduleImport("html").getMember("escape").getReturn()
return ", ".join(pp(x) for x in l) # $ use=moduleImport("html").getMember("escape").getReturn()

View File

@@ -4,11 +4,11 @@ from flask_user import UserMixin
def create_app():
app = Flask(__name__)
db = SQLAlchemy(app) #$ use=moduleImport("flask_sqlalchemy").getMember("SQLAlchemy").getReturn()
db = SQLAlchemy(app) # $ use=moduleImport("flask_sqlalchemy").getMember("SQLAlchemy").getReturn()
class Users(db.Model, UserMixin): #$ use=moduleImport("flask_sqlalchemy").getMember("SQLAlchemy").getReturn().getMember("Model").getASubclass()
class Users(db.Model, UserMixin): # $ use=moduleImport("flask_sqlalchemy").getMember("SQLAlchemy").getReturn().getMember("Model").getASubclass()
__tablename__ = 'users'
@app.route('/v2/user/<int:id>', methods=['GET','PUT'])
def users(id):
Users.query.filter_by(id=id).first() #$ use=moduleImport("flask_sqlalchemy").getMember("SQLAlchemy").getReturn().getMember("Model").getASubclass().getMember("query").getMember("filter_by")
Users.query.filter_by(id=id).first() # $ use=moduleImport("flask_sqlalchemy").getMember("SQLAlchemy").getReturn().getMember("Model").getASubclass().getMember("query").getMember("filter_by")

View File

@@ -10,17 +10,17 @@ def func():
class Bar(B): pass
class Baz(A): pass
def other_func():
print(Foo) #$ use=moduleImport("foo").getMember("A").getASubclass() use=moduleImport("foo").getMember("B").getASubclass()
print(Foo) # $ use=moduleImport("foo").getMember("A").getASubclass() use=moduleImport("foo").getMember("B").getASubclass()
# On the next line, we wish to express that it is not possible for `Bar` to be a subclass of `A`.
# However, we have no "true negative" annotation, so we use the MISSING annotation instead.
# (Normally, "true negative" is not needed as all applicable annotations must be present,
# but these API graph tests work differently, since having all results recorded in annotations
# but these API graph tests work differently, since having all results recorded in annotations
# would be excessive)
print(Bar) #$ use=moduleImport("foo").getMember("B").getASubclass() MISSING: use=moduleImport("foo").getMember("A").getASubclass()
print(Baz) #$ use=moduleImport("foo").getMember("B").getASubclass() SPURIOUS: use=moduleImport("foo").getMember("A").getASubclass()
print(Bar) # $ use=moduleImport("foo").getMember("B").getASubclass() MISSING: use=moduleImport("foo").getMember("A").getASubclass()
print(Baz) # $ use=moduleImport("foo").getMember("B").getASubclass() SPURIOUS: use=moduleImport("foo").getMember("A").getASubclass()
class Baz(B): pass
other_func()
other_func()

View File

@@ -1,4 +1,4 @@
from start.middle.end import foo #$ use=moduleImport("start").getMember("middle").getMember("end").getMember("foo")
from start.middle.end import bar #$ use=moduleImport("start").getMember("middle").getMember("end").getMember("bar")
print(foo) #$ use=moduleImport("start").getMember("middle").getMember("end").getMember("foo")
print(bar) #$ use=moduleImport("start").getMember("middle").getMember("end").getMember("bar")
from start.middle.end import foo # $ use=moduleImport("start").getMember("middle").getMember("end").getMember("foo")
from start.middle.end import bar # $ use=moduleImport("start").getMember("middle").getMember("end").getMember("bar")
print(foo) # $ use=moduleImport("start").getMember("middle").getMember("end").getMember("foo")
print(bar) # $ use=moduleImport("start").getMember("middle").getMember("end").getMember("bar")

View File

@@ -1,2 +1,2 @@
"magic_string".foo.bar #$ use=entryPoint("CustomEntryPoint").getMember("foo").getMember("bar")
"magic_string".foo.bar # $ use=entryPoint("CustomEntryPoint").getMember("foo").getMember("bar")
"magic_string2".foo.bar

View File

@@ -1,12 +1,12 @@
# Star imports
from unknown import * #$ use=moduleImport("unknown")
from unknown import * # $ use=moduleImport("unknown")
# This used to be missing, as we did not consider `hello` to be a `LocalSourceNode`,
# since it has flow going into it from its corresponding `GlobalSsaVariable`.
hello() #$ use=moduleImport("unknown").getMember("hello").getReturn()
hello() # $ use=moduleImport("unknown").getMember("hello").getReturn()
print(const_from_unknown) #$ use=moduleImport("unknown").getMember("const_from_unknown")
print(const_from_unknown) # $ use=moduleImport("unknown").getMember("const_from_unknown")
# We don't want our analysis to think that either `non_module_member` or `outer_bar` can
# come from `from unknown import *`
@@ -16,23 +16,23 @@ outer_bar = 5
outer_bar
def foo():
world() #$ use=moduleImport("unknown").getMember("world").getReturn()
world() # $ use=moduleImport("unknown").getMember("world").getReturn()
bar = 5
bar
non_module_member
print(bar) #$ use=moduleImport("builtins").getMember("print").getReturn()
print(bar) # $ use=moduleImport("builtins").getMember("print").getReturn()
def quux():
global non_module_member
non_module_member = 5
def func1():
var() #$ use=moduleImport("unknown").getMember("var").getReturn()
var() # $ use=moduleImport("unknown").getMember("var").getReturn()
def func2():
var = "FOO"
def func3():
var2 = print #$ use=moduleImport("builtins").getMember("print")
var2 = print # $ use=moduleImport("builtins").getMember("print")
def func4():
var2() #$ use=moduleImport("builtins").getMember("print").getReturn()
var2() # $ use=moduleImport("builtins").getMember("print").getReturn()
func4()

View File

@@ -1,14 +1,14 @@
# Star imports in local scope
hello2()
hello2()
def foo():
from unknown2 import * #$ use=moduleImport("unknown2")
world2() #$ use=moduleImport("unknown2").getMember("world2").getReturn()
from unknown2 import * # $ use=moduleImport("unknown2")
world2() # $ use=moduleImport("unknown2").getMember("world2").getReturn()
bar2 = 5
bar2
non_module_member2
print(bar2) #$ use=moduleImport("builtins").getMember("print").getReturn()
print(bar2) # $ use=moduleImport("builtins").getMember("print").getReturn()
def quux2():
global non_module_member2

View File

@@ -1,8 +1,8 @@
import mypkg
def test_subscript():
bar = mypkg.foo()["bar"] #$ use=moduleImport("mypkg").getMember("foo").getReturn().getASubscript()
mypkg.foo()["baz"] = 42 #$ def=moduleImport("mypkg").getMember("foo").getReturn().getASubscript()
mypkg.foo()["qux"] += 42 #$ use=moduleImport("mypkg").getMember("foo").getReturn().getASubscript()
mypkg.foo()["qux"] += 42 #$ def=moduleImport("mypkg").getMember("foo").getReturn().getASubscript()
mypkg.foo()[mypkg.index] = mypkg.value #$ def=moduleImport("mypkg").getMember("foo").getReturn().getASubscript()
bar = mypkg.foo()["bar"] # $ use=moduleImport("mypkg").getMember("foo").getReturn().getASubscript()
mypkg.foo()["baz"] = 42 # $ def=moduleImport("mypkg").getMember("foo").getReturn().getASubscript()
mypkg.foo()["qux"] += 42 # $ use=moduleImport("mypkg").getMember("foo").getReturn().getASubscript()
mypkg.foo()["qux"] += 42 # $ def=moduleImport("mypkg").getMember("foo").getReturn().getASubscript()
mypkg.foo()[mypkg.index] = mypkg.value # $ def=moduleImport("mypkg").getMember("foo").getReturn().getASubscript()

View File

@@ -1,7 +1,7 @@
def obfuscated_id(x): #$ step="FunctionExpr -> obfuscated_id"
y = x #$ step="x -> y" step="x, l:-1 -> x"
z = y #$ step="y -> z" step="y, l:-1 -> y"
return z #$ flow="42, l:+2 -> z" step="z, l:-1 -> z"
def obfuscated_id(x): # $ step="FunctionExpr -> obfuscated_id"
y = x # $ step="x -> y" step="x, l:-1 -> x"
z = y # $ step="y -> z" step="y, l:-1 -> y"
return z # $ flow="42, l:+2 -> z" step="z, l:-1 -> z"
a = 42 #$ step="42 -> a"
b = obfuscated_id(a) #$ flow="42, l:-1 -> b" flow="FunctionExpr, l:-6 -> obfuscated_id" step="obfuscated_id(..) -> b" step="obfuscated_id, l:-6 -> obfuscated_id" step="a, l:-1 -> a"
a = 42 # $ step="42 -> a"
b = obfuscated_id(a) # $ flow="42, l:-1 -> b" flow="FunctionExpr, l:-6 -> obfuscated_id" step="obfuscated_id(..) -> b" step="obfuscated_id, l:-6 -> obfuscated_id" step="a, l:-1 -> a"

View File

@@ -50,5 +50,5 @@ class With_index:
def test_index():
import operator
with_index = With_index() #$ MISSING: arg1="SSA variable with_index" func=With_index.__index__
with_index = With_index() # $ MISSING: arg1="SSA variable with_index" func=With_index.__index__
operator.index(with_index)

View File

@@ -1,4 +1,4 @@
| classes.py:54:44:54:107 | Comment #$ arg1="with_length_hint" func=With_length_hint.__length_hint__ | Missing result: arg1="with_length_hint" |
| classes.py:54:44:54:107 | Comment #$ arg1="with_length_hint" func=With_length_hint.__length_hint__ | Missing result: func=With_length_hint.__length_hint__ |
| classes.py:71:32:71:77 | Comment #$ arg1="with_index" func=With_index.__index__ | Missing result: arg1="with_index" |
| classes.py:71:32:71:77 | Comment #$ arg1="with_index" func=With_index.__index__ | Missing result: func=With_index.__index__ |
| classes.py:54:44:54:108 | Comment # $ arg1="with_length_hint" func=With_length_hint.__length_hint__ | Missing result: arg1="with_length_hint" |
| classes.py:54:44:54:108 | Comment # $ arg1="with_length_hint" func=With_length_hint.__length_hint__ | Missing result: func=With_length_hint.__length_hint__ |
| classes.py:71:32:71:78 | Comment # $ arg1="with_index" func=With_index.__index__ | Missing result: arg1="with_index" |
| classes.py:71:32:71:78 | Comment # $ arg1="with_index" func=With_index.__index__ | Missing result: func=With_index.__index__ |

View File

@@ -51,7 +51,7 @@ class With_length_hint:
def test_length_hint():
import operator
with_length_hint = With_length_hint() #$ arg1="with_length_hint" func=With_length_hint.__length_hint__
with_length_hint = With_length_hint() # $ arg1="with_length_hint" func=With_length_hint.__length_hint__
operator.length_hint(with_length_hint)
@@ -68,5 +68,5 @@ class With_index:
def test_index():
import operator
with_index = With_index() #$ arg1="with_index" func=With_index.__index__
with_index = With_index() # $ arg1="with_index" func=With_index.__index__
operator.index(with_index)

View File

@@ -53,9 +53,9 @@ def argument_passing(
b,
/,
c,
d=arg4, #$ arg4 func=argument_passing
d=arg4, # $ arg4 func=argument_passing
*,
e=arg5, #$ arg5 func=argument_passing
e=arg5, # $ arg5 func=argument_passing
f,
**g,
):
@@ -73,12 +73,12 @@ def argument_passing(
@expects(7)
def test_argument_passing1():
argument_passing(arg1, *(arg2, arg3, arg4), e=arg5, **{"f": arg6, "g": arg7}) #$ arg1 arg5 arg6 arg7 func=argument_passing MISSING: arg2 arg3 arg4
argument_passing(arg1, *(arg2, arg3, arg4), e=arg5, **{"f": arg6, "g": arg7}) # $ arg1 arg5 arg6 arg7 func=argument_passing MISSING: arg2 arg3 arg4
@expects(7)
def test_argument_passing2():
argument_passing(arg1, arg2, arg3, f=arg6) #$ arg1 arg2 arg3 arg6
argument_passing(arg1, arg2, arg3, f=arg6) # $ arg1 arg2 arg3 arg6
def with_pos_only(a, /, b):
@@ -88,9 +88,9 @@ def with_pos_only(a, /, b):
@expects(6)
def test_pos_only():
with_pos_only(arg1, arg2) #$ arg1 arg2
with_pos_only(arg1, b=arg2) #$ arg1 arg2
with_pos_only(arg1, *(arg2,)) #$ arg1 MISSING: arg2
with_pos_only(arg1, arg2) # $ arg1 arg2
with_pos_only(arg1, b=arg2) # $ arg1 arg2
with_pos_only(arg1, *(arg2,)) # $ arg1 MISSING: arg2
def with_multiple_kw_args(a, b, c):
@@ -101,13 +101,13 @@ def with_multiple_kw_args(a, b, c):
@expects(12)
def test_multiple_kw_args():
with_multiple_kw_args(b=arg2, c=arg3, a=arg1) #$ arg1 arg2 arg3
with_multiple_kw_args(arg1, *(arg2,), arg3) #$ arg1 MISSING: arg2 arg3
with_multiple_kw_args(arg1, **{"c": arg3}, b=arg2) #$ arg1 arg2 arg3 func=with_multiple_kw_args
with_multiple_kw_args(**{"b": arg2}, **{"c": arg3}, **{"a": arg1}) #$ arg1 arg2 arg3 func=with_multiple_kw_args
with_multiple_kw_args(b=arg2, c=arg3, a=arg1) # $ arg1 arg2 arg3
with_multiple_kw_args(arg1, *(arg2,), arg3) # $ arg1 MISSING: arg2 arg3
with_multiple_kw_args(arg1, **{"c": arg3}, b=arg2) # $ arg1 arg2 arg3 func=with_multiple_kw_args
with_multiple_kw_args(**{"b": arg2}, **{"c": arg3}, **{"a": arg1}) # $ arg1 arg2 arg3 func=with_multiple_kw_args
def with_default_arguments(a=arg1, b=arg2, c=arg3): #$ arg1 arg2 arg3 func=with_default_arguments
def with_default_arguments(a=arg1, b=arg2, c=arg3): # $ arg1 arg2 arg3 func=with_default_arguments
SINK1(a)
SINK2(b)
SINK3(c)
@@ -116,9 +116,9 @@ def with_default_arguments(a=arg1, b=arg2, c=arg3): #$ arg1 arg2 arg3 func=with
@expects(12)
def test_default_arguments():
with_default_arguments()
with_default_arguments(arg1) #$ arg1
with_default_arguments(b=arg2) #$ arg2
with_default_arguments(**{"c": arg3}) #$ arg3 func=with_default_arguments
with_default_arguments(arg1) # $ arg1
with_default_arguments(b=arg2) # $ arg2
with_default_arguments(**{"c": arg3}) # $ arg3 func=with_default_arguments
# All combinations
@@ -126,14 +126,14 @@ def test_pos_pos():
def with_pos(a):
SINK1(a)
with_pos(arg1) #$ arg1 func=test_pos_pos.with_pos
with_pos(arg1) # $ arg1 func=test_pos_pos.with_pos
def test_pos_pos_only():
def with_pos_only(a, /):
SINK1(a)
with_pos_only(arg1) #$ arg1 func=test_pos_pos_only.with_pos_only
with_pos_only(arg1) # $ arg1 func=test_pos_pos_only.with_pos_only
def test_pos_star():
@@ -141,35 +141,35 @@ def test_pos_star():
if len(a) > 0:
SINK1(a[0])
with_star(arg1) #$ arg1 func=test_pos_star.with_star
with_star(arg1) # $ arg1 func=test_pos_star.with_star
def test_pos_kw():
def with_kw(a=""):
SINK1(a)
with_kw(arg1) #$ arg1 func=test_pos_kw.with_kw
with_kw(arg1) # $ arg1 func=test_pos_kw.with_kw
def test_kw_pos():
def with_pos(a):
SINK1(a)
with_pos(a=arg1) #$ arg1 func=test_kw_pos.with_pos
with_pos(a=arg1) # $ arg1 func=test_kw_pos.with_pos
def test_kw_kw():
def with_kw(a=""):
SINK1(a)
with_kw(a=arg1) #$ arg1 func=test_kw_kw.with_kw
with_kw(a=arg1) # $ arg1 func=test_kw_kw.with_kw
def test_kw_doublestar():
def with_doublestar(**kwargs):
SINK1(kwargs["a"])
with_doublestar(a=arg1) #$ arg1 func=test_kw_doublestar.with_doublestar
with_doublestar(a=arg1) # $ arg1 func=test_kw_doublestar.with_doublestar
def only_kwargs(**kwargs):

File diff suppressed because it is too large Load Diff

View File

@@ -58,7 +58,7 @@ SINK7 = functools.partial(SINK, expected=arg7)
def f(a, b):
return a
SINK(f(SOURCE, 3)) #$ flow="SOURCE -> f(..)"
SINK(f(SOURCE, 3)) # $ flow="SOURCE -> f(..)"
# Instance methods
# An instance method object combines a class, a class instance and any callable object (normally a user-defined function).
@@ -236,10 +236,10 @@ class Customized:
# testing __new__ and __init__
customized = Customized()
SINK(Customized.a) #$ MISSING:flow="SOURCE, l:-8 -> customized.a"
SINK(Customized.a) # $ MISSING:flow="SOURCE, l:-8 -> customized.a"
SINK_F(Customized.b)
SINK(customized.a) #$ MISSING: flow="SOURCE, l:-10 -> customized.a"
SINK(customized.b) #$ flow="SOURCE, l:-7 -> customized.b"
SINK(customized.a) # $ MISSING: flow="SOURCE, l:-10 -> customized.a"
SINK(customized.b) # $ flow="SOURCE, l:-7 -> customized.b"
class Test2:

View File

@@ -38,7 +38,7 @@ def test_while():
n = 2
while n > 0:
if n == 1:
SINK(x) #$ flow="SOURCE, l:+1 -> x"
SINK(x) # $ flow="SOURCE, l:+1 -> x"
x = SOURCE
n -= 1
@@ -54,14 +54,14 @@ def test_while_obj():
n = 2
while n > 0:
if n == 1:
SINK(myobj.foo) #$ flow="SOURCE, l:+1 -> myobj.foo"
SINK(myobj.foo) # $ flow="SOURCE, l:+1 -> myobj.foo"
setFoo(myobj, SOURCE)
n -= 1
def setAndTestFoo(obj, x, test):
if test:
# This flow is not found, if self-loops are broken at the SSA level.
SINK(obj.foo) #$ flow="SOURCE, l:+7 -> obj.foo"
SINK(obj.foo) # $ flow="SOURCE, l:+7 -> obj.foo"
obj.foo = x
def test_while_obj_sink():
@@ -70,4 +70,3 @@ def test_while_obj_sink():
while n > 0:
setAndTestFoo(myobj, SOURCE, n == 1)
n -= 1

View File

@@ -3,5 +3,5 @@
t = (SOURCE, NONSOURCE)
a, b = t
SINK(a) #$ flow="SOURCE, l:-2 -> a"
SINK(a) # $ flow="SOURCE, l:-2 -> a"
SINK_F(b)

View File

@@ -41,7 +41,7 @@ def SINK_F(x):
def test_tuple_with_local_flow():
x = (NONSOURCE, SOURCE)
y = x[1]
SINK(y) #$ flow="SOURCE, l:-2 -> y"
SINK(y) # $ flow="SOURCE, l:-2 -> y"
def test_tuple_negative():
@@ -53,45 +53,45 @@ def test_tuple_negative():
# 6.2.1. Identifiers (Names)
def test_names():
x = SOURCE
SINK(x) #$ flow="SOURCE, l:-1 -> x"
SINK(x) # $ flow="SOURCE, l:-1 -> x"
# 6.2.2. Literals
def test_string_literal():
x = "source"
SINK(x) #$ flow="'source', l:-1 -> x"
SINK(x) # $ flow="'source', l:-1 -> x"
def test_bytes_literal():
x = b"source"
SINK(x) #$ flow="b'source', l:-1 -> x"
SINK(x) # $ flow="b'source', l:-1 -> x"
def test_integer_literal():
x = 42
SINK(x) #$ flow="42, l:-1 -> x"
SINK(x) # $ flow="42, l:-1 -> x"
def test_floatnumber_literal():
x = 42.0
SINK(x) #$ flow="42.0, l:-1 -> x"
SINK(x) # $ flow="42.0, l:-1 -> x"
def test_imagnumber_literal():
x = 42j
SINK(x) #$ MISSING:flow="42j, l:-1 -> x"
SINK(x) # $ MISSING:flow="42j, l:-1 -> x"
# 6.2.3. Parenthesized forms
def test_parenthesized_form():
x = (SOURCE)
SINK(x) #$ flow="SOURCE, l:-1 -> x"
SINK(x) # $ flow="SOURCE, l:-1 -> x"
# 6.2.5. List displays
def test_list_display():
x = [SOURCE]
SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]"
SINK(x[0]) # $ flow="SOURCE, l:-1 -> x[0]"
def test_list_display_negative():
@@ -101,23 +101,23 @@ def test_list_display_negative():
def test_list_comprehension():
x = [SOURCE for y in [NONSOURCE]]
SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]"
SINK(x[0]) # $ flow="SOURCE, l:-1 -> x[0]"
def test_list_comprehension_flow():
x = [y for y in [SOURCE]]
SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]"
SINK(x[0]) # $ flow="SOURCE, l:-1 -> x[0]"
def test_list_comprehension_inflow():
l = [SOURCE]
x = [y for y in l]
SINK(x[0]) #$ flow="SOURCE, l:-2 -> x[0]"
SINK(x[0]) # $ flow="SOURCE, l:-2 -> x[0]"
def test_nested_list_display():
x = [*[SOURCE]]
SINK(x[0]) #$ MISSING:flow="SOURCE, l:-1 -> x[0]"
SINK(x[0]) # $ MISSING:flow="SOURCE, l:-1 -> x[0]"
@expects(6)
@@ -144,98 +144,98 @@ def test_list_comprehension_with_tuple_result():
# 6.2.6. Set displays
def test_set_display():
x = {SOURCE}
SINK(x.pop()) #$ flow="SOURCE, l:-1 -> x.pop()"
SINK(x.pop()) # $ flow="SOURCE, l:-1 -> x.pop()"
def test_set_comprehension():
x = {SOURCE for y in [NONSOURCE]}
SINK(x.pop()) #$ flow="SOURCE, l:-1 -> x.pop()"
SINK(x.pop()) # $ flow="SOURCE, l:-1 -> x.pop()"
def test_set_comprehension_flow():
x = {y for y in [SOURCE]}
SINK(x.pop()) #$ flow="SOURCE, l:-1 -> x.pop()"
SINK(x.pop()) # $ flow="SOURCE, l:-1 -> x.pop()"
def test_set_comprehension_inflow():
l = {SOURCE}
x = {y for y in l}
SINK(x.pop()) #$ flow="SOURCE, l:-2 -> x.pop()"
SINK(x.pop()) # $ flow="SOURCE, l:-2 -> x.pop()"
def test_nested_set_display():
x = {*{SOURCE}}
SINK(x.pop()) #$ MISSING:flow="SOURCE, l:-1 -> x.pop()"
SINK(x.pop()) # $ MISSING:flow="SOURCE, l:-1 -> x.pop()"
# 6.2.7. Dictionary displays
def test_dict_display():
x = {"s": SOURCE}
SINK(x["s"]) #$ flow="SOURCE, l:-1 -> x['s']"
SINK(x["s"]) # $ flow="SOURCE, l:-1 -> x['s']"
def test_dict_display_pop():
x = {"s": SOURCE}
SINK(x.pop("s")) #$ flow="SOURCE, l:-1 -> x.pop(..)"
SINK(x.pop("s")) # $ flow="SOURCE, l:-1 -> x.pop(..)"
def test_dict_comprehension():
x = {y: SOURCE for y in ["s"]}
SINK(x["s"]) #$ MISSING:flow="SOURCE, l:-1 -> x['s']"
SINK(x["s"]) # $ MISSING:flow="SOURCE, l:-1 -> x['s']"
def test_dict_comprehension_pop():
x = {y: SOURCE for y in ["s"]}
SINK(x.pop("s")) #$ MISSING:flow="SOURCE, l:-1 -> x.pop()"
SINK(x.pop("s")) # $ MISSING:flow="SOURCE, l:-1 -> x.pop()"
def test_nested_dict_display():
x = {**{"s": SOURCE}}
SINK(x["s"]) #$ MISSING:flow="SOURCE, l:-1 -> x['s']"
SINK(x["s"]) # $ MISSING:flow="SOURCE, l:-1 -> x['s']"
def test_nested_dict_display_pop():
x = {**{"s": SOURCE}}
SINK(x.pop("s")) #$ MISSING:flow="SOURCE, l:-1 -> x.pop()"
SINK(x.pop("s")) # $ MISSING:flow="SOURCE, l:-1 -> x.pop()"
# Nested comprehensions
def test_nested_comprehension():
x = [y for z in [[SOURCE]] for y in z]
SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]"
SINK(x[0]) # $ flow="SOURCE, l:-1 -> x[0]"
def test_nested_comprehension_deep_with_local_flow():
x = [y for v in [[[[SOURCE]]]] for u in v for z in u for y in z]
SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]"
SINK(x[0]) # $ flow="SOURCE, l:-1 -> x[0]"
def test_nested_comprehension_dict():
d = {"s": [SOURCE]}
x = [y for k, v in d.items() for y in v]
SINK(x[0]) #$ flow="SOURCE, l:-2 -> x[0]"
SINK(x[0]) # $ flow="SOURCE, l:-2 -> x[0]"
def test_nested_comprehension_paren():
x = [y for y in (z for z in [SOURCE])]
SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]"
SINK(x[0]) # $ flow="SOURCE, l:-1 -> x[0]"
# Iterable unpacking in comprehensions
def test_unpacking_comprehension():
x = [a for (a, b) in [(SOURCE, NONSOURCE)]]
SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]"
SINK(x[0]) # $ flow="SOURCE, l:-1 -> x[0]"
def test_star_unpacking_comprehension():
x = [a[0] for (*a, b) in [(SOURCE, NONSOURCE)]]
SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]"
SINK(x[0]) # $ flow="SOURCE, l:-1 -> x[0]"
# 6.2.8. Generator expressions
def test_generator():
x = (SOURCE for y in [NONSOURCE])
SINK([*x][0]) #$ MISSING:flow="SOURCE, l:-1 -> List[0]"
SINK([*x][0]) # $ MISSING:flow="SOURCE, l:-1 -> List[0]"
# 6.2.9. Yield expressions
@@ -245,7 +245,7 @@ def gen(x):
def test_yield():
g = gen(SOURCE)
SINK(next(g)) #$ flow="SOURCE, l:-1 -> next(..)"
SINK(next(g)) # $ flow="SOURCE, l:-1 -> next(..)"
def gen_from(x):
@@ -254,19 +254,19 @@ def gen_from(x):
def test_yield_from():
g = gen_from(SOURCE)
SINK(next(g)) #$ MISSING:flow="SOURCE, l:-1 -> next()"
SINK(next(g)) # $ MISSING:flow="SOURCE, l:-1 -> next()"
# a statement rather than an expression, but related to generators
def test_for():
for x in gen(SOURCE):
SINK(x) #$ flow="SOURCE, l:-1 -> x"
SINK(x) # $ flow="SOURCE, l:-1 -> x"
# 6.2.9.1. Generator-iterator methods
def test___next__():
g = gen(SOURCE)
SINK(g.__next__()) #$ MISSING:flow="SOURCE, l:-1 -> g.__next__()"
SINK(g.__next__()) # $ MISSING:flow="SOURCE, l:-1 -> g.__next__()"
def gen2(x):
@@ -278,7 +278,7 @@ def gen2(x):
def test_send():
g = gen2(NONSOURCE)
n = next(g)
SINK(g.send(SOURCE)) #$ MISSING:flow="SOURCE -> g.send()"
SINK(g.send(SOURCE)) # $ MISSING:flow="SOURCE -> g.send()"
def gen_ex(x):
@@ -291,7 +291,7 @@ def gen_ex(x):
def test_throw():
g = gen_ex(SOURCE)
n = next(g)
SINK(g.throw(TypeError)) #$ MISSING:flow="SOURCE, l:-2 -> g.throw()"
SINK(g.throw(TypeError)) # $ MISSING:flow="SOURCE, l:-2 -> g.throw()"
# no `test_close` as `close` involves no data flow
@@ -312,7 +312,7 @@ def runa(a):
async def atest___anext__():
g = agen(SOURCE)
SINK(await g.__anext__()) #$ MISSING:flow="SOURCE, l:-1 -> g.__anext__()"
SINK(await g.__anext__()) # $ MISSING:flow="SOURCE, l:-1 -> g.__anext__()"
def test___anext__():
@@ -328,7 +328,7 @@ async def agen2(x):
async def atest_asend():
g = agen2(NONSOURCE)
n = await g.__anext__()
SINK(await g.asend(SOURCE)) #$ MISSING:flow="SOURCE -> g.asend()"
SINK(await g.asend(SOURCE)) # $ MISSING:flow="SOURCE -> g.asend()"
def test_asend():
@@ -345,7 +345,7 @@ async def agen_ex(x):
async def atest_athrow():
g = agen_ex(SOURCE)
n = await g.__anext__()
SINK(await g.athrow(TypeError)) #$ MISSING:flow="SOURCE, l:-2 -> g.athrow()"
SINK(await g.athrow(TypeError)) # $ MISSING:flow="SOURCE, l:-2 -> g.athrow()"
def test_athrow():
@@ -367,15 +367,15 @@ def test_attribute_reference():
# 6.3.2. Subscriptions
def test_subscription_tuple():
SINK((SOURCE,)[0]) #$ flow="SOURCE -> Tuple[0]"
SINK((SOURCE,)[0]) # $ flow="SOURCE -> Tuple[0]"
def test_subscription_list():
SINK([SOURCE][0]) #$ flow="SOURCE -> List[0]"
SINK([SOURCE][0]) # $ flow="SOURCE -> List[0]"
def test_subscription_mapping():
SINK({"s": SOURCE}["s"]) #$ flow="SOURCE -> Dict['s']"
SINK({"s": SOURCE}["s"]) # $ flow="SOURCE -> Dict['s']"
# overriding __getitem__ should be tested by the class coverage tests
@@ -387,7 +387,7 @@ l = [SOURCE]
def test_slicing():
s = l[0:1:1]
SINK(s[0]) #$ MISSING:flow="SOURCE -> s[0]"
SINK(s[0]) # $ MISSING:flow="SOURCE -> s[0]"
# The grammar seems to allow `l[0:1:1, 0:1]`, but the interpreter does not like it
@@ -398,7 +398,7 @@ def second(a, b):
def test_call_positional():
SINK(second(NONSOURCE, SOURCE)) #$ flow="SOURCE -> second(..)"
SINK(second(NONSOURCE, SOURCE)) # $ flow="SOURCE -> second(..)"
def test_call_positional_negative():
@@ -406,15 +406,15 @@ def test_call_positional_negative():
def test_call_keyword():
SINK(second(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> second(..)"
SINK(second(NONSOURCE, b=SOURCE)) # $ flow="SOURCE -> second(..)"
def test_call_unpack_iterable():
SINK(second(NONSOURCE, *[SOURCE])) #$ MISSING:flow="SOURCE -> second(..)"
SINK(second(NONSOURCE, *[SOURCE])) # $ MISSING:flow="SOURCE -> second(..)"
def test_call_unpack_mapping():
SINK(second(NONSOURCE, **{"b": SOURCE})) #$ flow="SOURCE -> second(..)"
SINK(second(NONSOURCE, **{"b": SOURCE})) # $ flow="SOURCE -> second(..)"
def f_extra_pos(a, *b):
@@ -422,7 +422,7 @@ def f_extra_pos(a, *b):
def test_call_extra_pos():
SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ flow="SOURCE -> f_extra_pos(..)"
SINK(f_extra_pos(NONSOURCE, SOURCE)) # $ flow="SOURCE -> f_extra_pos(..)"
def f_extra_keyword(a, **b):
@@ -430,7 +430,7 @@ def f_extra_keyword(a, **b):
def test_call_extra_keyword():
SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> f_extra_keyword(..)"
SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) # $ flow="SOURCE -> f_extra_keyword(..)"
# return the name of the first extra keyword argument
@@ -440,34 +440,34 @@ def f_extra_keyword_flow(**a):
# call the function with our source as the name of the keyword arguemnt
def test_call_extra_keyword_flow():
SINK(f_extra_keyword_flow(**{SOURCE: None})) #$ MISSING:flow="SOURCE -> f_extra_keyword(..)"
SINK(f_extra_keyword_flow(**{SOURCE: None})) # $ MISSING:flow="SOURCE -> f_extra_keyword(..)"
# 6.11. Boolean operations
def test_or(x = False):
# if we don't know the value of the lhs, we should always add flow
SINK(x or SOURCE) #$ flow="SOURCE -> BoolExpr"
SINK(x or SOURCE) # $ flow="SOURCE -> BoolExpr"
def test_and(x = True):
# if we don't know the value of the lhs, we should always add flow
SINK(x and SOURCE) #$ flow="SOURCE -> BoolExpr"
SINK(x and SOURCE) # $ flow="SOURCE -> BoolExpr"
# 6.12. Assignment expressions
def test_assignment_expression_flow_lhs():
x = NONSOURCE
if x := SOURCE:
SINK(x) #$ flow="SOURCE, l:-1 -> x"
SINK(x) # $ flow="SOURCE, l:-1 -> x"
def test_assignment_expression_flow_out():
x = NONSOURCE
SINK(x := SOURCE) #$ flow="SOURCE -> AssignExpr"
SINK(x := SOURCE) # $ flow="SOURCE -> AssignExpr"
# 6.13. Conditional expressions
def test_conditional_true():
SINK(SOURCE if True else NONSOURCE) #$ flow="SOURCE -> IfExp"
SINK(SOURCE if True else NONSOURCE) # $ flow="SOURCE -> IfExp"
def test_conditional_true_guards():
@@ -475,7 +475,7 @@ def test_conditional_true_guards():
def test_conditional_false():
SINK(NONSOURCE if False else SOURCE) #$ flow="SOURCE -> IfExp"
SINK(NONSOURCE if False else SOURCE) # $ flow="SOURCE -> IfExp"
def test_conditional_false_guards():
@@ -485,13 +485,13 @@ def test_conditional_false_guards():
# Condition is evaluated first, so x is SOURCE once chosen
def test_conditional_evaluation_true():
x = NONSOURCE
SINK(x if (SOURCE == (x := SOURCE)) else NONSOURCE) #$ flow="SOURCE -> IfExp"
SINK(x if (SOURCE == (x := SOURCE)) else NONSOURCE) # $ flow="SOURCE -> IfExp"
# Condition is evaluated first, so x is SOURCE once chosen
def test_conditional_evaluation_false():
x = NONSOURCE
SINK(NONSOURCE if (NONSOURCE == (x := SOURCE)) else x) #$ flow="SOURCE -> IfExp"
SINK(NONSOURCE if (NONSOURCE == (x := SOURCE)) else x) # $ flow="SOURCE -> IfExp"
# 6.14. Lambdas
@@ -499,14 +499,14 @@ def test_lambda():
def f(x):
return x
SINK(f(SOURCE)) #$ flow="SOURCE -> f(..)"
SINK(f(SOURCE)) # $ flow="SOURCE -> f(..)"
def test_lambda_positional():
def second(a, b):
return b
SINK(second(NONSOURCE, SOURCE)) #$ flow="SOURCE -> second(..)"
SINK(second(NONSOURCE, SOURCE)) # $ flow="SOURCE -> second(..)"
def test_lambda_positional_negative():
@@ -520,57 +520,57 @@ def test_lambda_keyword():
def second(a, b):
return b
SINK(second(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> second(..)"
SINK(second(NONSOURCE, b=SOURCE)) # $ flow="SOURCE -> second(..)"
def test_lambda_unpack_iterable():
def second(a, b):
return b
SINK(second(NONSOURCE, *[SOURCE])) #$ MISSING:flow="SOURCE -> second(..)" # Flow missing
SINK(second(NONSOURCE, *[SOURCE])) # $ MISSING:flow="SOURCE -> second(..)" # Flow missing
def test_lambda_unpack_mapping():
def second(a, b):
return b
SINK(second(NONSOURCE, **{"b": SOURCE})) #$ flow="SOURCE -> second(..)"
SINK(second(NONSOURCE, **{"b": SOURCE})) # $ flow="SOURCE -> second(..)"
def test_lambda_extra_pos():
f_extra_pos = lambda a, *b: b[0]
SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ flow="SOURCE -> f_extra_pos(..)"
SINK(f_extra_pos(NONSOURCE, SOURCE)) # $ flow="SOURCE -> f_extra_pos(..)"
def test_lambda_extra_keyword():
f_extra_keyword = lambda a, **b: b["b"]
SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> f_extra_keyword(..)"
SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) # $ flow="SOURCE -> f_extra_keyword(..)"
# call the function with our source as the name of the keyword argument
def test_lambda_extra_keyword_flow():
# return the name of the first extra keyword argument
f_extra_keyword_flow = lambda **a: [*a][0]
SINK(f_extra_keyword_flow(**{SOURCE: None})) #$ MISSING:flow="SOURCE -> f_extra_keyword(..)"
SINK(f_extra_keyword_flow(**{SOURCE: None})) # $ MISSING:flow="SOURCE -> f_extra_keyword(..)"
@expects(4)
def test_swap():
a = SOURCE
b = NONSOURCE
SINK(a) #$ flow="SOURCE, l:-2 -> a"
SINK(a) # $ flow="SOURCE, l:-2 -> a"
SINK_F(b)
a, b = b, a
SINK_F(a)
SINK(b) #$ flow="SOURCE, l:-7 -> b"
SINK(b) # $ flow="SOURCE, l:-7 -> b"
@expects(2)
def test_unpacking_assignment():
t = (SOURCE, NONSOURCE)
a, b = t
SINK(a) #$ flow="SOURCE, l:-2 -> a"
SINK(a) # $ flow="SOURCE, l:-2 -> a"
SINK_F(b)
@@ -578,16 +578,16 @@ def test_unpacking_assignment():
def test_nested_unpacking_assignment():
t = (SOURCE, (NONSOURCE, SOURCE))
a, (b, c) = t
SINK(a) #$ flow="SOURCE, l:-2 -> a"
SINK(a) # $ flow="SOURCE, l:-2 -> a"
SINK_F(b)
SINK(c) #$ flow="SOURCE, l:-4 -> c"
SINK(c) # $ flow="SOURCE, l:-4 -> c"
@expects(2)
def test_deeply_nested_unpacking_assignment():
t = [[[[SOURCE]]], NONSOURCE]
[[[a]]], b = t
SINK(a) #$ flow="SOURCE, l:-2 -> a"
SINK(a) # $ flow="SOURCE, l:-2 -> a"
SINK_F(b)
@@ -595,19 +595,19 @@ def test_deeply_nested_unpacking_assignment():
def test_iterated_unpacking_assignment():
t = (SOURCE, SOURCE, NONSOURCE)
a, *b, c = t
SINK(a) #$ flow="SOURCE, l:-2 -> a"
SINK(a) # $ flow="SOURCE, l:-2 -> a"
SINK_F(b)
SINK(b[0]) #$ flow="SOURCE, l:-4 -> b[0]"
SINK_F(c) #$ SPURIOUS: flow="SOURCE, l:-5 -> c" # We do not track tuple sizes
SINK(b[0]) # $ flow="SOURCE, l:-4 -> b[0]"
SINK_F(c) # $ SPURIOUS: flow="SOURCE, l:-5 -> c" # We do not track tuple sizes
@expects(3)
def test_iterated_unpacking_assignment_shrink():
t = (SOURCE, SOURCE)
a, *b, c = t
SINK(a) #$ flow="SOURCE, l:-2 -> a"
SINK(a) # $ flow="SOURCE, l:-2 -> a"
SINK_F(b)
SINK(c) #$ flow="SOURCE, l:-4 -> c"
SINK(c) # $ flow="SOURCE, l:-4 -> c"
@expects(15)
@@ -616,25 +616,25 @@ def test_unpacking_assignment_conversion():
# tuple
((a1, a2, a3), b, c) = ll
SINK(a1) #$ flow="SOURCE, l:-4 -> a1"
SINK_F(a2) #$ SPURIOUS: flow="SOURCE, l:-5 -> a2" # We expect an FP as all elements are tainted
SINK(a3) #$ flow="SOURCE, l:-6 -> a3"
SINK(a1) # $ flow="SOURCE, l:-4 -> a1"
SINK_F(a2) # $ SPURIOUS: flow="SOURCE, l:-5 -> a2" # We expect an FP as all elements are tainted
SINK(a3) # $ flow="SOURCE, l:-6 -> a3"
SINK_F(b) # The list itself is not tainted
SINK_F(c)
# mixed
[(a1, a2, a3), b, c] = ll
SINK(a1) #$ flow="SOURCE, l:-12 -> a1"
SINK_F(a2) #$ SPURIOUS: flow="SOURCE, l:-13 -> a2" # We expect an FP as all elements are tainted
SINK(a3) #$ flow="SOURCE, l:-14 -> a3"
SINK(a1) # $ flow="SOURCE, l:-12 -> a1"
SINK_F(a2) # $ SPURIOUS: flow="SOURCE, l:-13 -> a2" # We expect an FP as all elements are tainted
SINK(a3) # $ flow="SOURCE, l:-14 -> a3"
SINK_F(b) # The list itself is not tainted
SINK_F(c)
# mixed differently
([a1, a2, a3], b, c) = ll
SINK(a1) #$ flow="SOURCE, l:-20 -> a1"
SINK_F(a2) #$ SPURIOUS: flow="SOURCE, l:-21 -> a2" # We expect an FP as all elements are tainted
SINK(a3) #$ flow="SOURCE, l:-22 -> a3"
SINK(a1) # $ flow="SOURCE, l:-20 -> a1"
SINK_F(a2) # $ SPURIOUS: flow="SOURCE, l:-21 -> a2" # We expect an FP as all elements are tainted
SINK(a3) # $ flow="SOURCE, l:-22 -> a3"
SINK_F(b) # The list itself is not tainted
SINK_F(c)
@@ -644,37 +644,37 @@ def test_iterated_unpacking_assignment_conversion():
# list
[[a1, *a2], *b] = tt
SINK(a1) #$ flow="SOURCE, l:-4 -> a1"
SINK(a1) # $ flow="SOURCE, l:-4 -> a1"
SINK_F(a2) # The list itself is not tainted
SINK_F(a2[0]) #$ SPURIOUS: flow="SOURCE, l:-6 -> a2[0]" # FP here due to list abstraction
SINK(a2[1]) #$ flow="SOURCE, l:-7 -> a2[1]"
SINK_F(a2[0]) # $ SPURIOUS: flow="SOURCE, l:-6 -> a2[0]" # FP here due to list abstraction
SINK(a2[1]) # $ flow="SOURCE, l:-7 -> a2[1]"
SINK_F(b) # The list itself is not tainted
SINK_F(b[0])
# tuple
((a1, *a2), *b) = tt
SINK(a1) #$ flow="SOURCE, l:-13 -> a1"
SINK(a1) # $ flow="SOURCE, l:-13 -> a1"
SINK_F(a2) # The list itself is not tainted
SINK_F(a2[0]) #$ SPURIOUS: flow="SOURCE, l:-15 -> a2[0]" # FP here due to list abstraction
SINK(a2[1]) #$ flow="SOURCE, l:-16 -> a2[1]"
SINK_F(a2[0]) # $ SPURIOUS: flow="SOURCE, l:-15 -> a2[0]" # FP here due to list abstraction
SINK(a2[1]) # $ flow="SOURCE, l:-16 -> a2[1]"
SINK_F(b) # The list itself is not tainted
SINK_F(b[0])
# mixed
[(a1, *a2), *b] = tt
SINK(a1) #$ flow="SOURCE, l:-22 -> a1"
SINK(a1) # $ flow="SOURCE, l:-22 -> a1"
SINK_F(a2) # The list itself is not tainted
SINK_F(a2[0]) #$ SPURIOUS: flow="SOURCE, l:-24 -> a2[0]" # FP here due to list abstraction
SINK(a2[1]) #$ flow="SOURCE, l:-25 -> a2[1]"
SINK_F(a2[0]) # $ SPURIOUS: flow="SOURCE, l:-24 -> a2[0]" # FP here due to list abstraction
SINK(a2[1]) # $ flow="SOURCE, l:-25 -> a2[1]"
SINK_F(b) # The list itself is not tainted
SINK_F(b[0])
# mixed differently
([a1, *a2], *b) = tt
SINK(a1) #$ flow="SOURCE, l:-31 -> a1"
SINK(a1) # $ flow="SOURCE, l:-31 -> a1"
SINK_F(a2) # The list itself is not tainted
SINK_F(a2[0]) #$ SPURIOUS: flow="SOURCE, l:-33 -> a2[0]" # FP here due to list abstraction
SINK(a2[1]) #$ flow="SOURCE, l:-34 -> a2[1]"
SINK_F(a2[0]) # $ SPURIOUS: flow="SOURCE, l:-33 -> a2[0]" # FP here due to list abstraction
SINK(a2[1]) # $ flow="SOURCE, l:-34 -> a2[1]"
SINK_F(b) # The list itself is not tainted
SINK_F(b[0])
@@ -682,16 +682,16 @@ def test_iterated_unpacking_assignment_conversion():
@expects(3)
def test_iterable_repacking():
a, *(b, c) = (SOURCE, NONSOURCE, SOURCE)
SINK(a) #$ flow="SOURCE, l:-1 -> a"
SINK(a) # $ flow="SOURCE, l:-1 -> a"
SINK_F(b)
SINK(c) #$ MISSING: flow="SOURCE, l:-3 -> c"
SINK(c) # $ MISSING: flow="SOURCE, l:-3 -> c"
@expects(4)
def test_iterable_unpacking_in_for():
tl = [(SOURCE, NONSOURCE), (SOURCE, NONSOURCE)]
for x,y in tl:
SINK(x) #$ flow="SOURCE, l:-2 -> x"
SINK(x) # $ flow="SOURCE, l:-2 -> x"
SINK_F(y)
@@ -700,21 +700,21 @@ def test_iterable_star_unpacking_in_for():
tl = [(SOURCE, NONSOURCE), (SOURCE, NONSOURCE)]
for *x,y in tl:
SINK_F(x)
SINK(x[0]) #$ flow="SOURCE, l:-3 -> x[0]"
SINK_F(y) #$ SPURIOUS: flow="SOURCE, l:-4 -> y" # FP here since we do not track the tuple lenght and so `*x` could be empty
SINK(x[0]) # $ flow="SOURCE, l:-3 -> x[0]"
SINK_F(y) # $ SPURIOUS: flow="SOURCE, l:-4 -> y" # FP here since we do not track the tuple lenght and so `*x` could be empty
@expects(6)
def test_iterable_star_unpacking_in_for_2():
tl = [(SOURCE, NONSOURCE), (SOURCE, NONSOURCE)]
for x,*y,z in tl:
SINK(x) #$ flow="SOURCE, l:-2 -> x"
SINK(x) # $ flow="SOURCE, l:-2 -> x"
SINK_F(y) # The list itself is not tainted (and is here empty)
SINK_F(z)
def iterate_star_args(first, second, *args):
for arg in args:
SINK(arg) #$ flow="SOURCE, l:+5 -> arg" flow="SOURCE, l:+6 -> arg"
SINK(arg) # $ flow="SOURCE, l:+5 -> arg" flow="SOURCE, l:+6 -> arg"
# FP reported here: https://github.com/github/codeql-python-team/issues/49
@expects(2)
@@ -751,17 +751,17 @@ def test_deep_callgraph():
return f5(arg)
x = f6(SOURCE)
SINK(x) #$ flow="SOURCE, l:-1 -> x"
SINK(x) # $ flow="SOURCE, l:-1 -> x"
x = f5(SOURCE)
SINK(x) #$ flow="SOURCE, l:-1 -> x"
SINK(x) # $ flow="SOURCE, l:-1 -> x"
x = f4(SOURCE)
SINK(x) #$ flow="SOURCE, l:-1 -> x"
SINK(x) # $ flow="SOURCE, l:-1 -> x"
x = f3(SOURCE)
SINK(x) #$ flow="SOURCE, l:-1 -> x"
SINK(x) # $ flow="SOURCE, l:-1 -> x"
x = f2(SOURCE)
SINK(x) #$ flow="SOURCE, l:-1 -> x"
SINK(x) # $ flow="SOURCE, l:-1 -> x"
x = f1(SOURCE)
SINK(x) #$ flow="SOURCE, l:-1 -> x"
SINK(x) # $ flow="SOURCE, l:-1 -> x"
def wat_f1(arg):
@@ -785,17 +785,17 @@ def wat_f6(arg):
@expects(6)
def test_deep_callgraph_defined_in_module():
x = wat_f6(SOURCE)
SINK(x) #$ flow="SOURCE, l:-1 -> x"
SINK(x) # $ flow="SOURCE, l:-1 -> x"
x = wat_f5(SOURCE)
SINK(x) #$ flow="SOURCE, l:-1 -> x"
SINK(x) # $ flow="SOURCE, l:-1 -> x"
x = wat_f4(SOURCE)
SINK(x) #$ flow="SOURCE, l:-1 -> x"
SINK(x) # $ flow="SOURCE, l:-1 -> x"
x = wat_f3(SOURCE)
SINK(x) #$ flow="SOURCE, l:-1 -> x"
SINK(x) # $ flow="SOURCE, l:-1 -> x"
x = wat_f2(SOURCE)
SINK(x) #$ flow="SOURCE, l:-1 -> x"
SINK(x) # $ flow="SOURCE, l:-1 -> x"
x = wat_f1(SOURCE)
SINK(x) #$ flow="SOURCE, l:-1 -> x"
SINK(x) # $ flow="SOURCE, l:-1 -> x"
@expects(2)
def test_dynamic_tuple_creation_1():
@@ -803,7 +803,7 @@ def test_dynamic_tuple_creation_1():
tup += (SOURCE,)
tup += (NONSOURCE,)
SINK(tup[0]) #$ MISSING:flow="SOURCE, l:-3 -> tup[0]"
SINK(tup[0]) # $ MISSING:flow="SOURCE, l:-3 -> tup[0]"
SINK_F(tup[1])
@@ -813,7 +813,7 @@ def test_dynamic_tuple_creation_2():
tup += (SOURCE,)
tup += (NONSOURCE,)
SINK(tup[0]) #$ MISSING:flow="SOURCE, l:-3 -> tup[0]"
SINK(tup[0]) # $ MISSING:flow="SOURCE, l:-3 -> tup[0]"
SINK_F(tup[1])
@@ -823,7 +823,7 @@ def test_dynamic_tuple_creation_3():
tup2 = (NONSOURCE,)
tup = tup1 + tup2
SINK(tup[0]) #$ MISSING:flow="SOURCE, l:-4 -> tup[0]"
SINK(tup[0]) # $ MISSING:flow="SOURCE, l:-4 -> tup[0]"
SINK_F(tup[1])
@@ -834,7 +834,7 @@ def test_dynamic_tuple_creation_4():
for item in [SOURCE, NONSOURCE]:
tup += (item,)
SINK(tup[0]) #$ MISSING:flow="SOURCE, l:-3 -> tup[0]"
SINK(tup[0]) # $ MISSING:flow="SOURCE, l:-3 -> tup[0]"
SINK_F(tup[1])
def return_from_inner_scope(x):
@@ -844,7 +844,7 @@ def return_from_inner_scope(x):
return SOURCE
def test_return_from_inner_scope():
SINK(return_from_inner_scope([])) #$ flow="SOURCE, l:-3 -> return_from_inner_scope(..)"
SINK(return_from_inner_scope([])) # $ flow="SOURCE, l:-3 -> return_from_inner_scope(..)"
# Inspired by reverse read inconsistency check
@@ -855,13 +855,13 @@ def test_reverse_read_subscript():
d = {"a": NONSOURCE}
l = [d]
insertAtA(l[0])
SINK(d["a"]) #$ MISSING:flow="SOURCE, l-6 -> d['a']""
SINK(d["a"]) # $ MISSING:flow="SOURCE, l-6 -> d['a']""
def test_reverse_read_dict_arg():
d = {"a": NONSOURCE}
dd = {"d": d}
insertAtA(**dd)
SINK(d["a"]) #$ MISSING:flow="SOURCE, l-12 -> d['a']""
SINK(d["a"]) # $ MISSING:flow="SOURCE, l-12 -> d['a']""
class WithA:
@@ -876,10 +876,10 @@ def test_reverse_read_subscript_cls():
withA = WithA()
l = [withA]
l[0].setA(SOURCE)
SINK(withA.a) #$ MISSING:flow="SOURCE, l:-1 -> self.a"
SINK(withA.a) # $ MISSING:flow="SOURCE, l:-1 -> self.a"
@expects(3)
def test_with_default_param_value(x=SOURCE, /, y=SOURCE, *, z=SOURCE):
SINK(x) #$ flow="SOURCE, l:-1 -> x"
SINK(y) #$ flow="SOURCE, l:-2 -> y"
SINK(z) #$ flow="SOURCE, l:-3 -> z"
SINK(x) # $ flow="SOURCE, l:-1 -> x"
SINK(y) # $ flow="SOURCE, l:-2 -> y"
SINK(z) # $ flow="SOURCE, l:-3 -> z"

View File

@@ -41,8 +41,8 @@ def SINK_F(x):
def test_list_from_list():
l1 = [SOURCE, NONSOURCE]
l2 = list(l1)
SINK(l2[0]) #$ flow="SOURCE, l:-2 -> l2[0]"
SINK_F(l2[1]) #$ SPURIOUS: flow="SOURCE, l:-3 -> l2[1]"
SINK(l2[0]) # $ flow="SOURCE, l:-2 -> l2[0]"
SINK_F(l2[1]) # $ SPURIOUS: flow="SOURCE, l:-3 -> l2[1]"
# -- skip list_from_string
@@ -50,19 +50,19 @@ def test_list_from_list():
def test_list_from_tuple():
t = (SOURCE, NONSOURCE)
l = list(t)
SINK(l[0]) #$ flow="SOURCE, l:-2 -> l[0]"
SINK_F(l[1]) #$ SPURIOUS: flow="SOURCE, l:-3 -> l[1]"
SINK(l[0]) # $ flow="SOURCE, l:-2 -> l[0]"
SINK_F(l[1]) # $ SPURIOUS: flow="SOURCE, l:-3 -> l[1]"
def test_list_from_set():
s = {SOURCE}
l = list(s)
SINK(l[0]) #$ flow="SOURCE, l:-2 -> l[0]"
SINK(l[0]) # $ flow="SOURCE, l:-2 -> l[0]"
@expects(2)
def test_list_from_dict():
d = {SOURCE: 'v', NONSOURCE: 'v2'}
l = list(d)
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-2 -> l[0]"
SINK(l[0]) # $ MISSING: flow="SOURCE, l:-2 -> l[0]"
SINK_F(l[1]) # expecting FP due to imprecise flow
### Tuple
@@ -71,26 +71,26 @@ def test_list_from_dict():
def test_tuple_from_list():
l = [SOURCE, NONSOURCE]
t = tuple(l)
SINK(t[0]) #$ MISSING: flow="SOURCE, l:-2 -> t[0]"
SINK(t[0]) # $ MISSING: flow="SOURCE, l:-2 -> t[0]"
SINK_F(t[1])
@expects(2)
def test_tuple_from_tuple():
t0 = (SOURCE, NONSOURCE)
t = tuple(t0)
SINK(t[0]) #$ flow="SOURCE, l:-2 -> t[0]"
SINK(t[0]) # $ flow="SOURCE, l:-2 -> t[0]"
SINK_F(t[1])
def test_tuple_from_set():
s = {SOURCE}
t = tuple(s)
SINK(t[0]) #$ MISSING: flow="SOURCE, l:-2 -> t[0]"
SINK(t[0]) # $ MISSING: flow="SOURCE, l:-2 -> t[0]"
@expects(2)
def test_tuple_from_dict():
d = {SOURCE: "v1", NONSOURCE: "v2"}
t = tuple(d)
SINK(t[0]) #$ MISSING: flow="SOURCE, l:-2 -> t[0]"
SINK(t[0]) # $ MISSING: flow="SOURCE, l:-2 -> t[0]"
SINK_F(t[1])
@@ -100,25 +100,25 @@ def test_set_from_list():
l = [SOURCE]
s = set(l)
v = s.pop()
SINK(v) #$ flow="SOURCE, l:-3 -> v"
SINK(v) # $ flow="SOURCE, l:-3 -> v"
def test_set_from_tuple():
t = (SOURCE,)
s = set(t)
v = s.pop()
SINK(v) #$ flow="SOURCE, l:-3 -> v"
SINK(v) # $ flow="SOURCE, l:-3 -> v"
def test_set_from_set():
s0 = {SOURCE}
s = set(s0)
v = s.pop()
SINK(v) #$ flow="SOURCE, l:-3 -> v"
SINK(v) # $ flow="SOURCE, l:-3 -> v"
def test_set_from_dict():
d = {SOURCE: "val"}
s = set(d)
v = s.pop()
SINK(v) #$ MISSING: flow="SOURCE, l:-3 -> v"
SINK(v) # $ MISSING: flow="SOURCE, l:-3 -> v"
### Dict
@@ -126,29 +126,29 @@ def test_set_from_dict():
@expects(2)
def test_dict_from_keyword():
d = dict(k = SOURCE, k1 = NONSOURCE)
SINK(d["k"]) #$ flow="SOURCE, l:-1 -> d['k']"
SINK(d["k"]) # $ flow="SOURCE, l:-1 -> d['k']"
SINK_F(d["k1"])
@expects(2)
def test_dict_from_list():
d = dict([("k", SOURCE), ("k1", NONSOURCE)])
SINK(d["k"]) #$ flow="SOURCE, l:-1 -> d['k']"
SINK_F(d["k1"]) #$ SPURIOUS: flow="SOURCE, l:-2 -> d['k1']" // due to imprecise list content
SINK(d["k"]) # $ flow="SOURCE, l:-1 -> d['k']"
SINK_F(d["k1"]) # $ SPURIOUS: flow="SOURCE, l:-2 -> d['k1']" // due to imprecise list content
@expects(2)
def test_dict_from_dict():
d1 = {'k': SOURCE, 'k1': NONSOURCE}
d2 = dict(d1)
SINK(d2["k"]) #$ flow="SOURCE, l:-2 -> d2['k']"
SINK(d2["k"]) # $ flow="SOURCE, l:-2 -> d2['k']"
SINK_F(d2["k1"])
@expects(4)
def test_dict_from_multiple_args():
d = dict([("k", SOURCE), ("k1", NONSOURCE)], k2 = SOURCE, k3 = NONSOURCE)
SINK(d["k"]) #$ flow="SOURCE, l:-1 -> d['k']"
SINK_F(d["k1"]) #$ SPURIOUS: flow="SOURCE, l:-2 -> d['k1']" // due to imprecise list content
SINK(d["k2"]) #$ flow="SOURCE, l:-3 -> d['k2']"
SINK_F(d["k3"]) #$ SPURIOUS: flow="SOURCE, l:-4 -> d['k3']" // due to imprecise list content
SINK(d["k"]) # $ flow="SOURCE, l:-1 -> d['k']"
SINK_F(d["k1"]) # $ SPURIOUS: flow="SOURCE, l:-2 -> d['k1']" // due to imprecise list content
SINK(d["k2"]) # $ flow="SOURCE, l:-3 -> d['k2']"
SINK_F(d["k3"]) # $ SPURIOUS: flow="SOURCE, l:-4 -> d['k3']" // due to imprecise list content
## Container methods
@@ -157,46 +157,46 @@ def test_dict_from_multiple_args():
def test_list_pop():
l = [SOURCE]
v = l.pop()
SINK(v) #$ flow="SOURCE, l:-2 -> v"
SINK(v) # $ flow="SOURCE, l:-2 -> v"
def test_list_pop_index():
l = [SOURCE]
v = l.pop(0)
SINK(v) #$ flow="SOURCE, l:-2 -> v"
SINK(v) # $ flow="SOURCE, l:-2 -> v"
def test_list_pop_index_imprecise():
l = [SOURCE, NONSOURCE]
v = l.pop(1)
SINK_F(v) #$ SPURIOUS: flow="SOURCE, l:-2 -> v"
SINK_F(v) # $ SPURIOUS: flow="SOURCE, l:-2 -> v"
@expects(2)
def test_list_copy():
l0 = [SOURCE, NONSOURCE]
l = l0.copy()
SINK(l[0]) #$ flow="SOURCE, l:-2 -> l[0]"
SINK_F(l[1]) #$ SPURIOUS: flow="SOURCE, l:-3 -> l[1]"
SINK(l[0]) # $ flow="SOURCE, l:-2 -> l[0]"
SINK_F(l[1]) # $ SPURIOUS: flow="SOURCE, l:-3 -> l[1]"
def test_list_append():
l = [NONSOURCE]
l.append(SOURCE)
SINK(l[1]) #$ flow="SOURCE, l:-1 -> l[1]"
SINK(l[1]) # $ flow="SOURCE, l:-1 -> l[1]"
### Set
def test_set_pop():
s = {SOURCE}
v = s.pop()
SINK(v) #$ flow="SOURCE, l:-2 -> v"
SINK(v) # $ flow="SOURCE, l:-2 -> v"
def test_set_copy():
s0 = {SOURCE}
s = s0.copy()
SINK(s.pop()) #$ flow="SOURCE, l:-2 -> s.pop()"
SINK(s.pop()) # $ flow="SOURCE, l:-2 -> s.pop()"
def test_set_add():
s = set([])
s.add(SOURCE)
SINK(s.pop()) #$ flow="SOURCE, l:-1 -> s.pop()"
SINK(s.pop()) # $ flow="SOURCE, l:-1 -> s.pop()"
### Dict
@@ -204,13 +204,13 @@ def test_dict_keys():
d = {SOURCE: "value"}
keys = d.keys()
key_list = list(keys)
SINK(key_list[0]) #$ MISSING: flow="SOURCE, l:-3 -> key_list[0]"
SINK(key_list[0]) # $ MISSING: flow="SOURCE, l:-3 -> key_list[0]"
def test_dict_values():
d = {'k': SOURCE}
vals = d.values()
val_list = list(vals)
SINK(val_list[0]) #$ flow="SOURCE, l:-3 -> val_list[0]"
SINK(val_list[0]) # $ flow="SOURCE, l:-3 -> val_list[0]"
@expects(4)
def test_dict_items():
@@ -218,43 +218,43 @@ def test_dict_items():
items = d.items()
item_list = list(items)
SINK_F(item_list[0][0]) # expecting FP due to imprecise flow
SINK(item_list[0][1]) #$ flow="SOURCE, l:-4 -> item_list[0][1]"
SINK(item_list[1][0]) #$ MISSING: flow="SOURCE, l:-5 -> item_list[1][0]"
SINK_F(item_list[1][1]) #$ SPURIOUS: flow="SOURCE, l:-6 -> item_list[1][1]"
SINK(item_list[0][1]) # $ flow="SOURCE, l:-4 -> item_list[0][1]"
SINK(item_list[1][0]) # $ MISSING: flow="SOURCE, l:-5 -> item_list[1][0]"
SINK_F(item_list[1][1]) # $ SPURIOUS: flow="SOURCE, l:-6 -> item_list[1][1]"
@expects(3)
def test_dict_pop():
d = {'k': SOURCE}
v = d.pop("k")
SINK(v) #$ flow="SOURCE, l:-2 -> v"
SINK(v) # $ flow="SOURCE, l:-2 -> v"
v1 = d.pop("k", NONSOURCE)
SINK_F(v1) #$ SPURIOUS: flow="SOURCE, l:-4 -> v1"
SINK_F(v1) # $ SPURIOUS: flow="SOURCE, l:-4 -> v1"
v2 = d.pop("non-existing", SOURCE)
SINK(v2) #$ flow="SOURCE, l:-1 -> v2"
SINK(v2) # $ flow="SOURCE, l:-1 -> v2"
@expects(3)
def test_dict_get():
d = {'k': SOURCE}
v = d.get("k")
SINK(v) #$ flow="SOURCE, l:-2 -> v"
SINK(v) # $ flow="SOURCE, l:-2 -> v"
v1 = d.get("non-existing", SOURCE)
SINK(v1) #$ flow="SOURCE, l:-1 -> v1"
SINK(v1) # $ flow="SOURCE, l:-1 -> v1"
k = "k"
v2 = d.get(k)
SINK(v2) #$ flow="SOURCE, l:-7 -> v2"
SINK(v2) # $ flow="SOURCE, l:-7 -> v2"
@expects(2)
def test_dict_popitem():
d = {'k': SOURCE}
t = d.popitem() # could be any pair (before 3.7), but we only have one
SINK_F(t[0])
SINK(t[1]) #$ flow="SOURCE, l:-3 -> t[1]"
SINK(t[1]) # $ flow="SOURCE, l:-3 -> t[1]"
@expects(2)
def test_dict_copy():
d = {'k': SOURCE, 'k1': NONSOURCE}
d1 = d.copy()
SINK(d1["k"]) #$ flow="SOURCE, l:-2 -> d1['k']"
SINK(d1["k"]) # $ flow="SOURCE, l:-2 -> d1['k']"
SINK_F(d1["k1"])
@@ -265,22 +265,22 @@ def test_dict_copy():
def test_sorted_list():
l0 = [SOURCE]
l = sorted(l0)
SINK(l[0]) #$ flow="SOURCE, l:-2 -> l[0]"
SINK(l[0]) # $ flow="SOURCE, l:-2 -> l[0]"
def test_sorted_tuple():
t = (SOURCE,)
l = sorted(t)
SINK(l[0]) #$ flow="SOURCE, l:-2 -> l[0]"
SINK(l[0]) # $ flow="SOURCE, l:-2 -> l[0]"
def test_sorted_set():
s = {SOURCE}
l = sorted(s)
SINK(l[0]) #$ flow="SOURCE, l:-2 -> l[0]"
SINK(l[0]) # $ flow="SOURCE, l:-2 -> l[0]"
def test_sorted_dict():
d = {SOURCE: "val"}
l = sorted(d)
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-2 -> l[0]"
SINK(l[0]) # $ MISSING: flow="SOURCE, l:-2 -> l[0]"
### reversed
@@ -289,16 +289,16 @@ def test_reversed_list():
l0 = [SOURCE, NONSOURCE]
r = reversed(l0)
l = list(r)
SINK_F(l[0]) #$ SPURIOUS: flow="SOURCE, l:-3 -> l[0]"
SINK(l[1]) #$ flow="SOURCE, l:-4 -> l[1]"
SINK_F(l[0]) # $ SPURIOUS: flow="SOURCE, l:-3 -> l[0]"
SINK(l[1]) # $ flow="SOURCE, l:-4 -> l[1]"
@expects(2)
def test_reversed_tuple():
t = (SOURCE, NONSOURCE)
r = reversed(t)
l = list(r)
SINK_F(l[0]) #$ SPURIOUS: flow="SOURCE, l:-3 -> l[0]"
SINK(l[1]) #$ flow="SOURCE, l:-4 -> l[1]"
SINK_F(l[0]) # $ SPURIOUS: flow="SOURCE, l:-3 -> l[0]"
SINK(l[1]) # $ flow="SOURCE, l:-4 -> l[1]"
@expects(2)
def test_reversed_dict():
@@ -306,7 +306,7 @@ def test_reversed_dict():
r = reversed(d)
l = list(r)
SINK_F(l[0])
SINK(l[1]) #$ MISSING: flow="SOURCE, l:-4 -> l[1]"
SINK(l[1]) # $ MISSING: flow="SOURCE, l:-4 -> l[1]"
### iter
@@ -314,32 +314,32 @@ def test_iter_list():
l0 = [SOURCE]
i = iter(l0)
l = list(i)
SINK(l[0]) #$ flow="SOURCE, l:-3 -> l[0]"
SINK(l[0]) # $ flow="SOURCE, l:-3 -> l[0]"
def test_iter_tuple():
t = (SOURCE,)
i = iter(t)
l = list(i)
SINK(l[0]) #$ flow="SOURCE, l:-3 -> l[0]"
SINK(l[0]) # $ flow="SOURCE, l:-3 -> l[0]"
def test_iter_set():
t = {SOURCE}
i = iter(t)
l = list(i)
SINK(l[0]) #$ flow="SOURCE, l:-3 -> l[0]"
SINK(l[0]) # $ flow="SOURCE, l:-3 -> l[0]"
def test_iter_dict():
d = {SOURCE: "val"}
i = iter(d)
l = list(i)
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-3 -> l[0]"
SINK(l[0]) # $ MISSING: flow="SOURCE, l:-3 -> l[0]"
def test_iter_iter():
# applying iter() to the result of iter() is basically a no-op
l0 = [SOURCE]
i = iter(iter(l0))
l = list(i)
SINK(l[0]) #$ flow="SOURCE, l:-3 -> l[0]"
SINK(l[0]) # $ flow="SOURCE, l:-3 -> l[0]"
### next
@@ -347,25 +347,25 @@ def test_next_list():
l = [SOURCE]
i = iter(l)
n = next(i)
SINK(n) #$ flow="SOURCE, l:-3 -> n"
SINK(n) # $ flow="SOURCE, l:-3 -> n"
def test_next_tuple():
t = (SOURCE,)
i = iter(t)
n = next(i)
SINK(n) #$ flow="SOURCE, l:-3 -> n"
SINK(n) # $ flow="SOURCE, l:-3 -> n"
def test_next_set():
s = {SOURCE}
i = iter(s)
n = next(i)
SINK(n) #$ flow="SOURCE, l:-3 -> n"
SINK(n) # $ flow="SOURCE, l:-3 -> n"
def test_next_dict():
d = {SOURCE: "val"}
i = iter(d)
n = next(i)
SINK(n) #$ MISSING: flow="SOURCE, l:-3 -> n"
SINK(n) # $ MISSING: flow="SOURCE, l:-3 -> n"
### map
@@ -375,13 +375,13 @@ def test_map_list():
l2 = [NONSOURCE]
def f(p1,p2):
SINK(p1) #$ flow="SOURCE, l:-4 -> p1"
SINK(p1) # $ flow="SOURCE, l:-4 -> p1"
SINK_F(p2)
return p1,p2
rl = list(map(f, l1, l2))
SINK(rl[0][0]) #$ flow="SOURCE, l:-10 -> rl[0][0]"
SINK(rl[0][0]) # $ flow="SOURCE, l:-10 -> rl[0][0]"
SINK_F(rl[0][1])
@expects(4)
@@ -390,13 +390,13 @@ def test_map_set():
s2 = {NONSOURCE}
def f(p1,p2):
SINK(p1) #$ flow="SOURCE, l:-4 -> p1"
SINK(p1) # $ flow="SOURCE, l:-4 -> p1"
SINK_F(p2)
return p1,p2
rl = list(map(f, s1, s2))
SINK(rl[0][0]) #$ flow="SOURCE, l:-10 -> rl[0][0]"
SINK(rl[0][0]) # $ flow="SOURCE, l:-10 -> rl[0][0]"
SINK_F(rl[0][1])
@expects(4)
@@ -405,13 +405,13 @@ def test_map_tuple():
t2 = (NONSOURCE,)
def f(p1,p2):
SINK(p1) #$ flow="SOURCE, l:-4 -> p1"
SINK(p1) # $ flow="SOURCE, l:-4 -> p1"
SINK_F(p2)
return p1,p2
rl = list(map(f, t1, t2))
SINK(rl[0][0]) #$ flow="SOURCE, l:-10 -> rl[0][0]"
SINK(rl[0][0]) # $ flow="SOURCE, l:-10 -> rl[0][0]"
SINK_F(rl[0][1])
@@ -421,13 +421,13 @@ def test_map_dict():
d2 = {NONSOURCE: "v2"}
def f(p1,p2):
SINK(p1) #$ MISSING: flow="SOURCE, l:-4 -> p1"
SINK(p1) # $ MISSING: flow="SOURCE, l:-4 -> p1"
SINK_F(p2)
return p1,p2
rl = list(map(f, d1, d2))
SINK(rl[0][0]) #$ MISSING: flow="SOURCE, l:-10 -> rl[0][0]"
SINK(rl[0][0]) # $ MISSING: flow="SOURCE, l:-10 -> rl[0][0]"
SINK_F(rl[0][1])
@expects(4)
@@ -436,13 +436,13 @@ def test_map_multi_list():
l2 = [SOURCE]
def f(p1,p2):
SINK(p1) #$ flow="SOURCE, l:-4 -> p1"
SINK(p2) #$ flow="SOURCE, l:-4 -> p2"
SINK(p1) # $ flow="SOURCE, l:-4 -> p1"
SINK(p2) # $ flow="SOURCE, l:-4 -> p2"
return p1,p2
rl = list(map(f, l1, l2))
SINK(rl[0][0]) #$ flow="SOURCE, l:-9 -> rl[0][0]"
SINK(rl[0][1]) #$ flow="SOURCE, l:-9 -> rl[0][1]"
SINK(rl[0][0]) # $ flow="SOURCE, l:-9 -> rl[0][0]"
SINK(rl[0][1]) # $ flow="SOURCE, l:-9 -> rl[0][1]"
@expects(4)
def test_map_multi_tuple():
@@ -450,59 +450,59 @@ def test_map_multi_tuple():
l2 = (SOURCE,)
def f(p1,p2):
SINK(p1) #$ flow="SOURCE, l:-4 -> p1"
SINK(p2) #$ MISSING: flow="SOURCE, l:-4 -> p2" # Tuples are not tracked beyond the first list argument for performance.
SINK(p1) # $ flow="SOURCE, l:-4 -> p1"
SINK(p2) # $ MISSING: flow="SOURCE, l:-4 -> p2" # Tuples are not tracked beyond the first list argument for performance.
return p1,p2
rl = list(map(f, l1, l2))
SINK(rl[0][0]) #$ flow="SOURCE, l:-9 -> rl[0][0]"
SINK(rl[0][1]) #$ MISSING: flow="SOURCE, l:-9 -> rl[0][1]"
SINK(rl[0][0]) # $ flow="SOURCE, l:-9 -> rl[0][0]"
SINK(rl[0][1]) # $ MISSING: flow="SOURCE, l:-9 -> rl[0][1]"
### filter
### filter
@expects(2)
def test_filter_list():
l = [SOURCE]
def f(p):
SINK(p) #$ flow="SOURCE, l:-3 -> p"
return True
SINK(p) # $ flow="SOURCE, l:-3 -> p"
return True
rl = list(filter(f,l))
SINK(rl[0]) #$ flow="SOURCE, l:-7 -> rl[0]"
SINK(rl[0]) # $ flow="SOURCE, l:-7 -> rl[0]"
@expects(2)
def test_filter_set():
s = {SOURCE}
def f(p):
SINK(p) #$ flow="SOURCE, l:-3 -> p"
return True
SINK(p) # $ flow="SOURCE, l:-3 -> p"
return True
rl = list(filter(f,s))
SINK(rl[0]) #$ flow="SOURCE, l:-7 -> rl[0]"
SINK(rl[0]) # $ flow="SOURCE, l:-7 -> rl[0]"
@expects(2)
def test_filter_tuple():
t = (SOURCE,)
def f(p):
SINK(p) #$ flow="SOURCE, l:-3 -> p"
return True
SINK(p) # $ flow="SOURCE, l:-3 -> p"
return True
rl = list(filter(f,t))
SINK(rl[0]) #$ flow="SOURCE, l:-7 -> rl[0]"
SINK(rl[0]) # $ flow="SOURCE, l:-7 -> rl[0]"
@expects(2)
def test_filter_dict():
d = {SOURCE: "v"}
def f(p):
SINK(p) #$ MISSING: flow="SOURCE, l:-3 -> p"
return True
SINK(p) # $ MISSING: flow="SOURCE, l:-3 -> p"
return True
rl = list(filter(f,d))
SINK(rl[0]) #$ MISSING: flow="SOURCE, l:-7 -> rl[0]"
SINK(rl[0]) # $ MISSING: flow="SOURCE, l:-7 -> rl[0]"
@expects(1)
def test_enumerate_list():
@@ -510,7 +510,7 @@ def test_enumerate_list():
e = list(enumerate(l))
SINK(e[0][1]) #$ flow="SOURCE, l:-4 -> e[0][1]"
SINK(e[0][1]) # $ flow="SOURCE, l:-4 -> e[0][1]"
@expects(1)
def test_enumerate_set():
@@ -518,7 +518,7 @@ def test_enumerate_set():
e = list(enumerate(s))
SINK(e[0][1]) #$ flow="SOURCE, l:-4 -> e[0][1]"
SINK(e[0][1]) # $ flow="SOURCE, l:-4 -> e[0][1]"
@expects(1)
def test_enumerate_tuple():
@@ -526,17 +526,17 @@ def test_enumerate_tuple():
e = list(enumerate(t))
SINK(e[0][1]) #$ flow="SOURCE, l:-4 -> e[0][1]"
SINK(e[0][1]) # $ flow="SOURCE, l:-4 -> e[0][1]"
@expects(2)
def test_enumerate_list_for():
l = [SOURCE]
for i, x in enumerate(l):
SINK(x) #$ flow="SOURCE, l:-3 -> x"
SINK(x) # $ flow="SOURCE, l:-3 -> x"
for t in enumerate(l):
SINK(t[1]) #$ flow="SOURCE, l:-6 -> t[1]"
SINK(t[1]) # $ flow="SOURCE, l:-6 -> t[1]"
@expects(1)
def test_enumerate_dict():
@@ -552,16 +552,16 @@ def test_zip_list():
l2 = [SOURCE, NONSOURCE]
l3 = [NONSOURCE, SOURCE]
l4 = [NONSOURCE, NONSOURCE]
z = list(zip(l1,l2,l3,l4))
SINK(z[0][0]) #$ flow="SOURCE, l:-7 -> z[0][0]"
SINK(z[0][1]) #$ flow="SOURCE, l:-7 -> z[0][1]"
SINK_F(z[0][2]) #$ SPURIOUS: flow="SOURCE, l:-7 -> z[0][2]"
SINK(z[0][0]) # $ flow="SOURCE, l:-7 -> z[0][0]"
SINK(z[0][1]) # $ flow="SOURCE, l:-7 -> z[0][1]"
SINK_F(z[0][2]) # $ SPURIOUS: flow="SOURCE, l:-7 -> z[0][2]"
SINK_F(z[0][3])
SINK(z[1][0]) #$ flow="SOURCE, l:-11 -> z[1][0]"
SINK_F(z[1][1]) #$ SPURIOUS: flow="SOURCE, l:-11 -> z[1][1]"
SINK(z[1][2]) #$ flow="SOURCE, l:-11 -> z[1][2]"
SINK(z[1][0]) # $ flow="SOURCE, l:-11 -> z[1][0]"
SINK_F(z[1][1]) # $ SPURIOUS: flow="SOURCE, l:-11 -> z[1][1]"
SINK(z[1][2]) # $ flow="SOURCE, l:-11 -> z[1][2]"
SINK_F(z[1][3])
@expects(4)
@@ -570,12 +570,12 @@ def test_zip_set():
s2 = {NONSOURCE}
s3 = {SOURCE}
s4 = {NONSOURCE}
z = list(zip(s1,s2,s3,s4))
SINK(z[0][0]) #$ flow="SOURCE, l:-7 -> z[0][0]"
SINK(z[0][0]) # $ flow="SOURCE, l:-7 -> z[0][0]"
SINK_F(z[0][1])
SINK(z[0][2]) #$ flow="SOURCE, l:-7 -> z[0][2]"
SINK(z[0][2]) # $ flow="SOURCE, l:-7 -> z[0][2]"
SINK_F(z[0][3])
@expects(8)
@@ -584,16 +584,16 @@ def test_zip_tuple():
t2 = (SOURCE, NONSOURCE)
t3 = (NONSOURCE, SOURCE)
t4 = (NONSOURCE, NONSOURCE)
z = list(zip(t1,t2,t3,t4))
SINK(z[0][0]) #$ flow="SOURCE, l:-7 -> z[0][0]"
SINK(z[0][1]) #$ flow="SOURCE, l:-7 -> z[0][1]"
SINK_F(z[0][2])
SINK(z[0][0]) # $ flow="SOURCE, l:-7 -> z[0][0]"
SINK(z[0][1]) # $ flow="SOURCE, l:-7 -> z[0][1]"
SINK_F(z[0][2])
SINK_F(z[0][3])
SINK(z[1][0]) #$ flow="SOURCE, l:-11 -> z[1][0]"
SINK_F(z[1][1]) #$ SPURIOUS: flow="SOURCE, l:-11 -> z[1][1]"
SINK(z[1][2]) #$ MISSING: flow="SOURCE, l:-11 -> z[1][2]" # Tuple contents are not tracked beyond the first two arguments for performance.
SINK(z[1][0]) # $ flow="SOURCE, l:-11 -> z[1][0]"
SINK_F(z[1][1]) # $ SPURIOUS: flow="SOURCE, l:-11 -> z[1][1]"
SINK(z[1][2]) # $ MISSING: flow="SOURCE, l:-11 -> z[1][2]" # Tuple contents are not tracked beyond the first two arguments for performance.
SINK_F(z[1][3])
@expects(4)
@@ -602,10 +602,10 @@ def test_zip_dict():
d2 = {NONSOURCE: "v"}
d3 = {SOURCE: "v"}
d4 = {NONSOURCE: "v"}
z = list(zip(d1,d2,d3,d4))
SINK(z[0][0]) #$ MISSING: flow="SOURCE, l:-7 -> z[0][0]"
SINK_F(z[0][1])
SINK(z[0][2]) #$ MISSING: flow="SOURCE, l:-7 -> z[0][2]"
SINK_F(z[0][3])
SINK(z[0][0]) # $ MISSING: flow="SOURCE, l:-7 -> z[0][0]"
SINK_F(z[0][1])
SINK(z[0][2]) # $ MISSING: flow="SOURCE, l:-7 -> z[0][2]"
SINK_F(z[0][3])

View File

@@ -1 +1 @@
known_attr = [1000] #$ writes=known_attr
known_attr = [1000] # $ writes=known_attr

View File

@@ -2,15 +2,15 @@
# Simple assignment
g = [5] # $writes=g
g = [5] # $ writes=g
# Multiple assignment
g1, g2 = [6], [7] # $writes=g1 writes=g2
g1, g2 = [6], [7] # $ writes=g1 writes=g2
# Assignment that's only referenced in this scope.
unreferenced_g = [8] # $writes=unreferenced_g
unreferenced_g = [8] # $ writes=unreferenced_g
print(unreferenced_g)
# Testing modifications of globals
@@ -24,49 +24,49 @@ g_mod = []
# but currently our analysis thinks `g_mod` might be used in the `print` call
g_mod = [10] # $ SPURIOUS: writes=g_mod
print("foo")
g_mod = [100] # $writes=g_mod
g_mod = [100] # $ writes=g_mod
# Modification by mutation
g_ins = [50] # $writes=g_ins
g_ins = [50] # $ writes=g_ins
print(g_ins)
g_ins.append(75)
# A global with multiple potential definitions
import unknown_module # $writes=unknown_module
import unknown_module # $ writes=unknown_module
if unknown_module.attr:
g_mult = [200] # $writes=g_mult
g_mult = [200] # $ writes=g_mult
else:
g_mult = [300] # $writes=g_mult
g_mult = [300] # $ writes=g_mult
# A global variable that may be redefined depending on some unknown value
g_redef = [400] # $writes=g_redef
g_redef = [400] # $ writes=g_redef
if unknown_module.attr:
g_redef = [500] # $writes=g_redef
g_redef = [500] # $ writes=g_redef
def global_access(): # $writes=global_access
def global_access(): # $ writes=global_access
l = 5
print(g) # $reads=g
print(g1) # $reads=g1
print(g2) # $reads=g2
print(g_mod) # $reads=g_mod
print(g_ins) # $reads=g_ins
print(g_mult) # $reads=g_mult
print(g_redef) # $reads=g_redef
print(g) # $ reads=g
print(g1) # $ reads=g1
print(g2) # $ reads=g2
print(g_mod) # $ reads=g_mod
print(g_ins) # $ reads=g_ins
print(g_mult) # $ reads=g_mult
print(g_redef) # $ reads=g_redef
def print_g_mod(): # $writes=print_g_mod
print(g_mod) # $reads=g_mod
def print_g_mod(): # $ writes=print_g_mod
print(g_mod) # $ reads=g_mod
def global_mod(): # $writes=global_mod
def global_mod(): # $ writes=global_mod
global g_mod
g_mod += [150] # $reads,writes=g_mod
print_g_mod() # $reads=print_g_mod
g_mod += [150] # $ reads,writes=g_mod
print_g_mod() # $ reads=print_g_mod
def global_inside_local_function(): # $writes=global_inside_local_function
def global_inside_local_function(): # $ writes=global_inside_local_function
def local_function():
print(g) # $reads=g
print(g) # $ reads=g
local_function()
## Imports
@@ -74,24 +74,24 @@ def global_inside_local_function(): # $writes=global_inside_local_function
# Direct imports
import foo_module # $writes=foo_module
import foo_module # $ writes=foo_module
def use_foo(): # $writes=use_foo
print(foo_module.attr) # $reads=foo_module
def use_foo(): # $ writes=use_foo
print(foo_module.attr) # $ reads=foo_module
# Partial imports
from bar import baz_attr, quux_attr # $writes=baz_attr writes=quux_attr
from bar import baz_attr, quux_attr # $ writes=baz_attr writes=quux_attr
def use_partial_import(): # $writes=use_partial_import
print(baz_attr, quux_attr) # $reads=baz_attr reads=quux_attr
def use_partial_import(): # $ writes=use_partial_import
print(baz_attr, quux_attr) # $ reads=baz_attr reads=quux_attr
# Aliased imports
from spam_module import ham_attr as eggs_attr # $writes=eggs_attr
from spam_module import ham_attr as eggs_attr # $ writes=eggs_attr
def use_aliased_import(): # $writes=use_aliased_import
print(eggs_attr) # $reads=eggs_attr
def use_aliased_import(): # $ writes=use_aliased_import
print(eggs_attr) # $ reads=eggs_attr
# Import star (unlikely to work unless we happen to extract/model the referenced module)
@@ -99,23 +99,23 @@ def use_aliased_import(): # $writes=use_aliased_import
from unknown import *
def secretly_use_unknown(): # $writes=secretly_use_unknown
print(unknown_attr) # $reads=unknown_attr
def secretly_use_unknown(): # $ writes=secretly_use_unknown
print(unknown_attr) # $ reads=unknown_attr
# Known modules
from known import *
def secretly_use_known(): # $writes=secretly_use_known
print(known_attr) # $reads=known_attr
def secretly_use_known(): # $ writes=secretly_use_known
print(known_attr) # $ reads=known_attr
# Local import in function
def imports_locally(): # $writes=imports_locally
def imports_locally(): # $ writes=imports_locally
import mod1
# Global import hidden in function
def imports_stuff(): # $writes=imports_stuff
def imports_stuff(): # $ writes=imports_stuff
global mod2
import mod2 # $writes=mod2
import mod2 # $ writes=mod2

View File

@@ -1,4 +1,4 @@
import threading
import threading
import time
# Test 1
@@ -7,11 +7,11 @@ foo1 = None
def bar1():
time.sleep(1)
ensure_tainted(foo1) # $tainted
ensure_tainted(foo1) # $ tainted
# The intent of these tests is to test how dataflow is handled through shared state accessed by different threads;
# The intent of these tests is to test how dataflow is handled through shared state accessed by different threads;
# but the presense or absense of the actual call to start a thread does not affect the results (there is no special modelling for Thread)
# threading.Thread(target=bar).start()
# threading.Thread(target=bar).start()
foo1 = TAINTED_STRING
@@ -21,7 +21,7 @@ foo2 = []
def bar2():
time.sleep(1)
ensure_tainted(foo2[0]) # $MISSING:tainted
ensure_tainted(foo2[0]) # $ MISSING:tainted
threading.Thread(target=bar2).start()
@@ -33,7 +33,7 @@ foo3 = []
def bar3():
time.sleep(1)
ensure_tainted(foo2[0]) # $MISSING:tainted
ensure_tainted(foo2[0]) # $ MISSING:tainted
foo3.append(TAINTED_STRING)
bar3()
@@ -42,16 +42,16 @@ bar3()
# TP - Sanity check: Flow is found through a ListElement directly without a call
foo4 = []
foo4.append(TAINTED_STRING)
ensure_tainted(foo4[0]) # $tainted
ensure_tainted(foo4[0]) # $ tainted
# Test 5
# FN - Flow is *not* tracked through a shared captured but non-global variable
def test5():
foo5 = None
foo5 = None
def bar5():
time.sleep(1)
ensure_tainted(foo5) # $MISSING:tainted
ensure_tainted(foo5) # $ MISSING:tainted
threading.Thread(target=bar5).start() # Only the presense of this thread call makes this an FN rather than a TN
@@ -64,7 +64,7 @@ def test6():
def bar6():
time.sleep(1)
ensure_tainted(foo6[0]) # $tainted
ensure_tainted(foo6[0]) # $ tainted
foo6.append(TAINTED_STRING)
bar6()
@@ -78,7 +78,7 @@ foo7 = []
def bar7():
time.sleep(1)
ensure_tainted(foo7[0]) # $MISSING: tainted
ensure_tainted(foo7[0]) # $ MISSING: tainted
def baz7(loc_foo):
loc_foo.append(TAINTED_STRING)
@@ -88,13 +88,13 @@ threading.Thread(target=bar7).start()
baz7(foo7)
# Test 8
# FN - Flow is also *not* found in the above case through a direct call
# FN - Flow is also *not* found in the above case through a direct call
foo8 = []
def bar8():
time.sleep(1)
ensure_tainted(foo8[0]) # $MISSING: tainted
ensure_tainted(foo8[0]) # $ MISSING: tainted
def baz8(loc_foo):
loc_foo.append(TAINTED_STRING)
@@ -109,10 +109,10 @@ def test9():
foo9 = []
def bar9():
time.sleep(1)
ensure_tainted(foo9[0]) # $tainted
ensure_tainted(foo9[0]) # $ tainted
def baz9(loc_foo):
loc_foo.append(TAINTED_STRING)
baz9(foo9)
bar9()
bar9()

View File

@@ -29,32 +29,32 @@ def SINK_F(x):
def test_guard():
match SOURCE:
case x if SINK(x): #$ flow="SOURCE, l:-1 -> x"
case x if SINK(x): # $ flow="SOURCE, l:-1 -> x"
pass
@expects(2)
def test_as_pattern():
match SOURCE:
case x as y:
SINK(x) #$ flow="SOURCE, l:-2 -> x"
SINK(y) #$ flow="SOURCE, l:-3 -> y"
SINK(x) # $ flow="SOURCE, l:-2 -> x"
SINK(y) # $ flow="SOURCE, l:-3 -> y"
def test_or_pattern():
match SOURCE:
# We cannot use NONSOURCE in place of "" below, since it would be seen as a variable.
case ("" as x) | x:
SINK(x) #$ flow="SOURCE, l:-3 -> x"
SINK(x) # $ flow="SOURCE, l:-3 -> x"
# No flow for literal pattern
def test_literal_pattern():
match SOURCE:
case "source" as x:
SINK(x) #$ flow="SOURCE, l:-2 -> x" flow="'source', l:-1 -> x"
SINK(x) # $ flow="SOURCE, l:-2 -> x" flow="'source', l:-1 -> x"
def test_capture_pattern():
match SOURCE:
case x:
SINK(x) #$ flow="SOURCE, l:-2 -> x"
SINK(x) # $ flow="SOURCE, l:-2 -> x"
# No flow for wildcard pattern
@@ -64,21 +64,21 @@ class Unsafe:
def test_value_pattern():
match SOURCE:
case Unsafe.VALUE as x:
SINK(x) #$ flow="SOURCE, l:-2 -> x" flow="SOURCE, l:-5 -> x"
SINK(x) # $ flow="SOURCE, l:-2 -> x" flow="SOURCE, l:-5 -> x"
@expects(2)
def test_sequence_pattern_tuple():
match (NONSOURCE, SOURCE):
case (x, y):
SINK_F(x)
SINK(y) #$ flow="SOURCE, l:-3 -> y"
SINK(y) # $ flow="SOURCE, l:-3 -> y"
@expects(2)
def test_sequence_pattern_list():
match [NONSOURCE, SOURCE]:
case [x, y]:
SINK_F(x) #$ SPURIOUS: flow="SOURCE, l:-2 -> x"
SINK(y) #$ flow="SOURCE, l:-3 -> y"
SINK_F(x) # $ SPURIOUS: flow="SOURCE, l:-2 -> x"
SINK(y) # $ flow="SOURCE, l:-3 -> y"
# Sets are excluded from sequence patterns,
# see https://www.python.org/dev/peps/pep-0635/#sequence-patterns
@@ -88,35 +88,35 @@ def test_star_pattern_tuple():
match (NONSOURCE, SOURCE):
case (x, *y):
SINK_F(x)
SINK(y[0]) #$ flow="SOURCE, l:-3 -> y[0]"
SINK(y[0]) # $ flow="SOURCE, l:-3 -> y[0]"
@expects(2)
def test_star_pattern_tuple_exclusion():
match (SOURCE, NONSOURCE):
case (x, *y):
SINK(x) #$ flow="SOURCE, l:-2 -> x"
SINK(x) # $ flow="SOURCE, l:-2 -> x"
SINK_F(y[0])
@expects(2)
def test_star_pattern_list():
match [NONSOURCE, SOURCE]:
case [x, *y]:
SINK_F(x) #$ SPURIOUS: flow="SOURCE, l:-2 -> x"
SINK(y[0]) #$ flow="SOURCE, l:-3 -> y[0]"
SINK_F(x) # $ SPURIOUS: flow="SOURCE, l:-2 -> x"
SINK(y[0]) # $ flow="SOURCE, l:-3 -> y[0]"
@expects(2)
def test_star_pattern_list_exclusion():
match [SOURCE, NONSOURCE]:
case [x, *y]:
SINK(x) #$ flow="SOURCE, l:-2 -> x"
SINK_F(y[0]) #$ SPURIOUS: flow="SOURCE, l:-3 -> y[0]"
SINK(x) # $ flow="SOURCE, l:-2 -> x"
SINK_F(y[0]) # $ SPURIOUS: flow="SOURCE, l:-3 -> y[0]"
@expects(2)
def test_mapping_pattern():
match {"a": NONSOURCE, "b": SOURCE}:
case {"a": x, "b": y}:
SINK_F(x)
SINK(y) #$ flow="SOURCE, l:-3 -> y"
SINK(y) # $ flow="SOURCE, l:-3 -> y"
# also tests the key value pattern
@expects(2)
@@ -124,13 +124,13 @@ def test_double_star_pattern():
match {"a": NONSOURCE, "b": SOURCE}:
case {"a": x, **y}:
SINK_F(x)
SINK(y["b"]) #$ flow="SOURCE, l:-3 -> y['b']"
SINK(y["b"]) # $ flow="SOURCE, l:-3 -> y['b']"
@expects(2)
def test_double_star_pattern_exclusion():
match {"a": SOURCE, "b": NONSOURCE}:
case {"a": x, **y}:
SINK(x) #$ flow="SOURCE, l:-2 -> x"
SINK(x) # $ flow="SOURCE, l:-2 -> x"
SINK_F(y["b"])
try:
SINK_F(y["a"])
@@ -149,7 +149,7 @@ def test_class_pattern():
match bad_cell:
case Cell(value = x):
SINK(x) #$ flow="SOURCE, l:-5 -> x"
SINK(x) # $ flow="SOURCE, l:-5 -> x"
match good_cell:
case Cell(value = x):

View File

@@ -182,7 +182,7 @@ SINK(instance.instance_method(SOURCE)[1]) # $ flow="SOURCE -> instance.instance
returned_class = get_class()
SINK(returned_class(SOURCE).config) # $ flow="SOURCE -> returned_class(..).config"
SINK(returned_class().instance_method(SOURCE)[1]) # $flow="SOURCE -> returned_class().instance_method(..)[1]"
SINK(returned_class().instance_method(SOURCE)[1]) # $ flow="SOURCE -> returned_class().instance_method(..)[1]"
fatory_instance = MS_Factory.get_instance()
SINK(fatory_instance.instance_method(SOURCE)[1]) # $ flow="SOURCE -> fatory_instance.instance_method(..)[1]"

View File

@@ -1,42 +1,42 @@
import sys #$ importTimeFlow="ImportExpr -> sys"
import os #$ importTimeFlow="ImportExpr -> os"
import sys # $ importTimeFlow="ImportExpr -> sys"
import os # $ importTimeFlow="ImportExpr -> os"
sys.path.append(os.path.dirname(os.path.dirname((__file__))))
from testlib import expects #$ importTimeFlow="ImportMember -> expects"
from testlib import expects # $ importTimeFlow="ImportMember -> expects"
# These are defined so that we can evaluate the test code.
NONSOURCE = "not a source" #$ importTimeFlow="'not a source' -> NONSOURCE"
SOURCE = "source" #$ importTimeFlow="'source' -> SOURCE"
NONSOURCE = "not a source" # $ importTimeFlow="'not a source' -> NONSOURCE"
SOURCE = "source" # $ importTimeFlow="'source' -> SOURCE"
def is_source(x): #$ importTimeFlow="FunctionExpr -> is_source"
def is_source(x): # $ importTimeFlow="FunctionExpr -> is_source"
return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j
def SINK(x): #$ importTimeFlow="FunctionExpr -> SINK"
if is_source(x): #$ runtimeFlow="ModuleVariableNode in Module multiphase for is_source, l:-17 -> is_source"
print("OK") #$ runtimeFlow="ModuleVariableNode in Module multiphase for print, l:-18 -> print"
def SINK(x): # $ importTimeFlow="FunctionExpr -> SINK"
if is_source(x): # $ runtimeFlow="ModuleVariableNode in Module multiphase for is_source, l:-17 -> is_source"
print("OK") # $ runtimeFlow="ModuleVariableNode in Module multiphase for print, l:-18 -> print"
else:
print("Unexpected flow", x) #$ runtimeFlow="ModuleVariableNode in Module multiphase for print, l:-20 -> print"
print("Unexpected flow", x) # $ runtimeFlow="ModuleVariableNode in Module multiphase for print, l:-20 -> print"
def SINK_F(x): #$ importTimeFlow="FunctionExpr -> SINK_F"
if is_source(x): #$ runtimeFlow="ModuleVariableNode in Module multiphase for is_source, l:-24 -> is_source"
print("Unexpected flow", x) #$ runtimeFlow="ModuleVariableNode in Module multiphase for print, l:-25 -> print"
def SINK_F(x): # $ importTimeFlow="FunctionExpr -> SINK_F"
if is_source(x): # $ runtimeFlow="ModuleVariableNode in Module multiphase for is_source, l:-24 -> is_source"
print("Unexpected flow", x) # $ runtimeFlow="ModuleVariableNode in Module multiphase for print, l:-25 -> print"
else:
print("OK") #$ runtimeFlow="ModuleVariableNode in Module multiphase for print, l:-27 -> print"
print("OK") # $ runtimeFlow="ModuleVariableNode in Module multiphase for print, l:-27 -> print"
def set_foo(): #$ importTimeFlow="FunctionExpr -> set_foo"
def set_foo(): # $ importTimeFlow="FunctionExpr -> set_foo"
global foo
foo = SOURCE #$ runtimeFlow="ModuleVariableNode in Module multiphase for SOURCE, l:-31 -> SOURCE" # missing final definition of foo
foo = SOURCE # $ runtimeFlow="ModuleVariableNode in Module multiphase for SOURCE, l:-31 -> SOURCE" # missing final definition of foo
foo = NONSOURCE #$ importTimeFlow="NONSOURCE -> foo"
foo = NONSOURCE # $ importTimeFlow="NONSOURCE -> foo"
set_foo()
@expects(2)
def test_phases(): #$ importTimeFlow="expects(..)(..), l:-1 -> test_phases"
def test_phases(): # $ importTimeFlow="expects(..)(..), l:-1 -> test_phases"
global foo
SINK(foo) #$ runtimeFlow="ModuleVariableNode in Module multiphase for SINK, l:-39 -> SINK" runtimeFlow="ModuleVariableNode in Module multiphase for foo, l:-39 -> foo"
foo = NONSOURCE #$ runtimeFlow="ModuleVariableNode in Module multiphase for NONSOURCE, l:-40 -> NONSOURCE"
set_foo() #$ runtimeFlow="ModuleVariableNode in Module multiphase for set_foo, l:-41 -> set_foo"
SINK(foo) #$ runtimeFlow="ModuleVariableNode in Module multiphase for SINK, l:-42 -> SINK" runtimeFlow="ModuleVariableNode in Module multiphase for foo, l:-42 -> foo"
SINK(foo) # $ runtimeFlow="ModuleVariableNode in Module multiphase for SINK, l:-39 -> SINK" runtimeFlow="ModuleVariableNode in Module multiphase for foo, l:-39 -> foo"
foo = NONSOURCE # $ runtimeFlow="ModuleVariableNode in Module multiphase for NONSOURCE, l:-40 -> NONSOURCE"
set_foo() # $ runtimeFlow="ModuleVariableNode in Module multiphase for set_foo, l:-41 -> set_foo"
SINK(foo) # $ runtimeFlow="ModuleVariableNode in Module multiphase for SINK, l:-42 -> SINK" runtimeFlow="ModuleVariableNode in Module multiphase for foo, l:-42 -> foo"

View File

@@ -2,32 +2,32 @@ class SomeClass:
pass
def simple_read_write():
x = SomeClass() # $tracked=foo
x.foo = tracked # $tracked tracked=foo
y = x.foo # $tracked=foo tracked
do_stuff(y) # $tracked
x = SomeClass() # $ tracked=foo
x.foo = tracked # $ tracked tracked=foo
y = x.foo # $ tracked=foo tracked
do_stuff(y) # $ tracked
def foo():
x = SomeClass() # $tracked=attr
bar(x) # $tracked=attr
x.attr = tracked # $tracked=attr tracked
baz(x) # $tracked=attr
x = SomeClass() # $ tracked=attr
bar(x) # $ tracked=attr
x.attr = tracked # $ tracked=attr tracked
baz(x) # $ tracked=attr
def bar(x): # $tracked=attr
z = x.attr # $tracked tracked=attr
do_stuff(z) # $tracked
def bar(x): # $ tracked=attr
z = x.attr # $ tracked tracked=attr
do_stuff(z) # $ tracked
def expects_int(x): # $int=field SPURIOUS: str=field
do_int_stuff(x.field) # $int int=field SPURIOUS: str str=field
def expects_int(x): # $ int=field SPURIOUS: str=field
do_int_stuff(x.field) # $ int int=field SPURIOUS: str str=field
def expects_string(x): # $ str=field SPURIOUS: int=field
do_string_stuff(x.field) # $str str=field SPURIOUS: int int=field
do_string_stuff(x.field) # $ str str=field SPURIOUS: int int=field
def test_incompatible_types():
x = SomeClass() # $int,str=field
x.field = int(5) # $int=field int SPURIOUS: str=field
expects_int(x) # $int=field SPURIOUS: str=field
x.field = str("Hello") # $str=field str SPURIOUS: int=field
x = SomeClass() # $ int,str=field
x.field = int(5) # $ int=field int SPURIOUS: str=field
expects_int(x) # $ int=field SPURIOUS: str=field
x.field = str("Hello") # $ str=field str SPURIOUS: int=field
expects_string(x) # $ str=field SPURIOUS: int=field
# set in different function
@@ -58,7 +58,7 @@ def test_global_attribute_read():
def test_local_attribute_assignment():
# Same as `test_global_attribute_assignment`, but the assigned variable is not global
# In this case, we don't want flow going to the `ModuleVariableNode` for `local_var`
# In this case, we don't want flow going to the `ModuleVariableNode` for `local_var`
# (which is referenced in `test_local_attribute_read`).
local_var = object() # $ tracked=foo
local_var.foo = tracked # $ tracked tracked=foo
@@ -71,11 +71,11 @@ def test_local_attribute_read():
# Attributes assigned statically to a class
# ------------------------------------------------------------------------------
class MyClass: # $tracked=field
field = tracked # $tracked
class MyClass: # $ tracked=field
field = tracked # $ tracked
lookup = MyClass.field # $tracked tracked=field
instance = MyClass() # $tracked=field
lookup = MyClass.field # $ tracked tracked=field
instance = MyClass() # $ tracked=field
lookup2 = instance.field # MISSING: tracked
# ------------------------------------------------------------------------------
@@ -85,56 +85,56 @@ lookup2 = instance.field # MISSING: tracked
# Via `getattr`/`setattr`
def setattr_immediate_write():
x = SomeClass() # $tracked=foo
setattr(x,"foo", tracked) # $tracked tracked=foo
y = x.foo # $tracked tracked=foo
do_stuff(y) # $tracked
x = SomeClass() # $ tracked=foo
setattr(x,"foo", tracked) # $ tracked tracked=foo
y = x.foo # $ tracked tracked=foo
do_stuff(y) # $ tracked
def getattr_immediate_read():
x = SomeClass() # $tracked=foo
x.foo = tracked # $tracked tracked=foo
y = getattr(x,"foo") # $tracked tracked=foo
do_stuff(y) # $tracked
x = SomeClass() # $ tracked=foo
x.foo = tracked # $ tracked tracked=foo
y = getattr(x,"foo") # $ tracked tracked=foo
do_stuff(y) # $ tracked
def setattr_indirect_write():
attr = "foo"
x = SomeClass() # $tracked=foo
setattr(x, attr, tracked) # $tracked tracked=foo
y = x.foo # $tracked tracked=foo
do_stuff(y) # $tracked
x = SomeClass() # $ tracked=foo
setattr(x, attr, tracked) # $ tracked tracked=foo
y = x.foo # $ tracked tracked=foo
do_stuff(y) # $ tracked
def getattr_indirect_read():
attr = "foo"
x = SomeClass() # $tracked=foo
x.foo = tracked # $tracked tracked=foo
y = getattr(x, attr) #$tracked tracked=foo
do_stuff(y) # $tracked
x = SomeClass() # $ tracked=foo
x.foo = tracked # $ tracked tracked=foo
y = getattr(x, attr) # $ tracked tracked=foo
do_stuff(y) # $ tracked
# Via `__dict__` -- not currently implemented.
def dunder_dict_immediate_write():
x = SomeClass() # $ MISSING: tracked=foo
x.__dict__["foo"] = tracked # $tracked MISSING: tracked=foo
x.__dict__["foo"] = tracked # $ tracked MISSING: tracked=foo
y = x.foo # $ MISSING: tracked tracked=foo
do_stuff(y) # $ MISSING: tracked
def dunder_dict_immediate_read():
x = SomeClass() # $tracked=foo
x.foo = tracked # $tracked tracked=foo
x = SomeClass() # $ tracked=foo
x.foo = tracked # $ tracked tracked=foo
y = x.__dict__["foo"] # $ tracked=foo MISSING: tracked
do_stuff(y) # $ MISSING: tracked
def dunder_dict_indirect_write():
attr = "foo"
x = SomeClass() # $ MISSING: tracked=foo
x.__dict__[attr] = tracked # $tracked MISSING: tracked=foo
x.__dict__[attr] = tracked # $ tracked MISSING: tracked=foo
y = x.foo # $ MISSING: tracked tracked=foo
do_stuff(y) # $ MISSING: tracked
def dunder_dict_indirect_read():
attr = "foo"
x = SomeClass() # $tracked=foo
x.foo = tracked # $tracked tracked=foo
x = SomeClass() # $ tracked=foo
x.foo = tracked # $ tracked tracked=foo
y = x.__dict__[attr] # $ tracked=foo MISSING: tracked
do_stuff(y) # $ MISSING: tracked

View File

@@ -1,12 +1,12 @@
# test of other content types than attributes
def test_tuple(index_arg):
tup = (tracked, other) # $tracked
tup = (tracked, other) # $ tracked
tup[0] # $ tracked
tup[1]
a,b = tup # $tracked
a,b = tup # $ tracked
a # $ tracked
b
@@ -22,7 +22,7 @@ def test_tuple(index_arg):
# nested tuples
nested_tuples = ((tracked, other), (other, tracked)) # $tracked
nested_tuples = ((tracked, other), (other, tracked)) # $ tracked
nested_tuples[0][0] # $ MISSING: tracked
nested_tuples[0][1]
@@ -44,7 +44,7 @@ def test_tuple(index_arg):
def test_dict(key_arg):
d1 = {"t": tracked, "o": other} # $tracked
d1 = {"t": tracked, "o": other} # $ tracked
d1["t"] # $ tracked
d1.get("t") # $ MISSING: tracked
d1.setdefault("t") # $ MISSING: tracked
@@ -84,7 +84,7 @@ def test_dict(key_arg):
def test_list(index_arg):
l = [tracked, other] # $tracked
l = [tracked, other] # $ tracked
l[0] # $ MISSING: tracked
l[1]

View File

@@ -1,9 +1,9 @@
def foo(foo_x): # $tracked
print("foo", foo_x) # $tracked
def foo(foo_x): # $ tracked
print("foo", foo_x) # $ tracked
def bar(bar_x): # $tracked
print("bar", bar_x) # $tracked
def bar(bar_x): # $ tracked
print("bar", bar_x) # $ tracked
if len(__file__) % 2 == 0:
@@ -11,5 +11,5 @@ if len(__file__) % 2 == 0:
else:
f = bar
x = tracked # $tracked
f(x) # $tracked
x = tracked # $ tracked
f(x) # $ tracked

View File

@@ -1,7 +1,7 @@
x = tracked # $tracked
x = tracked # $ tracked
def func():
return tracked # $tracked
return tracked # $ tracked
z = tracked # $tracked
some_func(z) # $tracked
z = tracked # $ tracked
some_func(z) # $ tracked

View File

@@ -1,64 +1,64 @@
def get_tracked():
x = tracked # $tracked
return x # $tracked
x = tracked # $ tracked
return x # $ tracked
def use_tracked_foo(x): # $tracked
do_stuff(x) # $tracked
def use_tracked_foo(x): # $ tracked
do_stuff(x) # $ tracked
def foo():
use_tracked_foo(
get_tracked() # $tracked
get_tracked() # $ tracked
)
def use_tracked_bar(x): # $tracked
do_stuff(x) # $tracked
def use_tracked_bar(x): # $ tracked
do_stuff(x) # $ tracked
def bar():
x = get_tracked() # $tracked
use_tracked_bar(x) # $tracked
x = get_tracked() # $ tracked
use_tracked_bar(x) # $ tracked
def use_tracked_baz(x): # $tracked
do_stuff(x) # $tracked
def use_tracked_baz(x): # $ tracked
do_stuff(x) # $ tracked
def baz():
x = tracked # $tracked
use_tracked_baz(x) # $tracked
x = tracked # $ tracked
use_tracked_baz(x) # $ tracked
def id(x): # $tracked
return x # $tracked
def id(x): # $ tracked
return x # $ tracked
def use_tracked_quux(x): # $ MISSING: tracked
do_stuff(y) # call after return -- not tracked in here.
def quux():
x = tracked # $tracked
y = id(x) # $tracked
x = tracked # $ tracked
y = id(x) # $ tracked
use_tracked_quux(y) # not tracked out of call to id.
g = None
def write_g(x): # $tracked
def write_g(x): # $ tracked
global g
g = x # $tracked
g = x # $ tracked
def use_g():
do_stuff(g) # $tracked
do_stuff(g) # $ tracked
def global_var_write_test():
x = tracked # $tracked
write_g(x) # $tracked
x = tracked # $ tracked
write_g(x) # $ tracked
use_g()
def test_import():
import mymodule
mymodule.x # $tracked
y = mymodule.func() # $tracked
y # $tracked
mymodule.z # $tracked
mymodule.x # $ tracked
y = mymodule.func() # $ tracked
y # $ tracked
mymodule.z # $ tracked
def to_inner_scope():
x = tracked # $tracked
x = tracked # $ tracked
def foo():
y = x # $ tracked
return y # $ tracked
@@ -67,15 +67,15 @@ def to_inner_scope():
def from_parameter_default():
x_alias = tracked # $tracked
def outer(x=tracked): # $tracked
print(x) # $tracked
x_alias = tracked # $ tracked
def outer(x=tracked): # $ tracked
print(x) # $ tracked
def inner():
print(x) # $ tracked
print(x_alias) # $tracked
return x # $tracked
also_x = outer() # $tracked
print(also_x) # $tracked
print(x_alias) # $ tracked
return x # $ tracked
also_x = outer() # $ tracked
print(also_x) # $ tracked
# ------------------------------------------------------------------------------
@@ -86,7 +86,7 @@ def my_decorator(func):
# This part doesn't make any sense in a normal decorator, but just shows how we
# handle type-tracking
func() # $tracked
func() # $ tracked
def wrapper():
print("before function call")
@@ -97,7 +97,7 @@ def my_decorator(func):
@my_decorator
def get_tracked2():
return tracked # $tracked
return tracked # $ tracked
@my_decorator
def unrelated_func():
@@ -109,17 +109,17 @@ def use_funcs_with_decorators():
# ------------------------------------------------------------------------------
def expects_int(x): # $int
do_int_stuff(x) # $int
def expects_int(x): # $ int
do_int_stuff(x) # $ int
def expects_string(x): # $str
do_string_stuff(x) # $str
def expects_string(x): # $ str
do_string_stuff(x) # $ str
def redefine_test():
x = int(5) # $int
expects_int(x) # $int
x = str("Hello") # $str
expects_string(x) # $str
x = int(5) # $ int
expects_int(x) # $ int
x = str("Hello") # $ str
expects_string(x) # $ str
# ------------------------------------------------------------------------------
# Tracking of self in methods

View File

@@ -33,7 +33,7 @@ def SINK_F(x):
def by_value1():
a = SOURCE
def inner(a_val=a):
SINK(a_val) #$ captured
SINK(a_val) # $ captured
SINK_F(a)
a = NONSOURCE
inner()
@@ -41,7 +41,7 @@ def by_value1():
def by_value2():
a = NONSOURCE
def inner(a_val=a):
SINK(a) #$ captured
SINK(a) # $ captured
SINK_F(a_val)
a = SOURCE
inner()

View File

@@ -37,7 +37,7 @@ def out():
def captureOut1():
sinkO1["x"] = SOURCE
captureOut1()
SINK(sinkO1["x"]) #$ captured
SINK(sinkO1["x"]) # $ captured
sinkO2 = { "x": "" }
def captureOut2():
@@ -45,7 +45,7 @@ def out():
sinkO2["x"] = SOURCE
m()
captureOut2()
SINK(sinkO2["x"]) #$ captured
SINK(sinkO2["x"]) # $ captured
nonSink0 = { "x": "" }
def captureOut1NotCalled():
@@ -67,7 +67,7 @@ def through(tainted):
def captureOut1():
sinkO1["x"] = tainted
captureOut1()
SINK(sinkO1["x"]) #$ captured
SINK(sinkO1["x"]) # $ captured
sinkO2 = { "x": "" }
def captureOut2():
@@ -75,7 +75,7 @@ def through(tainted):
sinkO2["x"] = tainted
m()
captureOut2()
SINK(sinkO2["x"]) #$ captured
SINK(sinkO2["x"]) # $ captured
nonSink1 = { "x": "" }
def captureOut1NotCalled():

View File

@@ -42,7 +42,7 @@ def out():
global sinkO1
sinkO1 = SOURCE
captureOut1()
SINK(sinkO1) #$ captured
SINK(sinkO1) # $ captured
def captureOut2():
def m():
@@ -50,12 +50,12 @@ def out():
sinkO2 = SOURCE
m()
captureOut2()
SINK(sinkO2) #$ captured
SINK(sinkO2) # $ captured
def captureOut1NotCalled():
global nonSink1
nonSink1 = SOURCE
SINK_F(nonSink1) #$ SPURIOUS: captured
SINK_F(nonSink1) # $ SPURIOUS: captured
def captureOut2NotCalled():
# notice that `m` is not called
@@ -63,7 +63,7 @@ def out():
global nonSink2
nonSink2 = SOURCE
captureOut2NotCalled()
SINK_F(nonSink2) #$ SPURIOUS: captured
SINK_F(nonSink2) # $ SPURIOUS: captured
@expects(4)
def test_out():
@@ -78,7 +78,7 @@ def through(tainted):
global sinkT1
sinkT1 = tainted
captureOut1()
SINK(sinkT1) #$ captured
SINK(sinkT1) # $ captured
def captureOut2():
def m():
@@ -86,7 +86,7 @@ def through(tainted):
sinkT2 = tainted
m()
captureOut2()
SINK(sinkT2) #$ captured
SINK(sinkT2) # $ captured
def captureOut1NotCalled():
global nonSinkT1

View File

@@ -34,17 +34,17 @@ def SINK_F(x):
def inParam(tainted):
def captureIn1():
sinkI1 = tainted
SINK(sinkI1) #$ captured
SINK(sinkI1) # $ captured
captureIn1()
def captureIn2():
def m():
sinkI2 = tainted
SINK(sinkI2) #$ captured
SINK(sinkI2) # $ captured
m()
captureIn2()
captureIn3 = lambda arg: SINK(tainted) #$ captured
captureIn3 = lambda arg: SINK(tainted) # $ captured
captureIn3("")
def captureIn1NotCalled():
@@ -68,17 +68,17 @@ def inLocal():
def captureIn1():
sinkI1 = tainted
SINK(sinkI1) #$ captured
SINK(sinkI1) # $ captured
captureIn1()
def captureIn2():
def m():
sinkI2 = tainted
SINK(sinkI2) #$ captured
SINK(sinkI2) # $ captured
m()
captureIn2()
captureIn3 = lambda arg: SINK(tainted) #$ captured
captureIn3 = lambda arg: SINK(tainted) # $ captured
captureIn3("")
def captureIn1NotCalled():

View File

@@ -38,7 +38,7 @@ def out():
nonlocal sinkO1
sinkO1 = SOURCE
captureOut1()
SINK(sinkO1) #$ captured
SINK(sinkO1) # $ captured
sinkO2 = ""
def captureOut2():
@@ -47,7 +47,7 @@ def out():
sinkO2 = SOURCE
m()
captureOut2()
SINK(sinkO2) #$ captured
SINK(sinkO2) # $ captured
nonSink1 = ""
def captureOut1NotCalled():
@@ -74,7 +74,7 @@ def through(tainted):
nonlocal sinkO1
sinkO1 = tainted
captureOut1()
SINK(sinkO1) #$ captured
SINK(sinkO1) # $ captured
sinkO2 = ""
def captureOut2():
@@ -83,7 +83,7 @@ def through(tainted):
sinkO2 = tainted
m()
captureOut2()
SINK(sinkO2) #$ captured
SINK(sinkO2) # $ captured
nonSink1 = ""
def captureOut1NotCalled():

View File

@@ -34,16 +34,16 @@ l = [NONSOURCE]
SINK_F(l[0])
l_mod = [SOURCE for x in l]
SINK(l_mod[0]) #$ captured
SINK(l_mod[0]) # $ captured
l_mod_lambda = [(lambda a : SOURCE)(x) for x in l]
SINK(l_mod_lambda[0]) #$ captured
SINK(l_mod_lambda[0]) # $ captured
def mod(x):
return SOURCE
l_mod_function = [mod(x) for x in l]
SINK(l_mod_function[0]) #$ captured
SINK(l_mod_function[0]) # $ captured
def mod_list(l):
def mod_local(x):
@@ -52,7 +52,7 @@ def mod_list(l):
return [mod_local(x) for x in l]
l_modded = mod_list(l)
SINK(l_modded[0]) #$ captured
SINK(l_modded[0]) # $ captured
def mod_list_first(l):
def mod_local(x):
@@ -61,4 +61,4 @@ def mod_list_first(l):
return [mod_local(l[0])]
l_modded_first = mod_list_first(l)
SINK(l_modded_first[0]) #$ captured
SINK(l_modded_first[0]) # $ captured

View File

@@ -38,7 +38,7 @@ def test_captured_field():
foo.setFoo(NONSOURCE)
def test():
SINK(foo.getFoo()) #$ captured
SINK(foo.getFoo()) # $ captured
def read():
return foo.getFoo()
@@ -48,4 +48,4 @@ def test_captured_field():
foo.setFoo(SOURCE)
test()
SINK(read()) #$ captured
SINK(read()) # $ captured

View File

@@ -45,4 +45,4 @@ def test_library_call():
for x in map(set, [1]):
pass
SINK(captured["x"]) #$ captured
SINK(captured["x"]) # $ captured

View File

@@ -92,12 +92,12 @@ def only_az(value):
class CommentValidatorNotUsed(models.Model):
text = models.CharField(max_length=256, validators=[only_az])
def save_comment_validator_not_used(request): # $requestHandler
def save_comment_validator_not_used(request): # $ requestHandler
comment = CommentValidatorNotUsed(text=request.POST["text"])
comment.save()
return HttpResponse("ok")
def display_comment_validator_not_used(request): # $requestHandler
def display_comment_validator_not_used(request): # $ requestHandler
comment = CommentValidatorNotUsed.objects.last()
return HttpResponse(comment.text) # NOT OK
@@ -111,12 +111,12 @@ http http://127.0.0.1:8000/display_comment_validator_not_used/
class CommentValidatorUsed(models.Model):
text = models.CharField(max_length=256, validators=[only_az])
def save_comment_validator_used(request): # $requestHandler
def save_comment_validator_used(request): # $ requestHandler
comment = CommentValidatorUsed(text=request.POST["text"])
comment.full_clean()
comment.save()
def display_comment_validator_used(request): # $requestHandler
def display_comment_validator_used(request): # $ requestHandler
comment = CommentValidatorUsed.objects.last()
return HttpResponse(comment.text) # sort of OK

View File

@@ -4,21 +4,21 @@ from django.http.response import HttpResponse
from django.views.generic import View
def url_match_xss(request, foo, bar, no_taint=None): # $requestHandler routedParameter=foo routedParameter=bar
return HttpResponse('url_match_xss: {} {}'.format(foo, bar)) # $HttpResponse
def url_match_xss(request, foo, bar, no_taint=None): # $ requestHandler routedParameter=foo routedParameter=bar
return HttpResponse('url_match_xss: {} {}'.format(foo, bar)) # $ HttpResponse
def get_params_xss(request): # $requestHandler
return HttpResponse(request.GET.get("untrusted")) # $HttpResponse
def get_params_xss(request): # $ requestHandler
return HttpResponse(request.GET.get("untrusted")) # $ HttpResponse
def post_params_xss(request): # $requestHandler
return HttpResponse(request.POST.get("untrusted")) # $HttpResponse
def post_params_xss(request): # $ requestHandler
return HttpResponse(request.POST.get("untrusted")) # $ HttpResponse
def http_resp_write(request): # $requestHandler
rsp = HttpResponse() # $HttpResponse
rsp.write(request.GET.get("untrusted")) # $HttpResponse
def http_resp_write(request): # $ requestHandler
rsp = HttpResponse() # $ HttpResponse
rsp.write(request.GET.get("untrusted")) # $ HttpResponse
return rsp
@@ -27,53 +27,53 @@ class Foo(object):
def post(self, request, untrusted): # $ MISSING: requestHandler routedParameter=untrusted
return HttpResponse('Foo post: {}'.format(untrusted)) # $HttpResponse
return HttpResponse('Foo post: {}'.format(untrusted)) # $ HttpResponse
class ClassView(View, Foo):
def get(self, request, untrusted): # $ requestHandler routedParameter=untrusted
return HttpResponse('ClassView get: {}'.format(untrusted)) # $HttpResponse
return HttpResponse('ClassView get: {}'.format(untrusted)) # $ HttpResponse
def show_articles(request, page_number=1): # $requestHandler routedParameter=page_number
def show_articles(request, page_number=1): # $ requestHandler routedParameter=page_number
page_number = int(page_number)
return HttpResponse('articles page: {}'.format(page_number)) # $HttpResponse
return HttpResponse('articles page: {}'.format(page_number)) # $ HttpResponse
def xxs_positional_arg(request, arg0, arg1, no_taint=None): # $requestHandler routedParameter=arg0 routedParameter=arg1
return HttpResponse('xxs_positional_arg: {} {}'.format(arg0, arg1)) # $HttpResponse
def xxs_positional_arg(request, arg0, arg1, no_taint=None): # $ requestHandler routedParameter=arg0 routedParameter=arg1
return HttpResponse('xxs_positional_arg: {} {}'.format(arg0, arg1)) # $ HttpResponse
urlpatterns = [
url(r"^url_match/(?P<foo>[^/]+)/(?P<bar>[^/]+)", url_match_xss), # $routeSetup="^url_match/(?P<foo>[^/]+)/(?P<bar>[^/]+)"
url(r"^get_params", get_params_xss), # $routeSetup="^get_params"
url(r"^post_params", post_params_xss), # $routeSetup="^post_params"
url(r"^http_resp_write", http_resp_write), # $routeSetup="^http_resp_write"
url(r"^class_view/(?P<untrusted>.+)", ClassView.as_view()), # $routeSetup="^class_view/(?P<untrusted>.+)"
url(r"^url_match/(?P<foo>[^/]+)/(?P<bar>[^/]+)", url_match_xss), # $ routeSetup="^url_match/(?P<foo>[^/]+)/(?P<bar>[^/]+)"
url(r"^get_params", get_params_xss), # $ routeSetup="^get_params"
url(r"^post_params", post_params_xss), # $ routeSetup="^post_params"
url(r"^http_resp_write", http_resp_write), # $ routeSetup="^http_resp_write"
url(r"^class_view/(?P<untrusted>.+)", ClassView.as_view()), # $ routeSetup="^class_view/(?P<untrusted>.+)"
# one pattern to support `articles/page-<n>` and ensuring that articles/ goes to page-1
url(r"articles/^(?:page-(?P<page_number>\d+)/)?", show_articles), # $routeSetup="articles/^(?:page-(?P<page_number>\d+)/)?"
url(r"articles/^(?:page-(?P<page_number>\d+)/)?", show_articles), # $ routeSetup="articles/^(?:page-(?P<page_number>\d+)/)?"
# passing as positional argument is not the recommended way of doing things, but it is certainly
# possible
url(r"^([^/]+)/(?:foo|bar)/([^/]+)", xxs_positional_arg, name='xxs_positional_arg'), # $routeSetup="^([^/]+)/(?:foo|bar)/([^/]+)"
url(r"^([^/]+)/(?:foo|bar)/([^/]+)", xxs_positional_arg, name='xxs_positional_arg'), # $ routeSetup="^([^/]+)/(?:foo|bar)/([^/]+)"
]
################################################################################
# Using patterns() for routing
def show_user(request, username): # $requestHandler routedParameter=username
return HttpResponse('show_user {}'.format(username)) # $HttpResponse
def show_user(request, username): # $ requestHandler routedParameter=username
return HttpResponse('show_user {}'.format(username)) # $ HttpResponse
urlpatterns = patterns(url(r"^users/(?P<username>[^/]+)", show_user)) # $routeSetup="^users/(?P<username>[^/]+)"
urlpatterns = patterns(url(r"^users/(?P<username>[^/]+)", show_user)) # $ routeSetup="^users/(?P<username>[^/]+)"
################################################################################
# Show we understand the keyword arguments to django.conf.urls.url
def kw_args(request): # $requestHandler
return HttpResponse('kw_args') # $HttpResponse
def kw_args(request): # $ requestHandler
return HttpResponse('kw_args') # $ HttpResponse
urlpatterns = [
url(view=kw_args, regex=r"^kw_args") # $routeSetup="^kw_args"
url(view=kw_args, regex=r"^kw_args") # $ routeSetup="^kw_args"
]

View File

@@ -8,12 +8,12 @@ import json
# FP reported in https://github.com/github/codeql-python-team/issues/38
def safe__json_response(request):
# implicitly sets Content-Type to "application/json"
return JsonResponse({"foo": request.GET.get("foo")}) # $HttpResponse mimetype=application/json responseBody=Dict
return JsonResponse({"foo": request.GET.get("foo")}) # $ HttpResponse mimetype=application/json responseBody=Dict
# Not an XSS sink, since the Content-Type is not "text/html"
def safe__manual_json_response(request):
json_data = '{"json": "{}"}'.format(request.GET.get("foo"))
return HttpResponse(json_data, content_type="application/json") # $HttpResponse mimetype=application/json responseBody=json_data
return HttpResponse(json_data, content_type="application/json") # $ HttpResponse mimetype=application/json responseBody=json_data
# reproduction of FP seen here:
# Usage: https://github.com/edx/edx-platform/blob/d70ebe6343a1573c694d6cf68f92c1ad40b73d7d/lms/djangoapps/commerce/api/v0/views.py#L106
@@ -27,25 +27,25 @@ class MyJsonResponse(HttpResponse):
# Not an XSS sink, since the Content-Type is not "text/html"
def safe__custom_json_response(request):
json_data = '{"json": "{}"}'.format(request.GET.get("foo"))
return MyJsonResponse(json_data) # $HttpResponse responseBody=json_data SPURIOUS: mimetype=text/html MISSING: mimetype=application/json
return MyJsonResponse(json_data) # $ HttpResponse responseBody=json_data SPURIOUS: mimetype=text/html MISSING: mimetype=application/json
# Not an XSS sink, since the Content-Type is not "text/html"
def safe__manual_content_type(request):
return HttpResponse('<img src="0" onerror="alert(1)">', content_type="text/plain") # $HttpResponse mimetype=text/plain responseBody='<img src="0" onerror="alert(1)">'
return HttpResponse('<img src="0" onerror="alert(1)">', content_type="text/plain") # $ HttpResponse mimetype=text/plain responseBody='<img src="0" onerror="alert(1)">'
# XSS FP reported in https://github.com/github/codeql/issues/3466
# Note: This should be an open-redirect sink, but not an XSS sink.
def or__redirect(request):
next = request.GET.get("next")
return HttpResponseRedirect(next) # $HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation=next
return HttpResponseRedirect(next) # $ HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation=next
def information_exposure_through_redirect(request, as_kw=False):
# This is a contrived example, but possible
private = "private"
next = request.GET.get("next")
if as_kw:
return HttpResponseRedirect(next, content=private) # $HttpResponse mimetype=text/html responseBody=private HttpRedirectResponse redirectLocation=next
return HttpResponseRedirect(next, content=private) # $ HttpResponse mimetype=text/html responseBody=private HttpRedirectResponse redirectLocation=next
else:
return HttpResponseRedirect(next, private) # $ HttpResponse mimetype=text/html responseBody=private HttpRedirectResponse redirectLocation=next
@@ -91,20 +91,20 @@ class CustomRedirectView(RedirectView):
# Ensure that simple subclasses are still vuln to XSS
def xss__not_found(request):
return HttpResponseNotFound(request.GET.get("name")) # $HttpResponse mimetype=text/html responseBody=request.GET.get(..)
return HttpResponseNotFound(request.GET.get("name")) # $ HttpResponse mimetype=text/html responseBody=request.GET.get(..)
# Ensure we still have an XSS sink when manually setting the content_type to HTML
def xss__manual_response_type(request):
return HttpResponse(request.GET.get("name"), content_type="text/html; charset=utf-8") # $HttpResponse mimetype=text/html responseBody=request.GET.get(..)
return HttpResponse(request.GET.get("name"), content_type="text/html; charset=utf-8") # $ HttpResponse mimetype=text/html responseBody=request.GET.get(..)
def xss__write(request):
response = HttpResponse() # $HttpResponse mimetype=text/html
response.write(request.GET.get("name")) # $HttpResponse mimetype=text/html responseBody=request.GET.get(..)
response = HttpResponse() # $ HttpResponse mimetype=text/html
response.write(request.GET.get("name")) # $ HttpResponse mimetype=text/html responseBody=request.GET.get(..)
# This is safe but probably a bug if the argument to `write` is not a result of `json.dumps` or similar.
def safe__write_json(request):
response = JsonResponse() # $HttpResponse mimetype=application/json
response.write(request.GET.get("name")) # $HttpResponse mimetype=application/json responseBody=request.GET.get(..)
response = JsonResponse() # $ HttpResponse mimetype=application/json
response.write(request.GET.get("name")) # $ HttpResponse mimetype=application/json responseBody=request.GET.get(..)
# Ensure manual subclasses are vulnerable
class CustomResponse(HttpResponse):
@@ -112,15 +112,15 @@ class CustomResponse(HttpResponse):
super().__init__(content, *args, content_type="text/html", **kwargs)
def xss__custom_response(request):
return CustomResponse("ACME Responses", request.GET("name")) # $HttpResponse MISSING: mimetype=text/html responseBody=request.GET.get(..) SPURIOUS: responseBody="ACME Responses"
return CustomResponse("ACME Responses", request.GET("name")) # $ HttpResponse MISSING: mimetype=text/html responseBody=request.GET.get(..) SPURIOUS: responseBody="ACME Responses"
class CustomJsonResponse(JsonResponse):
def __init__(self, banner, content, *args, **kwargs):
super().__init__(content, *args, content_type="text/html", **kwargs)
@csrf_protect # $CsrfLocalProtectionEnabled=safe__custom_json_response
@csrf_protect # $ CsrfLocalProtectionEnabled=safe__custom_json_response
def safe__custom_json_response(request):
return CustomJsonResponse("ACME Responses", {"foo": request.GET.get("foo")}) # $HttpResponse mimetype=application/json MISSING: responseBody=Dict SPURIOUS: responseBody="ACME Responses"
return CustomJsonResponse("ACME Responses", {"foo": request.GET.get("foo")}) # $ HttpResponse mimetype=application/json MISSING: responseBody=Dict SPURIOUS: responseBody="ACME Responses"
################################################################################
# Cookies
@@ -135,7 +135,7 @@ def setting_cookie(request):
resp.delete_cookie("key4") # $ CookieWrite CookieName="key4"
resp.delete_cookie(key="key4") # $ CookieWrite CookieName="key4"
resp["Set-Cookie"] = "key5=value5" # $ headerWriteName="Set-Cookie" headerWriteValue="key5=value5" CookieWrite CookieRawHeader="key5=value5" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax
resp.set_cookie(key="key6", value="value6", secure=True, httponly=False, samesite="None") # $ CookieWrite CookieName="key6" CookieValue="value6" CookieSecure=true CookieHttpOnly=false CookieSameSite=None
resp.set_cookie(key="key6", value="value6", secure=True, httponly=False, samesite="None") # $ CookieWrite CookieName="key6" CookieValue="value6" CookieSecure=true CookieHttpOnly=false CookieSameSite=None
kwargs = {'secure': True}
resp.set_cookie(key="key7", value="value7", **kwargs) # $ CookieWrite CookieName="key7" CookieValue="value7"
return resp

View File

@@ -6,21 +6,21 @@ import django.views.generic.base
from django.views.decorators.http import require_GET
def url_match_xss(request, foo, bar, no_taint=None): # $requestHandler routedParameter=foo routedParameter=bar
return HttpResponse('url_match_xss: {} {}'.format(foo, bar)) # $HttpResponse
def url_match_xss(request, foo, bar, no_taint=None): # $ requestHandler routedParameter=foo routedParameter=bar
return HttpResponse('url_match_xss: {} {}'.format(foo, bar)) # $ HttpResponse
def get_params_xss(request): # $requestHandler
return HttpResponse(request.GET.get("untrusted")) # $HttpResponse
def get_params_xss(request): # $ requestHandler
return HttpResponse(request.GET.get("untrusted")) # $ HttpResponse
def post_params_xss(request): # $requestHandler
return HttpResponse(request.POST.get("untrusted")) # $HttpResponse
def post_params_xss(request): # $ requestHandler
return HttpResponse(request.POST.get("untrusted")) # $ HttpResponse
def http_resp_write(request): # $requestHandler
rsp = HttpResponse() # $HttpResponse
rsp.write(request.GET.get("untrusted")) # $HttpResponse
def http_resp_write(request): # $ requestHandler
rsp = HttpResponse() # $ HttpResponse
rsp.write(request.GET.get("untrusted")) # $ HttpResponse
return rsp
@@ -29,13 +29,13 @@ class Foo(object):
def post(self, request, untrusted): # $ MISSING: requestHandler routedParameter=untrusted
return HttpResponse('Foo post: {}'.format(untrusted)) # $HttpResponse
return HttpResponse('Foo post: {}'.format(untrusted)) # $ HttpResponse
class ClassView(View, Foo):
def get(self, request, untrusted): # $ requestHandler routedParameter=untrusted
return HttpResponse('ClassView get: {}'.format(untrusted)) # $HttpResponse
return HttpResponse('ClassView get: {}'.format(untrusted)) # $ HttpResponse
# direct import with full path to `View` class
@@ -44,38 +44,38 @@ class ClassView2(django.views.generic.base.View):
pass
def show_articles(request, page_number=1): # $requestHandler routedParameter=page_number
def show_articles(request, page_number=1): # $ requestHandler routedParameter=page_number
page_number = int(page_number)
return HttpResponse('articles page: {}'.format(page_number)) # $HttpResponse
return HttpResponse('articles page: {}'.format(page_number)) # $ HttpResponse
def xxs_positional_arg(request, arg0, arg1, no_taint=None): # $requestHandler routedParameter=arg0 routedParameter=arg1
return HttpResponse('xxs_positional_arg: {} {}'.format(arg0, arg1)) # $HttpResponse
def xxs_positional_arg(request, arg0, arg1, no_taint=None): # $ requestHandler routedParameter=arg0 routedParameter=arg1
return HttpResponse('xxs_positional_arg: {} {}'.format(arg0, arg1)) # $ HttpResponse
urlpatterns = [
re_path(r"^url_match/(?P<foo>[^/]+)/(?P<bar>[^/]+)", url_match_xss), # $routeSetup="^url_match/(?P<foo>[^/]+)/(?P<bar>[^/]+)"
re_path(r"^get_params", get_params_xss), # $routeSetup="^get_params"
re_path(r"^post_params", post_params_xss), # $routeSetup="^post_params"
re_path(r"^http_resp_write", http_resp_write), # $routeSetup="^http_resp_write"
re_path(r"^class_view/(?P<untrusted>.+)", ClassView.as_view()), # $routeSetup="^class_view/(?P<untrusted>.+)"
re_path(r"^url_match/(?P<foo>[^/]+)/(?P<bar>[^/]+)", url_match_xss), # $ routeSetup="^url_match/(?P<foo>[^/]+)/(?P<bar>[^/]+)"
re_path(r"^get_params", get_params_xss), # $ routeSetup="^get_params"
re_path(r"^post_params", post_params_xss), # $ routeSetup="^post_params"
re_path(r"^http_resp_write", http_resp_write), # $ routeSetup="^http_resp_write"
re_path(r"^class_view/(?P<untrusted>.+)", ClassView.as_view()), # $ routeSetup="^class_view/(?P<untrusted>.+)"
# one pattern to support `articles/page-<n>` and ensuring that articles/ goes to page-1
re_path(r"articles/^(?:page-(?P<page_number>\d+)/)?", show_articles), # $routeSetup="articles/^(?:page-(?P<page_number>\d+)/)?"
re_path(r"articles/^(?:page-(?P<page_number>\d+)/)?", show_articles), # $ routeSetup="articles/^(?:page-(?P<page_number>\d+)/)?"
# passing as positional argument is not the recommended way of doing things, but it is certainly
# possible
re_path(r"^([^/]+)/(?:foo|bar)/([^/]+)", xxs_positional_arg, name='xxs_positional_arg'), # $routeSetup="^([^/]+)/(?:foo|bar)/([^/]+)"
re_path(r"^([^/]+)/(?:foo|bar)/([^/]+)", xxs_positional_arg, name='xxs_positional_arg'), # $ routeSetup="^([^/]+)/(?:foo|bar)/([^/]+)"
]
# Show we understand the keyword arguments to django.urls.re_path
def re_path_kwargs(request): # $requestHandler
return HttpResponse('re_path_kwargs') # $HttpResponse
def re_path_kwargs(request): # $ requestHandler
return HttpResponse('re_path_kwargs') # $ HttpResponse
urlpatterns = [
re_path(view=re_path_kwargs, route=r"^specifying-as-kwargs-is-not-a-problem") # $routeSetup="^specifying-as-kwargs-is-not-a-problem"
re_path(view=re_path_kwargs, route=r"^specifying-as-kwargs-is-not-a-problem") # $ routeSetup="^specifying-as-kwargs-is-not-a-problem"
]
################################################################################
@@ -83,27 +83,27 @@ urlpatterns = [
################################################################################
# saying page_number is an externally controlled *string* is a bit strange, when we have an int converter :O
def page_number(request, page_number=1): # $requestHandler routedParameter=page_number
return HttpResponse('page_number: {}'.format(page_number)) # $HttpResponse
def page_number(request, page_number=1): # $ requestHandler routedParameter=page_number
return HttpResponse('page_number: {}'.format(page_number)) # $ HttpResponse
def foo_bar_baz(request, foo, bar, baz): # $requestHandler routedParameter=foo routedParameter=bar routedParameter=baz
return HttpResponse('foo_bar_baz: {} {} {}'.format(foo, bar, baz)) # $HttpResponse
def foo_bar_baz(request, foo, bar, baz): # $ requestHandler routedParameter=foo routedParameter=bar routedParameter=baz
return HttpResponse('foo_bar_baz: {} {} {}'.format(foo, bar, baz)) # $ HttpResponse
def path_kwargs(request, foo, bar): # $requestHandler routedParameter=foo routedParameter=bar
return HttpResponse('path_kwargs: {} {} {}'.format(foo, bar)) # $HttpResponse
def path_kwargs(request, foo, bar): # $ requestHandler routedParameter=foo routedParameter=bar
return HttpResponse('path_kwargs: {} {} {}'.format(foo, bar)) # $ HttpResponse
def not_valid_identifier(request): # $requestHandler
return HttpResponse('<foo!>') # $HttpResponse
def not_valid_identifier(request): # $ requestHandler
return HttpResponse('<foo!>') # $ HttpResponse
urlpatterns = [
path("articles/", page_number), # $routeSetup="articles/"
path("articles/page-<int:page_number>", page_number), # $routeSetup="articles/page-<int:page_number>"
path("<int:foo>/<str:bar>/<baz>", foo_bar_baz, name='foo-bar-baz'), # $routeSetup="<int:foo>/<str:bar>/<baz>"
path("articles/", page_number), # $ routeSetup="articles/"
path("articles/page-<int:page_number>", page_number), # $ routeSetup="articles/page-<int:page_number>"
path("<int:foo>/<str:bar>/<baz>", foo_bar_baz, name='foo-bar-baz'), # $ routeSetup="<int:foo>/<str:bar>/<baz>"
path(view=path_kwargs, route="<foo>/<bar>"), # $routeSetup="<foo>/<bar>"
path(view=path_kwargs, route="<foo>/<bar>"), # $ routeSetup="<foo>/<bar>"
# We should not report there is a request parameter called `not_valid!`
path("not_valid/<not_valid!>", not_valid_identifier), # $routeSetup="not_valid/<not_valid!>"
path("not_valid/<not_valid!>", not_valid_identifier), # $ routeSetup="not_valid/<not_valid!>"
]
################################################################################
@@ -113,11 +113,11 @@ urlpatterns = [
# This version 1.x way of defining urls is deprecated in Django 3.1, but still works
from django.conf.urls import url
def deprecated(request): # $requestHandler
return HttpResponse('deprecated') # $HttpResponse
def deprecated(request): # $ requestHandler
return HttpResponse('deprecated') # $ HttpResponse
urlpatterns = [
url(r"^deprecated/", deprecated), # $routeSetup="^deprecated/"
url(r"^deprecated/", deprecated), # $ routeSetup="^deprecated/"
]
@@ -130,7 +130,7 @@ class PossiblyNotRouted(View):
# consider it to be a handle incoming HTTP requests
def get(self, request, possibly_not_routed=42): # $ requestHandler routedParameter=possibly_not_routed
return HttpResponse('PossiblyNotRouted get: {}'.format(possibly_not_routed)) # $HttpResponse
return HttpResponse('PossiblyNotRouted get: {}'.format(possibly_not_routed)) # $ HttpResponse
@require_GET

View File

@@ -4,7 +4,7 @@ from django.http import HttpRequest
from django.views import View
def test_taint(request: HttpRequest, foo, bar, baz=None): # $requestHandler routedParameter=foo routedParameter=bar
def test_taint(request: HttpRequest, foo, bar, baz=None): # $ requestHandler routedParameter=foo routedParameter=bar
ensure_tainted(foo, bar) # $ tainted
ensure_not_tainted(baz)

View File

@@ -3,19 +3,19 @@ from django.urls import path, re_path
from . import views
urlpatterns = [
path("foo/", views.foo), # $routeSetup="foo/"
path("foo/", views.foo), # $ routeSetup="foo/"
# TODO: Doesn't include standard `$` to mark end of string, due to problems with
# inline expectation tests (which thinks the `$` would mark the beginning of a new
# line)
re_path(r"^ba[rz]/", views.bar_baz), # $routeSetup="^ba[rz]/"
re_path(r"^ba[rz]/", views.bar_baz), # $ routeSetup="^ba[rz]/"
path("basic-view-handler/", views.MyBasicViewHandler.as_view()), # $routeSetup="basic-view-handler/"
path("custom-inheritance-view-handler/", views.MyViewHandlerWithCustomInheritance.as_view()), # $routeSetup="custom-inheritance-view-handler/"
path("basic-view-handler/", views.MyBasicViewHandler.as_view()), # $ routeSetup="basic-view-handler/"
path("custom-inheritance-view-handler/", views.MyViewHandlerWithCustomInheritance.as_view()), # $ routeSetup="custom-inheritance-view-handler/"
path("CustomRedirectView/<foo>", views.CustomRedirectView.as_view()), # $routeSetup="CustomRedirectView/<foo>"
path("CustomRedirectView2/<foo>", views.CustomRedirectView2.as_view()), # $routeSetup="CustomRedirectView2/<foo>"
path("CustomRedirectView/<foo>", views.CustomRedirectView.as_view()), # $ routeSetup="CustomRedirectView/<foo>"
path("CustomRedirectView2/<foo>", views.CustomRedirectView2.as_view()), # $ routeSetup="CustomRedirectView2/<foo>"
path("file-test/", views.file_test), # $routeSetup="file-test/"
path("file-test/", views.file_test), # $ routeSetup="file-test/"
]
from django import __version__ as django_version
@@ -30,7 +30,7 @@ if django_version[0] == "3":
# we need this assignment to get our logic working... maybe it should be more
# sophisticated?
urlpatterns = [
url(r"^deprecated/", views.deprecated), # $routeSetup="^deprecated/"
url(r"^deprecated/", views.deprecated), # $ routeSetup="^deprecated/"
]
urlpatterns += old_urlpatterns

View File

@@ -4,16 +4,16 @@ from django.views.decorators.csrf import csrf_exempt
from .models import MyModel
def foo(request: HttpRequest): # $requestHandler
return HttpResponse("foo") # $HttpResponse
def foo(request: HttpRequest): # $ requestHandler
return HttpResponse("foo") # $ HttpResponse
def bar_baz(request: HttpRequest): # $requestHandler
return HttpResponse("bar_baz") # $HttpResponse
def bar_baz(request: HttpRequest): # $ requestHandler
return HttpResponse("bar_baz") # $ HttpResponse
def deprecated(request: HttpRequest): # $requestHandler
return HttpResponse("deprecated") # $HttpResponse
def deprecated(request: HttpRequest): # $ requestHandler
return HttpResponse("deprecated") # $ HttpResponse
class MyBasicViewHandler(View):

View File

@@ -13,7 +13,7 @@ https://docs.djangoproject.com/en/3.1/ref/settings/
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent #$ getAPathArgument=Path(..)
BASE_DIR = Path(__file__).resolve().parent.parent # $ getAPathArgument=Path(..)
# Quick-start development settings - unsuitable for production
@@ -48,7 +48,7 @@ MIDDLEWARE = [
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
] # $CsrfProtectionSetting=false
] # $ CsrfProtectionSetting=false
ROOT_URLCONF = 'testproj.urls'

View File

@@ -17,6 +17,6 @@ from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls), # $routeSetup="admin/"
path("app/", include("testapp.urls")), # $routeSetup="app/"
path("admin/", admin.site.urls), # $ routeSetup="admin/"
path("app/", include("testapp.urls")), # $ routeSetup="app/"
]

View File

@@ -4,13 +4,13 @@ from django.db.models.expressions import RawSQL
def test_plain():
cursor = connection.cursor()
cursor.execute("some sql") # $getSql="some sql"
cursor.execute("some sql") # $ getSql="some sql"
def test_context():
with connection.cursor() as cursor:
cursor.execute("some sql") # $getSql="some sql"
cursor.execute(sql="some sql") # $getSql="some sql"
cursor.execute("some sql") # $ getSql="some sql"
cursor.execute(sql="some sql") # $ getSql="some sql"
class User(models.Model):
@@ -18,20 +18,20 @@ class User(models.Model):
def test_model():
User.objects.raw("some sql") # $getSql="some sql"
User.objects.raw("some sql") # $ getSql="some sql"
User.objects.annotate(RawSQL("some sql")) # $getSql="some sql"
User.objects.annotate(RawSQL("foo"), RawSQL("bar")) # $getSql="foo" getSql="bar"
User.objects.annotate(val=RawSQL("some sql")) # $getSql="some sql"
User.objects.annotate(RawSQL("some sql")) # $ getSql="some sql"
User.objects.annotate(RawSQL("foo"), RawSQL("bar")) # $ getSql="foo" getSql="bar"
User.objects.annotate(val=RawSQL("some sql")) # $ getSql="some sql"
User.objects.alias(RawSQL("foo"), RawSQL("bar")) # $getSql="foo" getSql="bar"
User.objects.alias(val=RawSQL("some sql")) # $getSql="some sql"
User.objects.alias(RawSQL("foo"), RawSQL("bar")) # $ getSql="foo" getSql="bar"
User.objects.alias(val=RawSQL("some sql")) # $ getSql="some sql"
User.objects.extra("some sql") # $getSql="some sql"
User.objects.extra(select="select", where="where", tables="tables", order_by="order_by") # $getSql="select" getSql="where" getSql="tables" getSql="order_by"
User.objects.extra("some sql") # $ getSql="some sql"
User.objects.extra(select="select", where="where", tables="tables", order_by="order_by") # $ getSql="select" getSql="where" getSql="tables" getSql="order_by"
raw = RawSQL("so raw")
User.objects.annotate(val=raw) # $getSql="so raw"
User.objects.annotate(val=raw) # $ getSql="so raw"
# chaining QuerySet calls
User.objects.using("db-name").exclude(username="admin").extra("some sql") # $ getSql="some sql"

View File

@@ -5,15 +5,15 @@ See http://docs.fabfile.org/en/1.14/tutorial.html
from fabric.api import run, local, sudo
local("cmd1; cmd2") # $getCommand="cmd1; cmd2"
run("cmd1; cmd2") # $getCommand="cmd1; cmd2"
sudo("cmd1; cmd2") # $getCommand="cmd1; cmd2"
local("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
run("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
sudo("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
local(command="cmd1; cmd2") # $getCommand="cmd1; cmd2"
run(command="cmd1; cmd2") # $getCommand="cmd1; cmd2"
sudo(command="cmd1; cmd2") # $getCommand="cmd1; cmd2"
local(command="cmd1; cmd2") # $ getCommand="cmd1; cmd2"
run(command="cmd1; cmd2") # $ getCommand="cmd1; cmd2"
sudo(command="cmd1; cmd2") # $ getCommand="cmd1; cmd2"
from fabric import operations
operations.local("cmd1; cmd2") # $getCommand="cmd1; cmd2"
operations.local(command="cmd1; cmd2") # $getCommand="cmd1; cmd2"
operations.local("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
operations.local(command="cmd1; cmd2") # $ getCommand="cmd1; cmd2"

View File

@@ -9,41 +9,41 @@ from fabric import connection, Connection, group, SerialGroup, ThreadingGroup, t
# Connection
################################################################################
c = Connection("web1")
c.run("cmd1; cmd2") # $getCommand="cmd1; cmd2"
c.local("cmd1; cmd2") # $getCommand="cmd1; cmd2"
c.sudo("cmd1; cmd2") # $getCommand="cmd1; cmd2"
c.run("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
c.local("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
c.sudo("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
c.local(command="cmd1; cmd2") # $getCommand="cmd1; cmd2"
c.run(command="cmd1; cmd2") # $getCommand="cmd1; cmd2"
c.sudo(command="cmd1; cmd2") # $getCommand="cmd1; cmd2"
c.local(command="cmd1; cmd2") # $ getCommand="cmd1; cmd2"
c.run(command="cmd1; cmd2") # $ getCommand="cmd1; cmd2"
c.sudo(command="cmd1; cmd2") # $ getCommand="cmd1; cmd2"
# fully qualified usage
c2 = connection.Connection("web2")
c2.run("cmd1; cmd2") # $getCommand="cmd1; cmd2"
c2.run("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
# ssh proxy_command command injection with gateway parameter,
# we need to call some of the following functions to run the proxy command
c = Connection("web1", gateway="cmd") # $getCommand="cmd"
c.run(command="cmd1; cmd2") # $getCommand="cmd1; cmd2"
c = Connection("web1", gateway="cmd") # $getCommand="cmd"
c = Connection("web1", gateway="cmd") # $ getCommand="cmd"
c.run(command="cmd1; cmd2") # $ getCommand="cmd1; cmd2"
c = Connection("web1", gateway="cmd") # $ getCommand="cmd"
c.get("afs")
c = Connection("web1", gateway="cmd") # $getCommand="cmd"
c.sudo(command="cmd1; cmd2") # $getCommand="cmd1; cmd2"
c = Connection("web1", gateway="cmd") # $getCommand="cmd"
c = Connection("web1", gateway="cmd") # $ getCommand="cmd"
c.sudo(command="cmd1; cmd2") # $ getCommand="cmd1; cmd2"
c = Connection("web1", gateway="cmd") # $ getCommand="cmd"
c.open_gateway()
c = Connection("web1", gateway="cmd") # $getCommand="cmd"
c = Connection("web1", gateway="cmd") # $ getCommand="cmd"
c.open()
c = Connection("web1", gateway="cmd") # $getCommand="cmd"
c = Connection("web1", gateway="cmd") # $ getCommand="cmd"
c.create_session()
c = Connection("web1", gateway="cmd") # $getCommand="cmd"
c = Connection("web1", gateway="cmd") # $ getCommand="cmd"
c.forward_local("80")
c = Connection("web1", gateway="cmd") # $getCommand="cmd"
c = Connection("web1", gateway="cmd") # $ getCommand="cmd"
c.forward_remote("80")
c = Connection("web1", gateway="cmd") # $getCommand="cmd"
c = Connection("web1", gateway="cmd") # $ getCommand="cmd"
c.put(local="local")
c = Connection("web1", gateway="cmd") # $getCommand="cmd"
c = Connection("web1", gateway="cmd") # $ getCommand="cmd"
c.shell()
c = Connection("web1", gateway="cmd") # $getCommand="cmd"
c = Connection("web1", gateway="cmd") # $ getCommand="cmd"
c.sftp()
# no call to desired methods so it is safe
c = Connection("web1", gateway="cmd")
@@ -51,26 +51,26 @@ c = Connection("web1", gateway="cmd")
################################################################################
# SerialGroup
################################################################################
results = SerialGroup("web1", "web2", "mac1").run("cmd1; cmd2") # $getCommand="cmd1; cmd2"
results = SerialGroup("web1", "web2", "mac1").run("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
pool = SerialGroup("web1", "web2", "web3")
pool.run("cmd1; cmd2") # $getCommand="cmd1; cmd2"
pool.sudo("cmd1; cmd2") # $getCommand="cmd1; cmd2"
pool.run("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
pool.sudo("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
# fully qualified usage
group.SerialGroup("web1", "web2", "mac1").run("cmd1; cmd2") # $getCommand="cmd1; cmd2"
group.SerialGroup("web1", "web2", "mac1").run("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
################################################################################
# ThreadingGroup
################################################################################
results = ThreadingGroup("web1", "web2", "mac1").run("cmd1; cmd2") # $getCommand="cmd1; cmd2"
results = ThreadingGroup("web1", "web2", "mac1").run("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
pool = ThreadingGroup("web1", "web2", "web3")
pool.run("cmd1; cmd2") # $getCommand="cmd1; cmd2"
pool.sudo("cmd1; cmd2") # $getCommand="cmd1; cmd2"
pool.run("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
pool.sudo("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
# fully qualified usage
group.ThreadingGroup("web1", "web2", "mac1").run("cmd1; cmd2") # $getCommand="cmd1; cmd2"
group.ThreadingGroup("web1", "web2", "mac1").run("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
################################################################################
@@ -81,11 +81,11 @@ group.ThreadingGroup("web1", "web2", "mac1").run("cmd1; cmd2") # $getCommand="c
@task
def foo(c):
# 'c' is a fabric.connection.Connection
c.run("cmd1; cmd2") # $getCommand="cmd1; cmd2"
c.run("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
# fully qualified usage
@tasks.task
def bar(c):
# 'c' is a fabric.connection.Connection
c.run("cmd1; cmd2") # $getCommand="cmd1; cmd2"
c.run("cmd1; cmd2") # $ getCommand="cmd1; cmd2"

View File

@@ -3,9 +3,9 @@ import flask
from flask import Flask, request, make_response
app = Flask(__name__)
@app.route("/") # $routeSetup="/"
def hello_world(): # $requestHandler
return "Hello World!" # $HttpResponse
@app.route("/") # $ routeSetup="/"
def hello_world(): # $ requestHandler
return "Hello World!" # $ HttpResponse
from flask.views import MethodView
@@ -22,46 +22,46 @@ class MyView(MethodView):
the_view = MyView.as_view('my_view')
app.add_url_rule('/the/', defaults={'user_id': None},
view_func=the_view, methods=['GET',]) # $routeSetup="/the/"
view_func=the_view, methods=['GET',]) # $ routeSetup="/the/"
@app.route("/dangerous") # $routeSetup="/dangerous"
def dangerous(): # $requestHandler
return request.args.get('payload') # $HttpResponse
@app.route("/dangerous") # $ routeSetup="/dangerous"
def dangerous(): # $ requestHandler
return request.args.get('payload') # $ HttpResponse
@app.route("/dangerous-with-cfg-split") # $routeSetup="/dangerous-with-cfg-split"
def dangerous2(): # $requestHandler
@app.route("/dangerous-with-cfg-split") # $ routeSetup="/dangerous-with-cfg-split"
def dangerous2(): # $ requestHandler
x = request.form['param0']
if request.method == "POST":
return request.form['param1'] # $HttpResponse
return request.form['param1'] # $ HttpResponse
return None # $ SPURIOUS: HttpResponse
@app.route("/unsafe") # $routeSetup="/unsafe"
def unsafe(): # $requestHandler
@app.route("/unsafe") # $ routeSetup="/unsafe"
def unsafe(): # $ requestHandler
first_name = request.args.get('name', '')
return make_response("Your name is " + first_name) # $HttpResponse
return make_response("Your name is " + first_name) # $ HttpResponse
@app.route("/safe") # $routeSetup="/safe"
def safe(): # $requestHandler
@app.route("/safe") # $ routeSetup="/safe"
def safe(): # $ requestHandler
first_name = request.args.get('name', '')
return make_response("Your name is " + escape(first_name)) # $HttpResponse
return make_response("Your name is " + escape(first_name)) # $ HttpResponse
@app.route("/hello/<name>") # $routeSetup="/hello/<name>"
def hello(name): # $requestHandler routedParameter=name
return make_response("Your name is " + name) # $HttpResponse
@app.route("/hello/<name>") # $ routeSetup="/hello/<name>"
def hello(name): # $ requestHandler routedParameter=name
return make_response("Your name is " + name) # $ HttpResponse
@app.route("/foo/<path:subpath>") # $routeSetup="/foo/<path:subpath>"
def foo(subpath): # $requestHandler routedParameter=subpath
return make_response("The subpath is " + subpath) # $HttpResponse
@app.route("/foo/<path:subpath>") # $ routeSetup="/foo/<path:subpath>"
def foo(subpath): # $ requestHandler routedParameter=subpath
return make_response("The subpath is " + subpath) # $ HttpResponse
@app.route("/multiple/") # $routeSetup="/multiple/"
@app.route("/multiple/foo/<foo>") # $routeSetup="/multiple/foo/<foo>"
@app.route("/multiple/bar/<bar>") # $routeSetup="/multiple/bar/<bar>"
def multiple(foo=None, bar=None): # $requestHandler routedParameter=foo routedParameter=bar
return make_response("foo={!r} bar={!r}".format(foo, bar)) # $HttpResponse
@app.route("/multiple/") # $ routeSetup="/multiple/"
@app.route("/multiple/foo/<foo>") # $ routeSetup="/multiple/foo/<foo>"
@app.route("/multiple/bar/<bar>") # $ routeSetup="/multiple/bar/<bar>"
def multiple(foo=None, bar=None): # $ requestHandler routedParameter=foo routedParameter=bar
return make_response("foo={!r} bar={!r}".format(foo, bar)) # $ HttpResponse
@app.route("/complex/<string(length=2):lang_code>") # $routeSetup="/complex/<string(length=2):lang_code>"
def complex(lang_code): # $requestHandler routedParameter=lang_code
return make_response("lang_code {}".format(lang_code)) # $HttpResponse
@app.route("/complex/<string(length=2):lang_code>") # $ routeSetup="/complex/<string(length=2):lang_code>"
def complex(lang_code): # $ requestHandler routedParameter=lang_code
return make_response("lang_code {}".format(lang_code)) # $ HttpResponse
if __name__ == "__main__":
app.run(debug=True)

View File

@@ -6,23 +6,23 @@ from werkzeug.datastructures import Headers
app = Flask(__name__)
@app.route("/html1") # $routeSetup="/html1"
def html1(): # $requestHandler
return "<h1>hello</h1>" # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
@app.route("/html1") # $ routeSetup="/html1"
def html1(): # $ requestHandler
return "<h1>hello</h1>" # $ HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
@app.route("/html2") # $routeSetup="/html2"
def html2(): # $requestHandler
@app.route("/html2") # $ routeSetup="/html2"
def html2(): # $ requestHandler
# note that response saved in a variable intentionally -- we wan the annotations to
# show that we recognize the response creation, and not the return (hopefully). (and
# do the same in the following of the file)
resp = make_response("<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
resp = make_response("<h1>hello</h1>") # $ HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/html3") # $routeSetup="/html3"
def html3(): # $requestHandler
resp = app.make_response("<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
@app.route("/html3") # $ routeSetup="/html3"
def html3(): # $ requestHandler
resp = app.make_response("<h1>hello</h1>") # $ HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@@ -30,50 +30,50 @@ def html3(): # $requestHandler
# https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.make_response
@app.route("/html4") # $routeSetup="/html4"
def html4(): # $requestHandler
resp = Response("<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
@app.route("/html4") # $ routeSetup="/html4"
def html4(): # $ requestHandler
resp = Response("<h1>hello</h1>") # $ HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/html5") # $routeSetup="/html5"
def html5(): # $requestHandler
resp = Response(response="<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
@app.route("/html5") # $ routeSetup="/html5"
def html5(): # $ requestHandler
resp = Response(response="<h1>hello</h1>") # $ HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/html6") # $routeSetup="/html6"
def html6(): # $requestHandler
@app.route("/html6") # $ routeSetup="/html6"
def html6(): # $ requestHandler
# note: flask.Flask.response_class is set to `flask.Response` by default.
# it can be overridden, but we don't try to handle that right now.
resp = Flask.response_class("<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
resp = Flask.response_class("<h1>hello</h1>") # $ HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/html7") # $routeSetup="/html7"
def html7(): # $requestHandler
@app.route("/html7") # $ routeSetup="/html7"
def html7(): # $ requestHandler
# note: app.response_class (flask.Flask.response_class) is set to `flask.Response` by default.
# it can be overridden, but we don't try to handle that right now.
resp = app.response_class("<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
resp = app.response_class("<h1>hello</h1>") # $ HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/html8") # $routeSetup="/html8"
def html8(): # $requestHandler
resp = make_response() # $HttpResponse mimetype=text/html
@app.route("/html8") # $ routeSetup="/html8"
def html8(): # $ requestHandler
resp = make_response() # $ HttpResponse mimetype=text/html
resp.set_data("<h1>hello</h1>") # $ MISSING: responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/jsonify") # $routeSetup="/jsonify"
def jsonify_route(): # $requestHandler
@app.route("/jsonify") # $ routeSetup="/jsonify"
def jsonify_route(): # $ requestHandler
x = "x"; y = "y"; z = "z"
if True:
import flask.json
resp = flask.json.jsonify(x, y, z=z) # $HttpResponse mimetype=application/json responseBody=x responseBody=y responseBody=z
resp = flask.json.jsonify(x, y, z=z) # $ HttpResponse mimetype=application/json responseBody=x responseBody=y responseBody=z
assert resp.mimetype == "application/json"
resp = app.json.response(x, y, z=z) # $HttpResponse mimetype=application/json responseBody=x responseBody=y responseBody=z
resp = app.json.response(x, y, z=z) # $ HttpResponse mimetype=application/json responseBody=x responseBody=y responseBody=z
assert resp.mimetype == "application/json"
resp = jsonify(x, y, z=z) # $ HttpResponse mimetype=application/json responseBody=x responseBody=y responseBody=z
@@ -83,24 +83,24 @@ def jsonify_route(): # $requestHandler
# Tricky return handling
################################################################################
@app.route("/tricky-return1") # $routeSetup="/tricky-return1"
def tricky_return1(): # $requestHandler
@app.route("/tricky-return1") # $ routeSetup="/tricky-return1"
def tricky_return1(): # $ requestHandler
if "raw" in request.args:
resp = "<h1>hellu</h1>"
else:
resp = make_response("<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
return resp # $HttpResponse mimetype=text/html responseBody=resp
resp = make_response("<h1>hello</h1>") # $ HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
return resp # $ HttpResponse mimetype=text/html responseBody=resp
def helper():
if "raw" in request.args:
return "<h1>hellu</h1>"
else:
return make_response("<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
return make_response("<h1>hello</h1>") # $ HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
@app.route("/tricky-return2") # $routeSetup="/tricky-return2"
def tricky_return2(): # $requestHandler
@app.route("/tricky-return2") # $ routeSetup="/tricky-return2"
def tricky_return2(): # $ requestHandler
resp = helper()
return resp # $HttpResponse mimetype=text/html responseBody=resp
return resp # $ HttpResponse mimetype=text/html responseBody=resp
################################################################################
@@ -108,16 +108,16 @@ def tricky_return2(): # $requestHandler
################################################################################
@app.route("/content-type/response-modification1") # $routeSetup="/content-type/response-modification1"
def response_modification1(): # $requestHandler
resp = make_response("<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
@app.route("/content-type/response-modification1") # $ routeSetup="/content-type/response-modification1"
def response_modification1(): # $ requestHandler
resp = make_response("<h1>hello</h1>") # $ HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
resp.content_type = "text/plain" # $ MISSING: HttpResponse mimetype=text/plain
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/content-type/response-modification2") # $routeSetup="/content-type/response-modification2"
def response_modification2(): # $requestHandler
resp = make_response("<h1>hello</h1>") # $HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
@app.route("/content-type/response-modification2") # $ routeSetup="/content-type/response-modification2"
def response_modification2(): # $ requestHandler
resp = make_response("<h1>hello</h1>") # $ HttpResponse mimetype=text/html responseBody="<h1>hello</h1>"
resp.headers["content-type"] = "text/plain" # $ headerWriteNameUnsanitized="content-type" headerWriteValue="text/plain" MISSING: HttpResponse mimetype=text/plain
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@@ -126,61 +126,61 @@ def response_modification2(): # $requestHandler
# see https://werkzeug.palletsprojects.com/en/1.0.x/wrappers/#werkzeug.wrappers.Response
@app.route("/content-type/Response1") # $routeSetup="/content-type/Response1"
def Response1(): # $requestHandler
resp = Response("<h1>hello</h1>", mimetype="text/plain") # $HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
@app.route("/content-type/Response1") # $ routeSetup="/content-type/Response1"
def Response1(): # $ requestHandler
resp = Response("<h1>hello</h1>", mimetype="text/plain") # $ HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/content-type/Response2") # $routeSetup="/content-type/Response2"
def Response2(): # $requestHandler
resp = Response("<h1>hello</h1>", content_type="text/plain; charset=utf-8") # $HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
@app.route("/content-type/Response2") # $ routeSetup="/content-type/Response2"
def Response2(): # $ requestHandler
resp = Response("<h1>hello</h1>", content_type="text/plain; charset=utf-8") # $ HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/content-type/Response3") # $routeSetup="/content-type/Response3"
def Response3(): # $requestHandler
@app.route("/content-type/Response3") # $ routeSetup="/content-type/Response3"
def Response3(): # $ requestHandler
# content_type argument takes priority (and result is text/plain)
resp = Response("<h1>hello</h1>", content_type="text/plain; charset=utf-8", mimetype="text/html") # $HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
resp = Response("<h1>hello</h1>", content_type="text/plain; charset=utf-8", mimetype="text/html") # $ HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/content-type/Response4") # $routeSetup="/content-type/Response4"
def Response4(): # $requestHandler
@app.route("/content-type/Response4") # $ routeSetup="/content-type/Response4"
def Response4(): # $ requestHandler
# note: capitalization of Content-Type does not matter
resp = Response("<h1>hello</h1>", headers={"Content-TYPE": "text/plain"}) # $ headerWriteBulk=Dict headerWriteBulkUnsanitized=name headerWriteNameUnsanitized="Content-TYPE" headerWriteValue="text/plain" HttpResponse responseBody="<h1>hello</h1>" SPURIOUS: mimetype=text/html MISSING: mimetype=text/plain
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/content-type/Response5") # $routeSetup="/content-type/Response5"
def Response5(): # $requestHandler
@app.route("/content-type/Response5") # $ routeSetup="/content-type/Response5"
def Response5(): # $ requestHandler
# content_type argument takes priority (and result is text/plain)
# note: capitalization of Content-Type does not matter
resp = Response("<h1>hello</h1>", headers={"Content-TYPE": "text/html"}, content_type="text/plain; charset=utf-8") # $ headerWriteBulk=Dict headerWriteBulkUnsanitized=name headerWriteNameUnsanitized="Content-TYPE" headerWriteValue="text/html" HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/content-type/Response6") # $routeSetup="/content-type/Response6"
def Response6(): # $requestHandler
@app.route("/content-type/Response6") # $ routeSetup="/content-type/Response6"
def Response6(): # $ requestHandler
# mimetype argument takes priority over header (and result is text/plain)
# note: capitalization of Content-Type does not matter
resp = Response("<h1>hello</h1>", headers={"Content-TYPE": "text/html"}, mimetype="text/plain") # $ headerWriteBulk=Dict headerWriteBulkUnsanitized=name headerWriteNameUnsanitized="Content-TYPE" headerWriteValue="text/html" HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/content-type/Flask-response-class") # $routeSetup="/content-type/Flask-response-class"
def Flask_response_class(): # $requestHandler
@app.route("/content-type/Flask-response-class") # $ routeSetup="/content-type/Flask-response-class"
def Flask_response_class(): # $ requestHandler
# note: flask.Flask.response_class is set to `flask.Response` by default.
# it can be overridden, but we don't try to handle that right now.
resp = Flask.response_class("<h1>hello</h1>", mimetype="text/plain") # $HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
resp = Flask.response_class("<h1>hello</h1>", mimetype="text/plain") # $ HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@app.route("/content-type/app-response-class") # $routeSetup="/content-type/app-response-class"
def app_response_class(): # $requestHandler
@app.route("/content-type/app-response-class") # $ routeSetup="/content-type/app-response-class"
def app_response_class(): # $ requestHandler
# note: app.response_class (flask.Flask.response_class) is set to `flask.Response` by default.
# it can be overridden, but we don't try to handle that right now.
resp = app.response_class("<h1>hello</h1>", mimetype="text/plain") # $HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
resp = app.response_class("<h1>hello</h1>", mimetype="text/plain") # $ HttpResponse mimetype=text/plain responseBody="<h1>hello</h1>"
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@@ -192,8 +192,8 @@ def app_response_class(): # $requestHandler
################################################################################
@app.route("/redirect-simple") # $routeSetup="/redirect-simple"
def redirect_simple(): # $requestHandler
@app.route("/redirect-simple") # $ routeSetup="/redirect-simple"
def redirect_simple(): # $ requestHandler
next = request.args['next']
resp = redirect(next) # $ HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation=next
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
@@ -206,13 +206,13 @@ def redirect_simple(): # $requestHandler
def unk():
return
@app.route("/setting_cookie") # $routeSetup="/setting_cookie"
def setting_cookie(): # $requestHandler
@app.route("/setting_cookie") # $ routeSetup="/setting_cookie"
def setting_cookie(): # $ requestHandler
resp = make_response() # $ HttpResponse mimetype=text/html
resp.set_cookie("key", "value") # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax
resp.set_cookie(key="key", value="value") # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax
resp.set_cookie(key="key", value="value", secure=True, httponly=True, samesite="Strict") # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=true CookieHttpOnly=true CookieSameSite=Strict
resp.set_cookie(key="key", value="value", secure=unk(), httponly=unk(), samesite=unk()) # $ CookieWrite CookieName="key" CookieValue="value"
resp.set_cookie(key="key", value="value", secure=unk(), httponly=unk(), samesite=unk()) # $ CookieWrite CookieName="key" CookieValue="value"
resp.headers.add("Set-Cookie", "key2=value2") # $ headerWriteNameUnsanitized="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax
resp.delete_cookie("key3") # $ CookieWrite CookieName="key3"
resp.delete_cookie(key="key3") # $ CookieWrite CookieName="key3"
@@ -222,33 +222,33 @@ def setting_cookie(): # $requestHandler
# Headers
################################################################################
@app.route("/headers") # $routeSetup="/headers"
def headers(): # $requestHandler
@app.route("/headers") # $ routeSetup="/headers"
def headers(): # $ requestHandler
resp1 = Response() # $ HttpResponse mimetype=text/html
resp1.headers["X-MyHeader"] = "a" # $ headerWriteNameUnsanitized="X-MyHeader" headerWriteValue="a"
resp2 = make_response() # $ HttpResponse mimetype=text/html
resp2.headers["X-MyHeader"] = "aa" # $ headerWriteNameUnsanitized="X-MyHeader" headerWriteValue="aa"
resp2.headers.extend({"X-MyHeader2": "b"}) # $ headerWriteBulk=Dict headerWriteBulkUnsanitized=name headerWriteNameUnsanitized="X-MyHeader2" headerWriteValue="b"
resp2.headers.extend({"X-MyHeader2": "b"}) # $ headerWriteBulk=Dict headerWriteBulkUnsanitized=name headerWriteNameUnsanitized="X-MyHeader2" headerWriteValue="b"
resp3 = make_response("hello", 200, {"X-MyHeader3": "c"}) # $ HttpResponse mimetype=text/html responseBody="hello" headerWriteBulk=Dict headerWriteBulkUnsanitized=name headerWriteNameUnsanitized="X-MyHeader3" headerWriteValue="c"
resp4 = make_response("hello", {"X-MyHeader4": "d"}) # $ HttpResponse mimetype=text/html responseBody="hello" headerWriteBulk=Dict headerWriteBulkUnsanitized=name headerWriteNameUnsanitized="X-MyHeader4" headerWriteValue="d"
resp5 = Response(headers={"X-MyHeader5":"e"}) # $ HttpResponse mimetype=text/html headerWriteBulk=Dict headerWriteBulkUnsanitized=name headerWriteBulkUnsanitized=name headerWriteNameUnsanitized="X-MyHeader5" headerWriteValue="e"
return resp5 # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp5
@app.route("/werkzeug-headers") # $routeSetup="/werkzeug-headers"
def werkzeug_headers(): # $requestHandler
@app.route("/werkzeug-headers") # $ routeSetup="/werkzeug-headers"
def werkzeug_headers(): # $ requestHandler
response = Response() # $ HttpResponse mimetype=text/html
headers = Headers()
headers.add("X-MyHeader1", "a") # $ headerWriteNameUnsanitized="X-MyHeader1" headerWriteValue="a"
headers.add_header("X-MyHeader2", "b") # $ headerWriteNameUnsanitized="X-MyHeader2" headerWriteValue="b"
headers.set("X-MyHeader3", "c") # $ headerWriteNameUnsanitized="X-MyHeader3" headerWriteValue="c"
headers.setdefault("X-MyHeader4", "d") # $ headerWriteNameUnsanitized="X-MyHeader4" headerWriteValue="d"
headers.__setitem__("X-MyHeader5", "e") # $ headerWriteNameUnsanitized="X-MyHeader5" headerWriteValue="e"
headers["X-MyHeader6"] = "f" # $ headerWriteNameUnsanitized="X-MyHeader6" headerWriteValue="f"
headers.set("X-MyHeader3", "c") # $ headerWriteNameUnsanitized="X-MyHeader3" headerWriteValue="c"
headers.setdefault("X-MyHeader4", "d") # $ headerWriteNameUnsanitized="X-MyHeader4" headerWriteValue="d"
headers.__setitem__("X-MyHeader5", "e") # $ headerWriteNameUnsanitized="X-MyHeader5" headerWriteValue="e"
headers["X-MyHeader6"] = "f" # $ headerWriteNameUnsanitized="X-MyHeader6" headerWriteValue="f"
h1 = {"X-MyHeader7": "g"} # $ headerWriteNameUnsanitized="X-MyHeader7" headerWriteValue="g"
headers.extend(h1) # $ headerWriteBulk=h1 headerWriteBulkUnsanitized=name
headers.extend(h1) # $ headerWriteBulk=h1 headerWriteBulkUnsanitized=name
h2 = [("X-MyHeader8", "h")] # $ headerWriteNameUnsanitized="X-MyHeader8" headerWriteValue="h"
headers.extend(h2) # $ headerWriteBulk=h2 headerWriteBulkUnsanitized=name
response.headers = headers
headers.extend(h2) # $ headerWriteBulk=h2 headerWriteBulkUnsanitized=name
response.headers = headers
return response # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=response
################################################################################

View File

@@ -5,28 +5,28 @@ app = Flask(__name__)
SOME_ROUTE = "/some/route"
@app.route(SOME_ROUTE) # $routeSetup="/some/route"
def some_route(): # $requestHandler
return make_response("some_route") # $HttpResponse
@app.route(SOME_ROUTE) # $ routeSetup="/some/route"
def some_route(): # $ requestHandler
return make_response("some_route") # $ HttpResponse
def index(): # $requestHandler
return make_response("index") # $HttpResponse
app.add_url_rule('/index', 'index', index) # $routeSetup="/index"
def index(): # $ requestHandler
return make_response("index") # $ HttpResponse
app.add_url_rule('/index', 'index', index) # $ routeSetup="/index"
# We don't support this yet, and I think that's OK
def later_set(): # $ MISSING: requestHandler
return make_response("later_set") # $HttpResponse
app.add_url_rule('/later-set', 'later_set', view_func=None) # $routeSetup="/later-set"
return make_response("later_set") # $ HttpResponse
app.add_url_rule('/later-set', 'later_set', view_func=None) # $ routeSetup="/later-set"
app.view_functions['later_set'] = later_set
# We don't want to execute this at runtime (since program will crash). Just using
# `False` makes our analysis skip it, so here's a workaround :D
if __file__ == "False":
@app.route(UNKNOWN_ROUTE) # $routeSetup
def unkown_route(foo, bar): # $requestHandler routedParameter=foo routedParameter=bar
return make_response("unkown_route") # $HttpResponse
@app.route(UNKNOWN_ROUTE) # $ routeSetup
def unkown_route(foo, bar): # $ requestHandler routedParameter=foo routedParameter=bar
return make_response("unkown_route") # $ HttpResponse
# View
#
@@ -40,7 +40,7 @@ class ShowUser(View):
def dispatch_request(self, user_id): # $ requestHandler routedParameter=user_id
return "user_id: {}".format(user_id) # $ HttpResponse
app.add_url_rule("/basic/user/<int:user_id>", view_func=ShowUser.as_view('show_user')) # $routeSetup="/basic/user/<int:user_id>"
app.add_url_rule("/basic/user/<int:user_id>", view_func=ShowUser.as_view('show_user')) # $ routeSetup="/basic/user/<int:user_id>"
class WithoutKnownRoute1(View):
@@ -81,9 +81,9 @@ class UserAPI(MethodView):
user_view = UserAPI.as_view("user_api")
app.add_url_rule("/users/", defaults={"user_id": None}, view_func=user_view, methods=["GET",]) # $routeSetup="/users/"
app.add_url_rule("/users/", view_func=user_view, methods=["POST",]) # $routeSetup="/users/"
app.add_url_rule("/users/<int:user_id>", view_func=user_view, methods=["GET", "PUT", "DELETE"]) # $routeSetup="/users/<int:user_id>"
app.add_url_rule("/users/", defaults={"user_id": None}, view_func=user_view, methods=["GET",]) # $ routeSetup="/users/"
app.add_url_rule("/users/", view_func=user_view, methods=["POST",]) # $ routeSetup="/users/"
app.add_url_rule("/users/<int:user_id>", view_func=user_view, methods=["GET", "PUT", "DELETE"]) # $ routeSetup="/users/<int:user_id>"
class WithoutKnownRoute2(MethodView):

View File

@@ -1,6 +1,6 @@
from flask import Flask, request
app = Flask(__name__)
@app.route("/save-uploaded-file") # $routeSetup="/save-uploaded-file"
def test_taint(): # $requestHandler
@app.route("/save-uploaded-file") # $ routeSetup="/save-uploaded-file"
def test_taint(): # $ requestHandler
request.files['key'].save("path") # $ getAPathArgument="path"

View File

@@ -1,5 +1,5 @@
import flask
import flask
class MySessionInterface(flask.sessions.SessionInterface):
def open_session(self, app, request):
ensure_tainted(request) # $tainted
ensure_tainted(request) # $ tainted

View File

@@ -1,8 +1,8 @@
from flask import Flask, request, render_template_string, stream_template_string
app = Flask(__name__)
@app.route("/test_taint/<name>/<int:number>") # $routeSetup="/test_taint/<name>/<int:number>"
def test_taint(name = "World!", number="0", foo="foo"): # $requestHandler routedParameter=name routedParameter=number
@app.route("/test_taint/<name>/<int:number>") # $ routeSetup="/test_taint/<name>/<int:number>"
def test_taint(name = "World!", number="0", foo="foo"): # $ requestHandler routedParameter=name routedParameter=number
ensure_tainted(name, number) # $ tainted
ensure_not_tainted(foo)
@@ -245,8 +245,8 @@ def test_taint(name = "World!", number="0", foo="foo"): # $requestHandler route
ensure_not_tainted(x)
@app.route("/debug/<foo>/<bar>", methods=['GET']) # $routeSetup="/debug/<foo>/<bar>"
def debug(foo, bar): # $requestHandler routedParameter=foo routedParameter=bar
@app.route("/debug/<foo>/<bar>", methods=['GET']) # $ routeSetup="/debug/<foo>/<bar>"
def debug(foo, bar): # $ requestHandler routedParameter=foo routedParameter=bar
print("request.view_args", request.view_args)
print("request.headers {!r}".format(request.headers))
@@ -254,20 +254,20 @@ def debug(foo, bar): # $requestHandler routedParameter=foo routedParameter=bar
print("request.pragma {!r}".format(request.pragma))
return 'ok' # $HttpResponse
return 'ok' # $ HttpResponse
@app.route("/stream", methods=['POST']) # $routeSetup="/stream"
def stream(): # $requestHandler
@app.route("/stream", methods=['POST']) # $ routeSetup="/stream"
def stream(): # $ requestHandler
print(request.path)
s = request.stream
print(s)
# just works :)
print(s.read())
return 'ok' # $HttpResponse
return 'ok' # $ HttpResponse
@app.route("/input_stream", methods=['POST']) # $routeSetup="/input_stream"
def input_stream(): # $requestHandler
@app.route("/input_stream", methods=['POST']) # $ routeSetup="/input_stream"
def input_stream(): # $ requestHandler
print(request.path)
s = request.input_stream
print(s)
@@ -275,38 +275,38 @@ def input_stream(): # $requestHandler
# be handled manually
print(s.read())
return 'ok' # $HttpResponse
return 'ok' # $ HttpResponse
@app.route("/form", methods=['POST']) # $routeSetup="/form"
def form(): # $requestHandler
@app.route("/form", methods=['POST']) # $ routeSetup="/form"
def form(): # $ requestHandler
print(request.path)
print("request.form", request.form)
return 'ok' # $HttpResponse
return 'ok' # $ HttpResponse
@app.route("/cache_control", methods=['POST']) # $routeSetup="/cache_control"
def cache_control(): # $requestHandler
@app.route("/cache_control", methods=['POST']) # $ routeSetup="/cache_control"
def cache_control(): # $ requestHandler
print(request.path)
print("request.cache_control.max_age", request.cache_control.max_age, type(request.cache_control.max_age))
print("request.cache_control.max_stale", request.cache_control.max_stale, type(request.cache_control.max_stale))
print("request.cache_control.min_fresh", request.cache_control.min_fresh, type(request.cache_control.min_fresh))
return 'ok' # $HttpResponse
return 'ok' # $ HttpResponse
@app.route("/file_upload", methods=['POST']) # $routeSetup="/file_upload"
def file_upload(): # $requestHandler
@app.route("/file_upload", methods=['POST']) # $ routeSetup="/file_upload"
def file_upload(): # $ requestHandler
print(request.path)
for k,v in request.files.items():
print(k, v, v.name, v.filename, v.stream)
return 'ok' # $HttpResponse
return 'ok' # $ HttpResponse
@app.route("/args", methods=['GET']) # $routeSetup="/args"
def args(): # $requestHandler
@app.route("/args", methods=['GET']) # $ routeSetup="/args"
def args(): # $ requestHandler
print(request.path)
print("request.args", request.args)
return 'ok' # $HttpResponse
return 'ok' # $ HttpResponse
# curl --header "My-Header: some-value" http://localhost:5000/debug/fooval/barval
# curl --header "Pragma: foo, bar" --header "Pragma: stuff, foo" http://localhost:5000/debug/fooval/barval

View File

@@ -1,16 +1,16 @@
from flask import Flask, Response, stream_with_context, render_template_string, stream_template_string
app = Flask(__name__)
@app.route("/a") # $routeSetup="/a"
@app.route("/a") # $ routeSetup="/a"
def a(): # $ requestHandler
r = render_template_string("abc") # $ templateConstruction="abc"
return r # $ HttpResponse
@app.route("/b") # $routeSetup="/b"
@app.route("/b") # $ routeSetup="/b"
def b(): # $ requestHandler
s = stream_template_string("abc") # $ templateConstruction="abc"
r = Response(stream_with_context(s)) # $ HttpResponse
return r # $ HttpResponse
if __name__ == "__main__":
app.run(debug=True)
app.run(debug=True)

View File

@@ -5,35 +5,35 @@ see https://www.pyinvoke.org/
import invoke
invoke.run("cmd1; cmd2") # $getCommand="cmd1; cmd2"
invoke.run(command="cmd1; cmd2") # $getCommand="cmd1; cmd2"
invoke.run("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
invoke.run(command="cmd1; cmd2") # $ getCommand="cmd1; cmd2"
def with_sudo():
invoke.sudo("cmd1; cmd2") # $getCommand="cmd1; cmd2"
invoke.sudo(command="cmd1; cmd2") # $getCommand="cmd1; cmd2"
invoke.sudo("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
invoke.sudo(command="cmd1; cmd2") # $ getCommand="cmd1; cmd2"
def manual_context():
c = invoke.Context()
c.run("cmd1; cmd2") # $getCommand="cmd1; cmd2"
c.sudo("cmd1; cmd2") # $getCommand="cmd1; cmd2"
c.run("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
c.sudo("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
# invoke.Context is just an alias for invoke.context.Context
c2 = invoke.context.Context()
c2.run("cmd1; cmd2") # $getCommand="cmd1; cmd2"
c2.run("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
manual_context()
def foo_helper(c):
c.run("cmd1; cmd2") # $getCommand="cmd1; cmd2"
c.run("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
# for use with the 'invoke' command-line tool
@invoke.task
def foo(c):
# 'c' is a invoke.context.Context
c.run("cmd1; cmd2") # $getCommand="cmd1; cmd2"
c.run("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
foo_helper(c)

View File

@@ -18,7 +18,7 @@ add_salary = ("INSERT INTO salaries "
data_employee = ('Geert', 'Vanderkelen', tomorrow, 'M', date(1977, 6, 14))
# Insert new employee
cursor.execute(add_employee, data_employee) # $getSql=add_employee
cursor.execute(add_employee, data_employee) # $ getSql=add_employee
emp_no = cursor.lastrowid
# Insert salary information
@@ -28,10 +28,10 @@ data_salary = {
'from_date': tomorrow,
'to_date': date(9999, 1, 1),
}
cursor.execute(add_salary, data_salary) # $getSql=add_salary
cursor.execute(add_salary, data_salary) # $ getSql=add_salary
# Make sure data is committed to the database
cnx.commit()
cursor.close()
cnx.close()
cnx.close()

View File

@@ -4,4 +4,4 @@ db=MySQLdb.connect(passwd="moonpie",db="thangs")
c=db.cursor()
max_price=5
c.execute("some sql", (max_price,)) # $getSql="some sql"
c.execute("some sql", (max_price,)) # $ getSql="some sql"

View File

@@ -2,79 +2,79 @@ import pandas as pd
import sqlite3
df = pd.DataFrame({'temp_c': [17.0, 25.0]}, index=['Portland', 'Berkeley'])
df.sample().query("query") # $getCode="query"
df.mod().query("query") # $getCode="query"
pd.eval("pythonExpr", target=df) # $getCode="pythonExpr"
df.sample().query("query") # $ getCode="query"
df.mod().query("query") # $ getCode="query"
pd.eval("pythonExpr", target=df) # $ getCode="pythonExpr"
df = pd.read_csv("filepath")
df.query("query") # $getCode="query"
df.eval("query") # $getCode="query"
df.copy().query("query") # $getCode="query"
df.query("query") # $ getCode="query"
df.eval("query") # $ getCode="query"
df.copy().query("query") # $ getCode="query"
df = pd.read_fwf("filepath")
df.query("query") # $getCode="query"
df.eval("query") # $getCode="query"
df.query("query") # $ getCode="query"
df.eval("query") # $ getCode="query"
df = pd.read_pickle("filepath") # $ decodeInput="filepath" decodeOutput=pd.read_pickle(..) decodeFormat=pickle decodeMayExecuteInput
df.query("query") # $getCode="query"
df.eval("query") # $getCode="query"
df.query("query") # $ getCode="query"
df.eval("query") # $ getCode="query"
df = pd.read_table("filepath")
df.query("query") # $getCode="query"
df.eval("query") # $getCode="query"
df.query("query") # $ getCode="query"
df.eval("query") # $ getCode="query"
df = pd.read_clipboard("filepath")
df.query("query") # $getCode="query"
df.eval("query") # $getCode="query"
df.query("query") # $ getCode="query"
df.eval("query") # $ getCode="query"
df = pd.read_excel("filepath")
df.query("query") # $getCode="query"
df.eval("query") # $getCode="query"
df.query("query") # $ getCode="query"
df.eval("query") # $ getCode="query"
df = pd.read_html("filepath")
df[0].query("query") # $getCode="query"
df[0].query("query") # $ getCode="query"
df = pd.read_xml("filepath")
df.query("query") # $getCode="query"
df.eval("query") # $getCode="query"
df.query("query") # $ getCode="query"
df.eval("query") # $ getCode="query"
df = pd.read_parquet("filepath")
df.query("query") # $getCode="query"
df.eval("query") # $getCode="query"
df.query("query") # $ getCode="query"
df.eval("query") # $ getCode="query"
df = pd.read_orc("filepath")
df.query("query") # $getCode="query"
df.eval("query") # $getCode="query"
df.query("query") # $ getCode="query"
df.eval("query") # $ getCode="query"
df = pd.read_spss("filepath")
df.query("query") # $getCode="query"
df.eval("query") # $getCode="query"
df.query("query") # $ getCode="query"
df.eval("query") # $ getCode="query"
df = pd.read_sql_table("filepath", 'postgres:///db_name')
df.query("query") # $getCode="query"
df.eval("query") # $getCode="query"
df.query("query") # $ getCode="query"
df.eval("query") # $ getCode="query"
connection = sqlite3.connect("pets.db")
df = pd.read_sql_query("sql query", connection) # $getSql="sql query"
df.query("query") # $getCode="query"
df.eval("query") # $getCode="query"
df = pd.read_sql_query("sql query", connection) # $ getSql="sql query"
df.query("query") # $ getCode="query"
df.eval("query") # $ getCode="query"
df = pd.read_sql("sql query", connection) # $getSql="sql query"
df.query("query") # $getCode="query"
df.eval("query") # $getCode="query"
df = pd.read_sql("sql query", connection) # $ getSql="sql query"
df.query("query") # $ getCode="query"
df.eval("query") # $ getCode="query"
df = pd.read_gbq("filepath")
df.query("query") # $getCode="query"
df.eval("query") # $getCode="query"
df.query("query") # $ getCode="query"
df.eval("query") # $ getCode="query"
df = pd.read_stata("filepath")
df.query("query") # $getCode="query"
df.eval("query") # $getCode="query"
df.query("query") # $ getCode="query"
df.eval("query") # $ getCode="query"
df = pd.read_sas("filepath")
df.query("query") # $getCode="query"
df.eval("query") # $getCode="query"
df.query("query") # $ getCode="query"
df.eval("query") # $ getCode="query"
df = pd.read_sas("filepath", iterator=True, chunksize=1)
df.query("query")
df = pd.read_sas("filepath", iterator=False, chunksize=1)
@@ -82,5 +82,5 @@ df.query("query")
df = pd.read_sas("filepath", iterator=True, chunksize=None)
df.query("query")
df = pd.read_sas("filepath", iterator=False, chunksize=None)
df.query("query") # $getCode="query"
df.eval("query") # $getCode="query"
df.query("query") # $ getCode="query"
df.eval("query") # $ getCode="query"

View File

@@ -8,4 +8,4 @@ paramiko_ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
paramiko_ssh_client.connect(hostname="127.0.0.1", port="22", username="ssh_user_name", pkey="k", timeout=11, banner_timeout=200)
cmd = "cmd"
paramiko_ssh_client.connect('hostname', username='user', password='yourpassword', sock=paramiko.ProxyCommand(cmd)) # $getCommand=cmd
paramiko_ssh_client.connect('hostname', username='user', password='yourpassword', sock=paramiko.ProxyCommand(cmd)) # $ getCommand=cmd

View File

@@ -8,7 +8,7 @@ def ignore(*args, **kwargs): pass
ensure_tainted = ensure_not_tainted = ignore
@view_config(route_name="test1") # $ routeSetup
def test1(request): # $ requestHandler
def test1(request): # $ requestHandler
ensure_tainted(
request, # $ tainted
@@ -26,7 +26,7 @@ def test1(request): # $ requestHandler
request.host_url, # $ tainted
request.if_match, # $ tainted
request.if_none_match, # $ tainted
request.if_range, # $ tainted
request.if_range, # $ tainted
request.pragma, # $ tainted
request.range, # $ tainted
request.referer, # $ tainted
@@ -71,11 +71,11 @@ def test1(request): # $ requestHandler
request.copy_get(), # $ tainted
request.copy().GET['a'], # $ tainted
request.copy_get().body # $ tainted
)
)
return Response("Ok") # $ HttpResponse responseBody="Ok" mimetype=text/html
def test2(request): # $ requestHandler
def test2(request): # $ requestHandler
ensure_tainted(request) # $ tainted
resp = Response("Ok", content_type="text/plain") # $ HttpResponse responseBody="Ok" mimetype=text/plain
@@ -83,7 +83,7 @@ def test2(request): # $ requestHandler
return resp
@view_config(route_name="test3", renderer="string") # $ routeSetup
def test3(ctx, req): # $ requestHandler
def test3(ctx, req): # $ requestHandler
ensure_tainted(req) # $ tainted
resp = req.response # $ HttpResponse mimetype=text/html
resp.set_cookie("hi", "there") # $ CookieWrite CookieName="hi" CookieValue="there" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax
@@ -93,13 +93,13 @@ def test3(ctx, req): # $ requestHandler
@view_config(route_name="test4", renderer="string") # $ routeSetup
def test4(request): # $ requestHandler
a = HTTPMultipleChoices("redirect") # $HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation="redirect"
b = HTTPMovedPermanently(location="redirect") # $HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation="redirect"
c = HTTPFound(location="redirect") # $HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation="redirect"
d = HTTPSeeOther(location="redirect") # $HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation="redirect"
e = HTTPUseProxy(location="redirect") # $HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation="redirect"
f = HTTPTemporaryRedirect(location="redirect") # $HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation="redirect"
g = HTTPPermanentRedirect(location="redirect") # $HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation="redirect"
a = HTTPMultipleChoices("redirect") # $ HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation="redirect"
b = HTTPMovedPermanently(location="redirect") # $ HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation="redirect"
c = HTTPFound(location="redirect") # $ HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation="redirect"
d = HTTPSeeOther(location="redirect") # $ HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation="redirect"
e = HTTPUseProxy(location="redirect") # $ HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation="redirect"
f = HTTPTemporaryRedirect(location="redirect") # $ HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation="redirect"
g = HTTPPermanentRedirect(location="redirect") # $ HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation="redirect"
raise a
# Unsupported cases
@@ -121,7 +121,7 @@ class Test6:
self.req = request
def test6method(self): # $ MISSING: requestHandler
ensure_not_tainted(self)
ensure_not_tainted(self)
ensure_tainted(self.req) # $ MISSING: tainted
return "Ok" # $ MISSING: HttpResponse mimetype=text/html responseBody="Ok"
@@ -132,7 +132,7 @@ class Test6:
self.req = request
def __call__(self): # $ MISSING: requestHandler
ensure_not_tainted(self)
ensure_not_tainted(self)
ensure_tainted(self.req) # $ MISSING: tainted
return "Ok" # $ MISSING: HttpResponse mimetype=text/html responseBody="Ok"

View File

@@ -18,5 +18,5 @@ from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls), # $ routeSetup="admin/"
path("", include("testapp.urls")), # $routeSetup=""
path("", include("testapp.urls")), # $ routeSetup=""
]

View File

@@ -6,27 +6,27 @@ ruamel.yaml.load(stream=payload) # $ decodeInput=payload decodeOutput=ruamel.ya
ruamel.yaml.load(payload, ruamel.yaml.Loader) # $ decodeInput=payload decodeOutput=ruamel.yaml.load(..) decodeFormat=YAML decodeMayExecuteInput
# Safe:
ruamel.yaml.load(payload, ruamel.yaml.SafeLoader) # $ decodeInput=payload decodeOutput=ruamel.yaml.load(..) decodeFormat=YAML
ruamel.yaml.load(payload, ruamel.yaml.SafeLoader) # $ decodeInput=payload decodeOutput=ruamel.yaml.load(..) decodeFormat=YAML
ruamel.yaml.load(payload, Loader=ruamel.yaml.SafeLoader) # $ decodeInput=payload decodeOutput=ruamel.yaml.load(..) decodeFormat=YAML
ruamel.yaml.load(payload, ruamel.yaml.BaseLoader) # $ decodeInput=payload decodeOutput=ruamel.yaml.load(..) decodeFormat=YAML
ruamel.yaml.safe_load(payload) # $ decodeInput=payload decodeOutput=ruamel.yaml.safe_load(..) decodeFormat=YAML
ruamel.yaml.safe_load(payload) # $ decodeInput=payload decodeOutput=ruamel.yaml.safe_load(..) decodeFormat=YAML
################################################################################
# load_all variants
################################################################################
# Unsafe:
ruamel.yaml.load_all(payload) # $ decodeInput=payload decodeOutput=ruamel.yaml.load_all(..) decodeFormat=YAML decodeMayExecuteInput
ruamel.yaml.load_all(payload) # $ decodeInput=payload decodeOutput=ruamel.yaml.load_all(..) decodeFormat=YAML decodeMayExecuteInput
# Safe:
ruamel.yaml.safe_load_all(payload) # $ decodeInput=payload decodeOutput=ruamel.yaml.safe_load_all(..) decodeFormat=YAML
ruamel.yaml.safe_load_all(payload) # $ decodeInput=payload decodeOutput=ruamel.yaml.safe_load_all(..) decodeFormat=YAML
################################################################################
# C-based loaders with `libyaml`
################################################################################
# Unsafe:
ruamel.yaml.load(payload, ruamel.yaml.CLoader) # $ decodeInput=payload decodeOutput=ruamel.yaml.load(..) decodeFormat=YAML decodeMayExecuteInput
ruamel.yaml.load(payload, ruamel.yaml.CLoader) # $ decodeInput=payload decodeOutput=ruamel.yaml.load(..) decodeFormat=YAML decodeMayExecuteInput
# Safe:
ruamel.yaml.load(payload, ruamel.yaml.CSafeLoader) # $ decodeInput=payload decodeOutput=ruamel.yaml.load(..) decodeFormat=YAML

View File

@@ -1,2 +1,2 @@
# exec statement is Python 2 specific
exec "print(42)" # $getCode="print(42)"
exec "print(42)" # $ getCode="print(42)"

View File

@@ -1,14 +1,14 @@
########################################
import os
os.popen2("cmd1; cmd2") # $getCommand="cmd1; cmd2"
os.popen3("cmd1; cmd2") # $getCommand="cmd1; cmd2"
os.popen4("cmd1; cmd2") # $getCommand="cmd1; cmd2"
os.popen2("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
os.popen3("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
os.popen4("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
os.popen2(cmd="cmd1; cmd2") # $getCommand="cmd1; cmd2"
os.popen3(cmd="cmd1; cmd2") # $getCommand="cmd1; cmd2"
os.popen4(cmd="cmd1; cmd2") # $getCommand="cmd1; cmd2"
os.popen2(cmd="cmd1; cmd2") # $ getCommand="cmd1; cmd2"
os.popen3(cmd="cmd1; cmd2") # $ getCommand="cmd1; cmd2"
os.popen4(cmd="cmd1; cmd2") # $ getCommand="cmd1; cmd2"
# os.popen does not support keyword arguments, so this is a TypeError
os.popen(cmd="cmd1; cmd2")
@@ -16,21 +16,21 @@ os.popen(cmd="cmd1; cmd2")
########################################
import platform
platform.popen("cmd1; cmd2") # $getCommand="cmd1; cmd2"
platform.popen(cmd="cmd1; cmd2") # $getCommand="cmd1; cmd2"
platform.popen("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
platform.popen(cmd="cmd1; cmd2") # $ getCommand="cmd1; cmd2"
########################################
# popen2 was deprecated in Python 2.6, but still available in Python 2.7
import popen2
popen2.popen2("cmd1; cmd2") # $getCommand="cmd1; cmd2"
popen2.popen3("cmd1; cmd2") # $getCommand="cmd1; cmd2"
popen2.popen4("cmd1; cmd2") # $getCommand="cmd1; cmd2"
popen2.Popen3("cmd1; cmd2") # $getCommand="cmd1; cmd2"
popen2.Popen4("cmd1; cmd2") # $getCommand="cmd1; cmd2"
popen2.popen2("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
popen2.popen3("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
popen2.popen4("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
popen2.Popen3("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
popen2.Popen4("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
popen2.popen2(cmd="cmd1; cmd2") # $getCommand="cmd1; cmd2"
popen2.popen3(cmd="cmd1; cmd2") # $getCommand="cmd1; cmd2"
popen2.popen4(cmd="cmd1; cmd2") # $getCommand="cmd1; cmd2"
popen2.Popen3(cmd="cmd1; cmd2") # $getCommand="cmd1; cmd2"
popen2.Popen4(cmd="cmd1; cmd2") # $getCommand="cmd1; cmd2"
popen2.popen2(cmd="cmd1; cmd2") # $ getCommand="cmd1; cmd2"
popen2.popen3(cmd="cmd1; cmd2") # $ getCommand="cmd1; cmd2"
popen2.popen4(cmd="cmd1; cmd2") # $ getCommand="cmd1; cmd2"
popen2.Popen3(cmd="cmd1; cmd2") # $ getCommand="cmd1; cmd2"
popen2.Popen4(cmd="cmd1; cmd2") # $ getCommand="cmd1; cmd2"

View File

@@ -1,4 +1,4 @@
import builtins
# exec being part of builtins is Python 3 only
builtins.exec("print(42)") # $getCode="print(42)"
builtins.exec("print(42)") # $ getCode="print(42)"

View File

@@ -9,16 +9,16 @@ if sys.version_info[0] == 3:
if sys.version_info[0] == 2:
import __builtin__ as builtins
exec("print(42)") # $getCode="print(42)"
eval("print(42)") # $getCode="print(42)"
exec("print(42)") # $ getCode="print(42)"
eval("print(42)") # $ getCode="print(42)"
builtins.eval("print(42)") # $getCode="print(42)"
builtins.eval("print(42)") # $ getCode="print(42)"
cmd = compile("print(42)", "<filename>", "exec")
exec(cmd) # $getCode=cmd
exec(cmd) # $ getCode=cmd
cmd = builtins.compile("print(42)", "<filename>", "exec")
exec(cmd) # $getCode=cmd
exec(cmd) # $ getCode=cmd
# ------------------------------------------------------------------------------
# taint related

View File

@@ -2,17 +2,17 @@ import os.path
path = "un\\normalized/path"
p1 = os.path.normpath(path) # $pathNormalization
p2 = os.path.normpath(path=path) # $pathNormalization
p1 = os.path.normpath(path) # $ pathNormalization
p2 = os.path.normpath(path=path) # $ pathNormalization
np = os.path.normpath
p3 = np(path) # $pathNormalization
p4 = np(path=path) # $pathNormalization
p3 = np(path) # $ pathNormalization
p4 = np(path=path) # $ pathNormalization
def normalize(path):
return os.path.normpath(path) # $pathNormalization
return os.path.normpath(path) # $ pathNormalization
p5 = normalize(path)

View File

@@ -1,7 +1,7 @@
s = "taintedString"
if s.startswith("tainted"):
s2 = s # $SafeAccessCheck=s
s2 = s # $ SafeAccessCheck=s
pass
sw = s.startswith

View File

@@ -13,8 +13,8 @@ import os
# can't use a string literal with spaces in the tags of an InlineExpectationsTest, so using variables :|
os.popen("cmd1; cmd2") # $getCommand="cmd1; cmd2"
os.system("cmd1; cmd2") # $getCommand="cmd1; cmd2"
os.popen("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
os.system("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
def os_members():
@@ -24,8 +24,8 @@ def os_members():
# :|
from os import popen, system
popen("cmd1; cmd2") # $getCommand="cmd1; cmd2"
system("cmd1; cmd2") # $getCommand="cmd1; cmd2"
popen("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
system("cmd1; cmd2") # $ getCommand="cmd1; cmd2"
########################################
@@ -85,62 +85,62 @@ os.posix_spawnp(path="path", argv=["<progname>", "arg0"], env=env) # $ getComma
import subprocess
subprocess.Popen("cmd1; cmd2", shell=True) # $getCommand="cmd1; cmd2"
subprocess.Popen("cmd1; cmd2", shell="truthy string") # $getCommand="cmd1; cmd2"
subprocess.Popen(["cmd1; cmd2", "shell-arg"], shell=True) # $getCommand="cmd1; cmd2"
subprocess.Popen("cmd1; cmd2", shell=True, executable="/bin/bash") # $getCommand="cmd1; cmd2" getCommand="/bin/bash"
subprocess.Popen("cmd1; cmd2", shell=True) # $ getCommand="cmd1; cmd2"
subprocess.Popen("cmd1; cmd2", shell="truthy string") # $ getCommand="cmd1; cmd2"
subprocess.Popen(["cmd1; cmd2", "shell-arg"], shell=True) # $ getCommand="cmd1; cmd2"
subprocess.Popen("cmd1; cmd2", shell=True, executable="/bin/bash") # $ getCommand="cmd1; cmd2" getCommand="/bin/bash"
subprocess.Popen("executable") # $getCommand="executable"
subprocess.Popen(["executable", "arg0"]) # $getCommand="executable"
subprocess.Popen("<progname>", executable="executable") # $getCommand="executable"
subprocess.Popen(["<progname>", "arg0"], executable="executable") # $getCommand="executable"
subprocess.Popen("executable") # $ getCommand="executable"
subprocess.Popen(["executable", "arg0"]) # $ getCommand="executable"
subprocess.Popen("<progname>", executable="executable") # $ getCommand="executable"
subprocess.Popen(["<progname>", "arg0"], executable="executable") # $ getCommand="executable"
# call/check_call/check_output/run all work like Popen from a command execution point of view
subprocess.call(["executable", "arg0"]) # $getCommand="executable"
subprocess.check_call(["executable", "arg0"]) # $getCommand="executable"
subprocess.check_output(["executable", "arg0"]) # $getCommand="executable"
subprocess.run(["executable", "arg0"]) # $getCommand="executable"
subprocess.call(["executable", "arg0"]) # $ getCommand="executable"
subprocess.check_call(["executable", "arg0"]) # $ getCommand="executable"
subprocess.check_output(["executable", "arg0"]) # $ getCommand="executable"
subprocess.run(["executable", "arg0"]) # $ getCommand="executable"
########################################
# actively using known shell as the executable
subprocess.Popen(["/bin/sh", "-c", "vuln"]) # $getCommand="/bin/sh" MISSING: getCommand="vuln"
subprocess.Popen(["/bin/bash", "-c", "vuln"]) # $getCommand="/bin/bash" MISSING: getCommand="vuln"
subprocess.Popen(["/bin/dash", "-c", "vuln"]) # $getCommand="/bin/dash" MISSING: getCommand="vuln"
subprocess.Popen(["/bin/zsh", "-c", "vuln"]) # $getCommand="/bin/zsh" MISSING: getCommand="vuln"
subprocess.Popen(["/bin/sh", "-c", "vuln"]) # $ getCommand="/bin/sh" MISSING: getCommand="vuln"
subprocess.Popen(["/bin/bash", "-c", "vuln"]) # $ getCommand="/bin/bash" MISSING: getCommand="vuln"
subprocess.Popen(["/bin/dash", "-c", "vuln"]) # $ getCommand="/bin/dash" MISSING: getCommand="vuln"
subprocess.Popen(["/bin/zsh", "-c", "vuln"]) # $ getCommand="/bin/zsh" MISSING: getCommand="vuln"
subprocess.Popen(["sh", "-c", "vuln"]) # $getCommand="sh" MISSING: getCommand="vuln"
subprocess.Popen(["bash", "-c", "vuln"]) # $getCommand="bash" MISSING: getCommand="vuln"
subprocess.Popen(["dash", "-c", "vuln"]) # $getCommand="dash" MISSING: getCommand="vuln"
subprocess.Popen(["zsh", "-c", "vuln"]) # $getCommand="zsh" MISSING: getCommand="vuln"
subprocess.Popen(["sh", "-c", "vuln"]) # $ getCommand="sh" MISSING: getCommand="vuln"
subprocess.Popen(["bash", "-c", "vuln"]) # $ getCommand="bash" MISSING: getCommand="vuln"
subprocess.Popen(["dash", "-c", "vuln"]) # $ getCommand="dash" MISSING: getCommand="vuln"
subprocess.Popen(["zsh", "-c", "vuln"]) # $ getCommand="zsh" MISSING: getCommand="vuln"
# Check that we don't consider ANY argument a command injection sink
subprocess.Popen(["sh", "/bin/python"]) # $getCommand="sh"
subprocess.Popen(["sh", "/bin/python"]) # $ getCommand="sh"
subprocess.Popen(["cmd.exe", "/c", "vuln"]) # $getCommand="cmd.exe" MISSING: getCommand="vuln"
subprocess.Popen(["cmd.exe", "/C", "vuln"]) # $getCommand="cmd.exe" MISSING: getCommand="vuln"
subprocess.Popen(["cmd", "/c", "vuln"]) # $getCommand="cmd" MISSING: getCommand="vuln"
subprocess.Popen(["cmd", "/C", "vuln"]) # $getCommand="cmd" MISSING: getCommand="vuln"
subprocess.Popen(["cmd.exe", "/c", "vuln"]) # $ getCommand="cmd.exe" MISSING: getCommand="vuln"
subprocess.Popen(["cmd.exe", "/C", "vuln"]) # $ getCommand="cmd.exe" MISSING: getCommand="vuln"
subprocess.Popen(["cmd", "/c", "vuln"]) # $ getCommand="cmd" MISSING: getCommand="vuln"
subprocess.Popen(["cmd", "/C", "vuln"]) # $ getCommand="cmd" MISSING: getCommand="vuln"
subprocess.Popen(["<progname>", "-c", "vuln"], executable="/bin/bash") # $getCommand="/bin/bash" MISSING: getCommand="vuln"
subprocess.Popen(["<progname>", "-c", "vuln"], executable="/bin/bash") # $ getCommand="/bin/bash" MISSING: getCommand="vuln"
if UNKNOWN:
os.execl("/bin/sh", "<progname>", "-c", "vuln") # $getCommand="/bin/sh" getAPathArgument="/bin/sh" MISSING: getCommand="vuln"
os.execl("/bin/sh", "<progname>", "-c", "vuln") # $ getCommand="/bin/sh" getAPathArgument="/bin/sh" MISSING: getCommand="vuln"
os.spawnl(os.P_WAIT, "/bin/sh", "<progname>", "-c", "vuln") # $getCommand="/bin/sh" getAPathArgument="/bin/sh" MISSING: getCommand="vuln"
os.spawnl(os.P_WAIT, "/bin/sh", "<progname>", "-c", "vuln") # $ getCommand="/bin/sh" getAPathArgument="/bin/sh" MISSING: getCommand="vuln"
########################################
# Passing arguments by reference
args = ["/bin/sh", "-c", "vuln"]
subprocess.Popen(args) # $getCommand=args
subprocess.Popen(args) # $ getCommand=args
args = "<progname>"
use_shell = False
exe = "executable"
subprocess.Popen(args, shell=use_shell, executable=exe) # $getCommand=exe
subprocess.Popen(args, shell=use_shell, executable=exe) # $ getCommand=exe
################################################################################
@@ -165,14 +165,14 @@ cmd = "sh -c " + wrong_use
import asyncio
from asyncio import subprocess
asyncio.run(asyncio.create_subprocess_exec("executable", "arg0")) # $getCommand="executable" getAPathArgument="executable"
asyncio.run(subprocess.create_subprocess_exec("executable", "arg0")) # $getCommand="executable" getAPathArgument="executable"
asyncio.run(asyncio.create_subprocess_exec("executable", "arg0")) # $ getCommand="executable" getAPathArgument="executable"
asyncio.run(subprocess.create_subprocess_exec("executable", "arg0")) # $ getCommand="executable" getAPathArgument="executable"
loop = asyncio.new_event_loop()
loop.run_until_complete(loop.subprocess_exec(asyncio.SubprocessProtocol, "executable", "arg0")) # $getCommand="executable" getAPathArgument="executable"
loop.run_until_complete(loop.subprocess_exec(asyncio.SubprocessProtocol, "executable", "arg0")) # $ getCommand="executable" getAPathArgument="executable"
asyncio.run(asyncio.create_subprocess_shell("shell_command")) # $getCommand="shell_command" getAPathArgument="shell_command"
asyncio.run(subprocess.create_subprocess_shell("shell_command")) # $getCommand="shell_command" getAPathArgument="shell_command"
asyncio.run(asyncio.create_subprocess_shell("shell_command")) # $ getCommand="shell_command" getAPathArgument="shell_command"
asyncio.run(subprocess.create_subprocess_shell("shell_command")) # $ getCommand="shell_command" getAPathArgument="shell_command"
loop = asyncio.get_running_loop()
loop.run_until_complete(loop.subprocess_shell(asyncio.SubprocessProtocol, "shell_command")) # $getCommand="shell_command" getAPathArgument="shell_command"
loop.run_until_complete(loop.subprocess_shell(asyncio.SubprocessProtocol, "shell_command")) # $ getCommand="shell_command" getAPathArgument="shell_command"

View File

@@ -1,16 +1,16 @@
import yaml
# Unsafe:
yaml.load(payload) # $decodeInput=payload decodeOutput=yaml.load(..) decodeFormat=YAML decodeMayExecuteInput
yaml.load(stream=payload) # $decodeInput=payload decodeOutput=yaml.load(..) decodeFormat=YAML decodeMayExecuteInput
yaml.load(payload, yaml.Loader) # $decodeInput=payload decodeOutput=yaml.load(..) decodeFormat=YAML decodeMayExecuteInput
yaml.load(payload) # $ decodeInput=payload decodeOutput=yaml.load(..) decodeFormat=YAML decodeMayExecuteInput
yaml.load(stream=payload) # $ decodeInput=payload decodeOutput=yaml.load(..) decodeFormat=YAML decodeMayExecuteInput
yaml.load(payload, yaml.Loader) # $ decodeInput=payload decodeOutput=yaml.load(..) decodeFormat=YAML decodeMayExecuteInput
yaml.unsafe_load(payload) # $ decodeInput=payload decodeOutput=yaml.unsafe_load(..) decodeFormat=YAML decodeMayExecuteInput
yaml.full_load(payload) # $ decodeInput=payload decodeOutput=yaml.full_load(..) decodeFormat=YAML decodeMayExecuteInput
# Safe:
yaml.load(payload, yaml.SafeLoader) # $ decodeInput=payload decodeOutput=yaml.load(..) decodeFormat=YAML
yaml.load(payload, Loader=yaml.SafeLoader) # $decodeInput=payload decodeOutput=yaml.load(..) decodeFormat=YAML
yaml.load(payload, yaml.BaseLoader) # $decodeInput=payload decodeOutput=yaml.load(..) decodeFormat=YAML
yaml.load(payload, Loader=yaml.SafeLoader) # $ decodeInput=payload decodeOutput=yaml.load(..) decodeFormat=YAML
yaml.load(payload, yaml.BaseLoader) # $ decodeInput=payload decodeOutput=yaml.load(..) decodeFormat=YAML
yaml.safe_load(payload) # $ decodeInput=payload decodeOutput=yaml.safe_load(..) decodeFormat=YAML
################################################################################
@@ -34,5 +34,5 @@ yaml.load(payload, yaml.CLoader) # $ decodeInput=payload decodeOutput=yaml.load
yaml.load(payload, yaml.CFullLoader) # $ decodeInput=payload decodeOutput=yaml.load(..) decodeFormat=YAML decodeMayExecuteInput
# Safe:
yaml.load(payload, yaml.CSafeLoader) # $decodeInput=payload decodeOutput=yaml.load(..) decodeFormat=YAML
yaml.load(payload, yaml.CBaseLoader) # $decodeInput=payload decodeOutput=yaml.load(..) decodeFormat=YAML
yaml.load(payload, yaml.CSafeLoader) # $ decodeInput=payload decodeOutput=yaml.load(..) decodeFormat=YAML
yaml.load(payload, yaml.CBaseLoader) # $ decodeInput=payload decodeOutput=yaml.load(..) decodeFormat=YAML

View File

@@ -1,46 +1,46 @@
import re
re.compile(r'[A-Z]') #$ charRange=1:2-3:4
re.compile(r'[A-Z]') # $ charRange=1:2-3:4
try:
re.compile(r'[]-[]') #$ SPURIOUS: charRange=1:2-3:4
re.compile(r'[]-[]') # $ SPURIOUS: charRange=1:2-3:4
raise Exception("this should not be reached")
except re.error:
pass
re.compile(r'[---]') #$ charRange=1:2-3:4
re.compile(r'[\---]') #$ charRange=1:3-4:5
re.compile(r'[--\-]') #$ charRange=1:2-3:5
re.compile(r'[\--\-]') #$ charRange=1:3-4:6
re.compile(r'[0-9-A-Z]') #$ charRange=1:2-3:4 charRange=5:6-7:8
re.compile(r'[0\-9-A-Z]') #$ charRange=4:5-6:7
re.compile(r'[---]') # $ charRange=1:2-3:4
re.compile(r'[\---]') # $ charRange=1:3-4:5
re.compile(r'[--\-]') # $ charRange=1:2-3:5
re.compile(r'[\--\-]') # $ charRange=1:3-4:6
re.compile(r'[0-9-A-Z]') # $ charRange=1:2-3:4 charRange=5:6-7:8
re.compile(r'[0\-9-A-Z]') # $ charRange=4:5-6:7
try:
re.compile(r'[0--9-A-Z]') #$ SPURIOUS: charRange=1:2-3:4 charRange=4:5-6:7
re.compile(r'[0--9-A-Z]') # $ SPURIOUS: charRange=1:2-3:4 charRange=4:5-6:7
raise Exception("this should not be reached")
except re.error:
pass
re.compile(r'[^A-Z]') #$ charRange=2:3-4:5
re.compile(r'[^A-Z]') # $ charRange=2:3-4:5
re.compile(r'[\0-\09]') #$ charRange=1:3-4:6
re.compile(r'[\0-\07]') #$ charRange=1:3-4:7
re.compile(r'[\0-\09]') # $ charRange=1:3-4:6
re.compile(r'[\0-\07]') # $ charRange=1:3-4:7
re.compile(r'[\0123-5]') #$ charRange=5:6-7:8
re.compile(r'[\0123-5]') # $ charRange=5:6-7:8
#Negative lookahead
re.compile(r'(?!not-this)^[A-Z_]+$') #$ charRange=14:15-16:17
re.compile(r'(?!not-this)^[A-Z_]+$') # $ charRange=14:15-16:17
#Negative lookbehind
re.compile(r'^[A-Z_]+$(?<!not-this)') #$ charRange=2:3-4:5
re.compile(r'^[A-Z_]+$(?<!not-this)') # $ charRange=2:3-4:5
#OK -- ODASA-ODASA-3968
re.compile('(?:[^%]|^)?%\((\w*)\)[a-z]') #$ charRange=22:23-24:25
re.compile('(?:[^%]|^)?%\((\w*)\)[a-z]') # $ charRange=22:23-24:25
#ODASA-3985
#Half Surrogate pairs
re.compile(u'[\uD800-\uDBFF][\uDC00-\uDFFF]') #$ charRange=1:2-3:4 charRange=6:7-8:9
re.compile(u'[\uD800-\uDBFF][\uDC00-\uDFFF]') # $ charRange=1:2-3:4 charRange=6:7-8:9
#Outside BMP
re.compile(u'[\U00010000-\U0010ffff]') #$ charRange=1:2-3:4
re.compile(u'[\U00010000-\U0010ffff]') # $ charRange=1:2-3:4

Some files were not shown because too many files have changed in this diff Show More