mirror of
https://github.com/github/codeql.git
synced 2026-04-29 02:35:15 +02:00
Apply suggestions from code review
Co-authored-by: Felicity Chapman <felicitymay@github.com>
This commit is contained in:
@@ -9,16 +9,15 @@ external libraries.
|
||||
About this article
|
||||
------------------
|
||||
|
||||
This article describes how to use API graphs to reference classes and functions defined in library
|
||||
code. You can use API graphs to conveniently refer to external library functions when defining things like
|
||||
remote flow sources.
|
||||
This article describes how you can use API graphs to reference classes and functions defined in library
|
||||
code. API graphs are particularly useful when you want to model the remote flow sources available from external library functions.
|
||||
|
||||
|
||||
Module and class references
|
||||
---------------------------
|
||||
|
||||
The most common entry point into the API graph will be the point where a toplevel module or class is
|
||||
accessed. For example, you can access the API graph node corresponding to the ``::Regexp`` class
|
||||
The most common entry point into the API graph is when a top-level module or class is accessed.
|
||||
For example, you can access the API graph node corresponding to the ``::Regexp`` class
|
||||
by using the ``API::getTopLevelMember`` method defined in the ``codeql.ruby.ApiGraphs`` module, as the
|
||||
following snippet demonstrates.
|
||||
|
||||
@@ -29,7 +28,7 @@ following snippet demonstrates.
|
||||
select API::getTopLevelMember("Regexp")
|
||||
|
||||
This query selects the API graph nodes corresponding to references to the ``Regexp`` class. For nested
|
||||
modules and classes, you can use the ``getMember` method. For example the following query selects
|
||||
modules and classes, you can use the ``getMember`` method. For example the following query selects
|
||||
references to the ``Net::HTTP`` class.
|
||||
|
||||
.. code-block:: ql
|
||||
@@ -38,9 +37,8 @@ references to the ``Net::HTTP`` class.
|
||||
|
||||
select API::getTopLevelMember("Net").getMember("HTTP")
|
||||
|
||||
Note that the given module name *must not* contain any ```::`` symbols. Thus, something like
|
||||
`API::getTopLevelMember("Net::HTTP")`` will not do what you expect. Instead, this should be decomposed
|
||||
into an access of the ``HTTP`` member of the API graph node for ``Net``, as in the example above.
|
||||
Note that you should specify module names without ``::`` symbols. If you write ``API::getTopLevelMember("Net::HTTP")``, it will not do what you expect. Instead, you need to decompose this name
|
||||
into an access of the ``HTTP`` member of the API graph node for ``Net``, as shown in the example above.
|
||||
|
||||
Calls and class instantiations
|
||||
------------------------------
|
||||
@@ -78,13 +76,13 @@ The following snippet builds on the above to find calls of the ``Regexp#match?``
|
||||
Subclasses
|
||||
----------
|
||||
|
||||
For many libraries, the main mode of usage is to extend one or more library classes. To track this
|
||||
Many libraries are used by extending one or more library classes. To track this
|
||||
in the API graph, you can use the ``getASubclass`` method to get the API graph node corresponding to
|
||||
all the immediate subclasses of this node. To find *all* subclasses, use ``*`` or ``+`` to apply the
|
||||
method repeatedly, as in ``getASubclass*``.
|
||||
the immediate subclasses of a node. To find *all* subclasses, use ``*`` or ``+`` to apply the
|
||||
method repeatedly. You can see an example where all subclasses are identified using ``getASubclass*`` below.
|
||||
|
||||
Note that ``getASubclass`` does not account for any subclassing that takes place in library code
|
||||
that has not been extracted. Thus, it may be necessary to account for this in the models you write.
|
||||
Note that ``getASubclass`` can only return subclasses that are extracted as part of the CodeQL database
|
||||
that you are analyzing. When libraries have predefined subclasses, you will need to explicitly include them in your model.
|
||||
For example, the ``ActionController::Base`` class has a predefined subclass ``Rails::ApplicationController``. To find
|
||||
all subclasses of ``ActionController::Base``, you must explicitly include the subclasses of ``Rails::ApplicationController`` as well.
|
||||
|
||||
@@ -109,10 +107,14 @@ Using the API graph in dataflow queries
|
||||
|
||||
Dataflow queries often search for points where data from external sources enters the code base
|
||||
as well as places where data leaves the code base. API graphs provide a convenient way to refer
|
||||
to external API components such as library functions and their inputs and outputs. API graph nodes
|
||||
cannot be used directly in dataflow queries they model entities that are defined externally,
|
||||
while dataflow nodes correspond to entities defined in the current code base. To brigde this gap
|
||||
the API node classes provide the ``asSource()`` and ``asSink()`` methods.
|
||||
to external API components such as library functions and their inputs and outputs.
|
||||
However, you do not use API graph nodes directly in dataflow queries.
|
||||
|
||||
- API graph nodes model entities that are defined outside your code base.
|
||||
- Dataflow nodes model entities defined within the current code base.
|
||||
|
||||
You bridge the gap between the entities outside and inside your code base using
|
||||
the API node class methods: ``asSource()`` and ``asSink()``.
|
||||
|
||||
The ``asSource()`` method is used to select dataflow nodes where a value from an external source
|
||||
enters the current code base. A typical example is the return value of a library function such as
|
||||
@@ -135,15 +137,15 @@ of the ``File.write(path, value)`` method.
|
||||
|
||||
select API::getTopLevelMember("File").getMethod("write").getParameter(1).asSink()
|
||||
|
||||
A more complex example is a call to ``File.open`` with a block argument. This function creates a ```File`` instance
|
||||
and passes it to the supplied block. In this case the first parameter of the block is the place where an
|
||||
externally created value enters the code base, i.e. the ``|file|`` in the example below:
|
||||
A more complex example is a call to ``File.open`` with a block argument. This function creates a ``File`` instance
|
||||
and passes it to the supplied block. In this case, we are interested in the first parameter of the block because this is where an
|
||||
externally created value enters the code base, that is, the ``|file|`` in the Ruby example below:
|
||||
|
||||
.. code-block:: ruby
|
||||
|
||||
File.open("/my/file.txt", "w") { |file| file << "Hello world" }
|
||||
|
||||
The following snippet finds parameters of blocks of ``File.open`` method calls:
|
||||
The following snippet of CodeQL finds parameters of blocks of ``File.open`` method calls:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
@@ -152,7 +154,7 @@ The following snippet finds parameters of blocks of ``File.open`` method calls:
|
||||
select API::getTopLevelMember("File").getMethod("open").getBlock().getParameter(0).asSource()
|
||||
|
||||
The following example is a dataflow query that that uses API graphs to find cases where data that
|
||||
is read flows into a call to ```File.write``.
|
||||
is read flows into a call to ``File.write``.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
|
||||
Reference in New Issue
Block a user