From 9b08b06de4b4e6230c008b13849b384ea85f6aad Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 27 Feb 2023 09:07:07 +0100 Subject: [PATCH 1/3] python: update deprecated predicate names --- .../using-api-graphs-in-python.rst | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst b/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst index adfcdaa8d60b..95f612af33ab 100644 --- a/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst +++ b/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst @@ -31,16 +31,16 @@ following snippet demonstrates. This query selects the API graph node corresponding to the ``re`` module. This node represents the fact that the ``re`` module has been imported rather than a specific location in the program where the import happens. Therefore, there will be at most one result per project, and it will not have a useful location, so you'll have to click `Show 1 non-source result` in order to see it. -To find where the ``re`` module is referenced in the program, you can use the ``getAUse`` method. The following query selects all references to the ``re`` module in the current database. +To find where the ``re`` module is referenced in the program, you can use the ``getAValueReachableFromSource`` method. The following query selects all references to the ``re`` module in the current database. .. code-block:: ql import python import semmle.python.ApiGraphs - select API::moduleImport("re").getAUse() + select API::moduleImport("re").getAValueReachableFromSource() -Note that the ``getAUse`` method accounts for local flow, so that ``my_re_compile`` +Note that the ``getAValueReachableFromSource`` method accounts for local flow, so that ``my_re_compile`` in the following snippet is correctly recognized as a reference to the ``re.compile`` function. @@ -53,7 +53,7 @@ correctly recognized as a reference to the ``re.compile`` function. r = my_re_compile(".*") If you only require immediate uses, without taking local flow into account, then you can use -the ``getAnImmediateUse`` method instead. +the ``asSource`` method instead. Note that the given module name *must not* contain any dots. Thus, something like ``API::moduleImport("flask.views")`` will not do what you expect. Instead, this should be decomposed @@ -71,7 +71,7 @@ the above ``re.compile`` example, you can now find references to ``re.compile``. import python import semmle.python.ApiGraphs - select API::moduleImport("re").getMember("compile").getAUse() + select API::moduleImport("re").getMember("compile").getAValueReachableFromSource() In addition to ``getMember``, you can use the ``getUnknownMember`` method to find references to API components where the name is not known statically. You can use the ``getAMember`` method to @@ -89,12 +89,12 @@ where the return value of ``re.compile`` is used: import python import semmle.python.ApiGraphs - select API::moduleImport("re").getMember("compile").getReturn().getAUse() + select API::moduleImport("re").getMember("compile").getReturn().getAValueReachableFromSource() Note that this includes all uses of the result of ``re.compile``, including those reachable via -local flow. To get just the *calls* to ``re.compile``, you can use ``getAnImmediateUse`` instead of -``getAUse``. As this is a common occurrence, you can use ``getACall`` instead of -``getReturn`` followed by ``getAnImmediateUse``. +local flow. To get just the *calls* to ``re.compile``, you can use ``asSource`` instead of +``getAValueReachableFromSource``. As this is a common occurrence, you can use ``getACall`` instead of +``getReturn`` followed by ``asSource``. Note that the API graph does not distinguish between class instantiations and function calls. As far as it's concerned, both are simply places where an API graph node is called. @@ -122,7 +122,7 @@ all subclasses of ``View``, you must explicitly include the subclasses of ``Meth API::moduleImport("flask").getMember("views").getMember(["View", "MethodView"]).getASubclass*() } - select viewClass().getAUse() + select viewClass().getAValueReachableFromSource() Note the use of the set literal ``["View", "MethodView"]`` to match both classes simultaneously. From 1447c2348a10a83b92f8e67edd41cebe30d68390 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 27 Feb 2023 10:06:23 +0100 Subject: [PATCH 2/3] python: describe `API::CallNode` --- .../using-api-graphs-in-python.rst | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst b/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst index 95f612af33ab..169fa093a2ae 100644 --- a/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst +++ b/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst @@ -93,8 +93,32 @@ where the return value of ``re.compile`` is used: Note that this includes all uses of the result of ``re.compile``, including those reachable via local flow. To get just the *calls* to ``re.compile``, you can use ``asSource`` instead of -``getAValueReachableFromSource``. As this is a common occurrence, you can use ``getACall`` instead of -``getReturn`` followed by ``asSource``. +``getAValueReachableFromSource``. As this is a common occurrence, you can, instead of +``getReturn`` followed by ``asSource``, simply use ``getACall``. This will result in an +``API::CallNode``, which deserves a small description of its own. + +``API::CallNode``s are not ``API::Node``s. Instead they are ``DataFlow::Node``s with some convenience +predicates that allows you to recover ``API::Node``s for the return value as well as for parameters +to the call. This enables you to constrain the call in various ways using the API graph. The following +snippet finds all calls to ``re.compile`` where the ``pattern`` argument comes from parsing a command +line argument using the ``argparse`` library. + +.. code-block:: ql + + import python + import semmle.python.ApiGraphs + + from API::CallNode call + where + call = API::moduleImport("re").getMember("compile").getACall() and + call.getParameter(0, "pattern") = + API::moduleImport("argparse") + .getMember("ArgumentParser") + .getReturn() + .getMember("parse_args") + .getMember(_) + select call + Note that the API graph does not distinguish between class instantiations and function calls. As far as it's concerned, both are simply places where an API graph node is called. From 335be21943897857339e84930f69c0f711aa5397 Mon Sep 17 00:00:00 2001 From: yoff Date: Mon, 27 Feb 2023 14:53:31 +0100 Subject: [PATCH 3/3] Update docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst Co-authored-by: Taus --- .../codeql-language-guides/using-api-graphs-in-python.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst b/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst index 169fa093a2ae..02adfdaf9833 100644 --- a/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst +++ b/docs/codeql/codeql-language-guides/using-api-graphs-in-python.rst @@ -98,7 +98,7 @@ local flow. To get just the *calls* to ``re.compile``, you can use ``asSource`` ``API::CallNode``, which deserves a small description of its own. ``API::CallNode``s are not ``API::Node``s. Instead they are ``DataFlow::Node``s with some convenience -predicates that allows you to recover ``API::Node``s for the return value as well as for parameters +predicates that allows you to recover ``API::Node``s for the return value as well as for arguments to the call. This enables you to constrain the call in various ways using the API graph. The following snippet finds all calls to ``re.compile`` where the ``pattern`` argument comes from parsing a command line argument using the ``argparse`` library.