Merge pull request #1681 from jf205/responsive-slides

Docs: a few CSS tweaks to improve slide appearance on small screens
This commit is contained in:
semmledocs-ac 2019-08-08 16:35:57 +01:00 коммит произвёл GitHub
Родитель cb8544d6e4 38e42edf04
Коммит ec5b2da7dc
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 717 добавлений и 598 удалений

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 910 KiB

После

Ширина:  |  Высота:  |  Размер: 238 KiB

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

До

Ширина:  |  Высота:  |  Размер: 121 KiB

После

Ширина:  |  Высота:  |  Размер: 121 KiB

Просмотреть файл

@ -140,8 +140,6 @@ slides > slide {
display: block;
position: absolute;
overflow: hidden;
left: 50%;
top: 50%;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
@ -239,13 +237,9 @@ body {
/* line 62, ../scss/default.scss */
slides > slide {
display: none;
font-family: 'Open Sans', Arial, sans-serif;
font-size: 26px;
font-family: 'Lato', sans-serif;
font-size: 2em;
color: #797979;
width: 900px;
height: 700px;
margin-left: -450px;
margin-top: -350px;
padding: 40px 60px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
@ -254,6 +248,7 @@ slides > slide {
-o-transition: all 0.6s ease-in-out;
-webkit-transition: all 0.6s ease-in-out;
transition: all 0.6s ease-in-out;
overflow: auto;
}
/* line 83, ../scss/default.scss */
slides > slide.far-past {
@ -296,7 +291,7 @@ slides > slide.dark {
}
/* line 135, ../scss/default.scss */
slides > slide:not(.nobackground):before {
font-size: 12pt;
font-size: 1em;
content: "";
position: absolute;
bottom: 20px;
@ -311,11 +306,11 @@ slides > slide:not(.nobackground):before {
}
/* line 147, ../scss/default.scss */
slides > slide:not(.nobackground):after {
font-size: 12pt;
font-size: 1em;
content: attr(data-slide-num) "/" attr(data-total-slides);
position: absolute;
position: fixed;
bottom: 20px;
right: 60px;
right: 20px;
line-height: 1.9;
}
/* line 158, ../scss/default.scss */
@ -372,8 +367,8 @@ slides.layout-faux-widescreen > slide {
/* line 212, ../scss/default.scss */
slides.layout-widescreen > slide,
slides.layout-faux-widescreen > slide {
margin-left: -620px;
width: 1240px;
width: 100%;
overflow: auto;
}
/* line 217, ../scss/default.scss */
slides.layout-widescreen > slide.far-past,
@ -456,11 +451,11 @@ h1, h2, h3 {
}
h1 {
font-size: 50px;
font-size: 3em;
}
/* line 280, ../scss/default.scss */
h2 {
font-size: 45px;
font-size: 2em;
line-height: 45px;
letter-spacing: -2px;
color: #515151;
@ -468,7 +463,7 @@ h2 {
/* line 287, ../scss/default.scss */
h3 {
font-size: 30px;
font-size: 1.6em;
letter-spacing: -1px;
line-height: 2;
font-weight: inherit;
@ -524,15 +519,15 @@ ul ul {
/* line 337, ../scss/default.scss */
pre {
font-family: 'consolas', 'Courier New', monospace;
font-size: 20px;
line-height: 28px;
font-size: 1em;
line-height: 1.2em;
padding: 10px 10px 10px 10px;
margin-bottom: 20px;
background-color: #e6e6e6;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
/*overflow: hidden;*/
overflow: auto;
}
/* line 351, ../scss/default.scss */
pre[data-lang]:after {
@ -541,7 +536,7 @@ pre[data-lang]:after {
right: 0;
top: 0;
position: absolute;
font-size: 16pt;
font-size: 1em;
color: white;
padding: 2px 25px;
text-transform: uppercase;
@ -735,7 +730,7 @@ table tr:nth-child(odd) {
/* line 488, ../scss/default.scss */
table th {
color: white;
font-size: 18px;
font-size: 1em;
background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSI0MCUiIHN0b3AtY29sb3I9IiM0Mzg3ZmQiLz48c3RvcCBvZmZzZXQ9IjgwJSIgc3RvcC1jb2xvcj0iIzJhN2NkZiIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==') no-repeat;
background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(40%, #4387fd), color-stop(80%, #2a7cdf)) no-repeat;
background: -moz-linear-gradient(top, #4387fd 40%, #2a7cdf 80%) no-repeat;
@ -744,7 +739,7 @@ table th {
}
/* line 494, ../scss/default.scss */
table td, table th {
font-size: 18px;
font-size: 1em;
padding: 1em 0.5em;
}
/* line 499, ../scss/default.scss */
@ -764,7 +759,7 @@ table.rows {
/* line 510, ../scss/default.scss */
q {
font-size: 45px;
font-size: 2em;
line-height: 72px;
}
/* line 514, ../scss/default.scss */
@ -901,7 +896,7 @@ article.smaller q:before, article.smaller q:after {
/* line 622, ../scss/default.scss */
.note {
position: absolute;
position: fixed;
z-index: 100;
width: 100%;
height: 100%;
@ -1298,7 +1293,7 @@ aside.gdbar img {
}
/* line 891, ../scss/default.scss */
.title-slide hgroup h1 {
font-size: 65px;
font-size: 3em;
line-height: 1.4;
letter-spacing: -3px;
color: white;
@ -1307,13 +1302,13 @@ aside.gdbar img {
}
/* line 898, ../scss/default.scss */
.title-slide hgroup h2 {
font-size: 34px;
font-size: 2em;
color: #a9a9a9;
font-weight: inherit;
}
/* line 904, ../scss/default.scss */
.title-slide hgroup p {
font-size: 20px;
font-size: 1.5em;
color: #797979;
line-height: 1.3;
margin-top: 2em;
@ -1398,16 +1393,16 @@ em {
slide {
background-image: url("../../normal-slide.svg");
background-size: cover;
}
width: 100%;
height: 100%;
overflow: auto;
}
.end-slide {
background-image: url("../../end-slide.svg");
background-size: cover;
background-size: 100% 100%;
background-color: #5c31ff;
}
.agenda-slide {
background-image: url("../../agenda-slide.svg");
background-size: cover;
}
.background2 {
background-image: url("../../not-normal-slide.svg");
@ -1459,6 +1454,7 @@ slide {
p {
color: #2c2a8a;
font-size: 1em;
}
/* James admonition changes */
@ -1471,6 +1467,8 @@ p.first.admonition-title {
text-align: left;
font-size: initial;
width: 100%;
overflow: scroll;
border: 1px solid black;
}
.admonition.note pre {
@ -1489,6 +1487,20 @@ p.first.admonition-title {
width: inherit;
}
/* scale and centre images*/
.image-box {
display: grid;
height: 100%;
}
img {
max-width: 100%;
max-height: 100vh;
margin: auto;
}
@media print {
/* line 978, ../scss/default.scss */
slides slide {
@ -1567,3 +1579,72 @@ p.first.admonition-title {
font-family: monospace !important;
}
}
@media (max-width: 480px) {
html {
height: 100%;
overflow: auto;
position: fixed;
width: 100%;
font-size: 45%;
}
body {
margin: 0;
padding: 0;
}
.column-left, .column-right {
width: 100%;
height: auto;
}
/*img {
transform: scale(0.6) translate(-20%, 0);
}*/
article {
top: 20%;
left: 10%;
right: 10%;
}
}
@media (min-width: 481px) and (max-width: 1024px) {
html {
height: 100%;
overflow: auto;
position: fixed;
width: 100%;
font-size: 70%;
}
body {
margin: 0;
padding: 0;
}
.column-left, .column-right {
width: 100%;
height: auto;
}
img {
transform: scale(0.75)
}
}
@media (min-width: 1025px) and (max-width: 1800px) {
html {
height: 100%;
overflow: auto;
position: fixed;
width: 100%;
font-size: 80%;
}
body {
margin: 0;
padding: 0;
}
}

Просмотреть файл

@ -1,5 +1,6 @@
.. toctree::
:glob:
:hidden:
./intro-to-ql/*
./*

Просмотреть файл

@ -1,176 +0,0 @@
Oops
====
.. code-block:: cpp
int write(int buf[], int size, int loc, int val) {
if (loc >= size) {
// return -1;
}
buf[loc] = val;
return 0;
}
- The return statement has been commented out (during debugging?)
- The if statement is now dead code
- No bounds checking!
.. note::
Heres a simple (artificial) bug, which well develop a QL query to catch.
This function writes a value to a given location in an array, first trying to do a bounds check to validate that the location is within bounds. However, the return statement has been commented out, leaving a redundant if statement and no bounds checking.
This case can act as our “patient zero” in the variant analysis game.
A simple QL query
=================
.. literalinclude:: code-snippets/empty-if-cpp.ql
:language: ql
.. note::
We are going to write a simple query which finds “if statements” with empty “then” blocks, so we can highlight the results like those on the previous slide. The query can be run in the `query console on LGTM <https://lgtm.com/query>`__, or in your `IDE <https://lgtm.com/help/lgtm/running-queries-ide>`__.
A `QL query <https://help.semmle.com/QL/ql-handbook/queries.html>`__ consists of a “select” clause that indicates what results should be returned. Typically it will also provide a “from” clause to declare some variables, and a “where” clause to state conditions over those variables. For more information on the structure of query files (including links to useful topics in the `QL language handbook <https://help.semmle.com/QL/ql-handbook/index.html>`__), see `Introduction to query files <https://help.semmle.com/QL/learn-ql/ql/writing-queries/introduction-to-queries.html>`__.
In our example here, the first line of the query imports the `C/C++ standard QL library <https://help.semmle.com/qldoc/cpp/>`__, which defines concepts like “IfStmt” and “Block”.
The query proper starts by declaring two variables–ifStmt and block. These variables represent sets of values in the database, according to the type of each of the variables. For example, ifStmt has the type IfStmt, which means it represents the set of all if statements in the program.
If we simply selected these two variables::
from IfStmt ifStmt, Block block
select ifStmt, block
We would get a result row for every combination of blocks and if statements in the program. This is known as a cross-product, because there is no logical condition linking the two variables. We can use the where clause to specify the condition that we are only interested in rows where the “block” is the “then” part of the if statement. We do this by specifying::
block = ifStmt.getThen()
This states that the block is equal to (not assigned!) the “then” part of the ``ifStmt``. ``getThen()`` is an operation which is available on any IfStmt. One way to interpret this is as a filtering operation – starting with every pair of block and if statements, check each one to whether the logical condition holds, and only keep the row if that is the case.
We can add a second condition that specifies the block must be empty::
and block.isEmpty()
The ``isEmpty()`` operation is available on any Block, and is only true if the “block” has no children.
Finally, we select a location, at which to report the problem, and a message, to explain what the problem is.
Structure of a QL query
=======================
A **query file** has the extension ``.ql`` and contains a **query clause**, and optionally **predicates**, **classes**, and **modules**.
A **query library** has the extension ``.qll`` and does not contain a query clause, but may contain modules, classes, and predicates.
Each query library also implicitly defines a module.
**Import** statements allow the classes and predicates defined in one module to be used in another.
.. note::
QL queries are always contained in query files with the file extension “.ql”. `Quick queries <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/quick-query.html>`__, run in `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/home-page.html>`__, are no exception: the quick query window maintains a temporary QL file in the background.
Parts of queries can be lifted into `QL library files <https://help.semmle.com/QL/ql-handbook/modules.html#library-modules>`__ with the extension “.qll”. Definitions within such libraries can be brought into scope using “import” statements, and similarly QLL files can import each others definitions using “import” statements.
Logic can be encapsulated as user-defined `predicates <https://help.semmle.com/QL/ql-handbook/predicates.html>`__ and `classes <https://help.semmle.com/QL/ql-handbook/types.html#classes>`__, and organized into `modules <https://help.semmle.com/QL/ql-handbook/modules.html>`__. Each QLL file implicitly defines a module, but QL and QLL files can also contain explicit module definitions, as we will see later.
Predicates in QL
================
A predicate allows you to pull out and name parts of a query.
.. container:: column-left
.. literalinclude:: code-snippets/empty-if-cpp.ql
:language: ql
.. container:: column-right
.. literalinclude:: code-snippets/empty-if-cpp-predicate.ql
:language: ql
.. note::
A QL predicate takes zero or more parameters, and its body is a condition on those parameters. The predicate may (or may not) hold. Predicates may also be recursive, simply by referring to themselves (directly or indirectly).
You can imagine a predicate to be a self-contained from-where-select statement, that produces an intermediate relation, or table. In this case, the isEmpty predicate will be the set of all blocks which are empty.
Classes in QL
=============
A QL class allows you to name a set of values and define (member) predicates on them.
A class has at least one supertype and optionally a **characteristic predicate**; it contains the values that belong to *all* supertypes *and* satisfy the characteristic predicate, if provided.
Memember predicates are inherited and can be overidden.
.. code-block:: ql
class EmptyBlock extends Block {
EmptyBlock() {
this.getNumStmt() = 0
}
}
.. note::
`Classes <https://help.semmle.com/QL/ql-handbook/types.html#classes>`__ model sets of values from the database. A class has one or more supertypes, and inherits `member predicates <https://help.semmle.com/QL/ql-handbook/types.html#member-predicates>`__ (methods) from each of them. Each value in a class must be in every supertype, but additional conditions can be stated in a so-called “characteristic predicate”, which looks a bit like a zero-argument constructor.
In the example, declaring a variable “EmptyBlock e” will allow it to range over only those blocks that have zero statements.
Classes in QL continued
=======================
.. container:: column-left
.. literalinclude:: code-snippets/empty-if-cpp-predicate.ql
:language: ql
.. container:: column-right
.. literalinclude:: code-snippets/empty-if-cpp-class.ql
:language: ql
.. note::
As shown in this example, classes behave much like unary predicates, but with instanceof instead of predicate calls to check membership. Later on, we will see how to define member predicates on classes.
Iterative query refinement
==========================
Common workflow: Start with a simple query, inspect a few results, refine, repeat.
For example, empty then branches are not a problem if there is an else.
Exercise: How can we refine the query to take this into account?
Hints:
- Use member predicate ``IfStmt.getElse()``
- Use ``not exists(...)``
.. note::
QL makes it very easy to experiment with analysis ideas. A common workflow is to start with a simple query (like our “redundant if-statement” example), examine a few results, refine the query based on any patterns that emerge and repeat.
As an exercise, refine the redundant-if query based on the observation that if the if-statement has an “else” clause, then even if the body of the “then” clause is empty, its not actually redundant.
Model answer
============
.. literalinclude:: code-snippets/empty-if-java-model.ql
.. note::
You can explore the results generated when this query is run on exiv2 in LGTM `here <https://lgtm.com/query/4641433299746527262/>`__.
What next?
==========
Try working through the next QL training topic: **Introduction to dataflow**.

Просмотреть файл

@ -1,175 +0,0 @@
Oops
====
.. code-block:: java
int write(int[] buf, int size, int loc, int val) {
if (loc >= size) {
// return -1;
}
buf[loc] = val;
return 0;
}
- The return statement has been commented out (during debugging?)
- The if statement is now dead code
- No explicit bounds checking, will throw ``ArrayIndexOutOfbounds``
.. note::
Heres a simple (artificial) bug, which well develop a QL query to catch.
This function writes a value to a given location in an array, first trying to do a bounds check to validate that the location is within bounds. However, the return statement has been commented out, leaving a redundant if statement and no bounds checking.
This case can act as our “patient zero” in the variant analysis game.
A simple QL query
=================
.. literalinclude:: code-snippets/empty-if-java.ql
:language: ql
.. note::
We are going to write a simple query which finds “if statements” with empty “then” blocks, so we can highlight the results like those on the previous slide. The query can be run in the `query console on LGTM <https://lgtm.com/query>`__, or in your `IDE <https://lgtm.com/help/lgtm/running-queries-ide>`__.
A `QL query <https://help.semmle.com/QL/ql-handbook/queries.html>`__ consists of a “select” clause that indicates what results should be returned. Typically it will also provide a “from” clause to declare some variables, and a “where” clause to state conditions over those variables. For more information on the structure of query files (including links to useful topics in the `QL language handbook <https://help.semmle.com/QL/ql-handbook/index.html>`__), see `Introduction to query files <https://help.semmle.com/QL/learn-ql/ql/writing-queries/introduction-to-queries.html>`__.
In our example here, the first line of the query imports the `Java standard QL library <https://help.semmle.com/qldoc/java/>`__, which defines concepts like “IfStmt” and “Block”.
The query proper starts by declaring two variables–ifStmt and block. These variables represent sets of values in the database, according to the type of each of the variables. For example, ifStmt has the type IfStmt, which means it represents the set of all if statements in the program.
If we simply selected these two variables::
from IfStmt ifStmt, Block block
select ifStmt, block
We would get a result row for every combination of blocks and if statements in the program. This is known as a cross-product, because there is no logical condition linking the two variables. We can use the where clause to specify the condition that we are only interested in rows where the “block” is the “then” part of the if statement. We do this by specifying::
block = ifStmt.getThen()
This states that the block is equal to (not assigned!) the “then” part of the ``ifStmt``. ``getThen()`` is an operation which is available on any IfStmt. One way to interpret this is as a filtering operation – starting with every pair of block and if statements, check each one to whether the logical condition holds, and only keep the row if that is the case.
We can add a second condition that specifies the block must be empty::
and block.isEmpty()
The ``isEmpty()`` operation is available on any Block, and is only true if the “block” has no children.
Finally, we select a location, at which to report the problem, and a message, to explain what the problem is.
Structure of a QL query
=======================
A **query file** has the extension ``.ql`` and contains a **query clause**, and optionally **predicates**, **classes**, and **modules**.
A **query library** has the extension ``.qll`` and does not contain a query clause, but may contain modules, classes, and predicates.
Each query library also implicitly defines a module.
**Import** statements allow the classes and predicates defined in one module to be used in another.
.. note::
QL queries are always contained in query files with the file extension “.ql”. `Quick queries <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/quick-query.html>`__, run in `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/home-page.html>`__, are no exception: the quick query window maintains a temporary QL file in the background.
Parts of queries can be lifted into `QL library files <https://help.semmle.com/QL/ql-handbook/modules.html#library-modules>`__ with the extension “.qll”. Definitions within such libraries can be brought into scope using “import” statements, and similarly QLL files can import each others definitions using “import” statements.
Logic can be encapsulated as user-defined `predicates <https://help.semmle.com/QL/ql-handbook/predicates.html>`__ and `classes <https://help.semmle.com/QL/ql-handbook/types.html#classes>`__, and organized into `modules <https://help.semmle.com/QL/ql-handbook/modules.html>`__. Each QLL file implicitly defines a module, but QL and QLL files can also contain explicit module definitions, as we will see later.
Predicates in QL
================
A predicate allows you to pull out and name parts of a query.
.. container:: column-left
.. literalinclude:: code-snippets/empty-if-java.ql
:language: ql
.. container:: column-right
.. literalinclude:: code-snippets/empty-if-java-predicate.ql
:language: ql
.. note::
A `QL predicate <https://help.semmle.com/QL/ql-handbook/predicates.html>`__ takes zero or more parameters, and its body is a condition on those parameters. The predicate may (or may not) hold. Predicates may also be `recursive <https://help.semmle.com/QL/ql-handbook/predicates.html#recursive-predicates>`__, simply by referring to themselves (directly or indirectly).
You can imagine a predicate to be a self-contained from-where-select statement, that produces an intermediate relation, or table. In this case, the isEmpty predicate will be the set of all blocks which are empty.
Classes in QL
=============
A QL class allows you to name a set of values and define (member) predicates on them.
A class has at least one supertype and optionally a **characteristic predicate**; it contains the values that belong to *all* supertypes *and* satisfy the characteristic predicate, if provided.
Memember predicates are inherited and can be overidden.
.. code-block:: ql
class EmptyBlock extends Block {
EmptyBlock() {
this.getNumStmt() = 0
}
}
.. note::
`Classes <https://help.semmle.com/QL/ql-handbook/types.html#classes>`__ model sets of values from the database. A class has one or more supertypes, and inherits `member predicates <https://help.semmle.com/QL/ql-handbook/types.html#member-predicates>`__ (methods) from each of them. Each value in a class must be in every supertype, but additional conditions can be stated in a so-called “characteristic predicate”, which looks a bit like a zero-argument constructor.
In the example, declaring a variable “EmptyBlock e” will allow it to range over only those blocks that have zero statements.
Classes in QL continued
=======================
.. container:: column-left
.. literalinclude:: code-snippets/empty-if-java-predicate.ql
:language: ql
.. container:: column-right
.. literalinclude:: code-snippets/empty-if-java-class.ql
:language: ql
.. note::
As shown in this example, classes behave much like unary predicates, but with instanceof instead of predicate calls to check membership. Later on, we will see how to define member predicates on classes.
Iterative query refinement
==========================
Common workflow: Start with a simple query, inspect a few results, refine, repeat.
For example, empty then branches are not a problem if there is an else.
Exercise: How can we refine the query to take this into account?
Hints:
- Use member predicate ``IfStmt.getElse()``
- Use ``not exists(...)``
.. note::
QL makes it very easy to experiment with analysis ideas. A common workflow is to start with a simple query (like our “redundant if-statement” example), examine a few results, refine the query based on any patterns that emerge and repeat.
As an exercise, refine the redundant-if query based on the observation that if the if-statement has an “else” clause, then even if the body of the “then” clause is empty, its not actually redundant.
Model answer
============
.. literalinclude:: code-snippets/empty-if-java-model.ql
.. note::
You can explore the results generated when this query is run on apache/struts in LGTM `here <https://lgtm.com/query/1269550358355690774/>`__.
What next?
==========
Try working through the next QL training topic: **Introduction to dataflow**.

Просмотреть файл

@ -1,9 +1,216 @@
.. Make language-specific slideshow by including the relevant bits and pieces from the
.. intro-to-ql folder
Introduction to QL for C/C++
============================
Introduction to variant analysis for C/C++
==========================================
Information
===========
- Pressing ``p`` toggles extra notes (if they're on the current slide)
- Pressing ``f`` toggles full screen viewing
- Pressing ``o`` toggles overview mode
Getting started and setting up
==============================
To try the examples in this presentation you should download:
- `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/install-plugin-free.html>`__
- Snapshot: `exiv2 <https://www.google.com/url?q=http://downloads.lgtm.com/snapshots/cpp/exiv2/Exiv2_exiv2_b090f4d.zip&sa=D&ust=1558103276046000& usg=AFQjCNFOJMgAMNChZHpMO9QEY62W-mYI1Q>`__
More resources:
- If you are completely new to QL, try the `QL detective tutorials <https://help.semmle.com/QL/learn-ql/ql/beginner/ql-tutorials.html>`__.
- To learn more about the main features of QL, try looking at the `QL language handbook <https://help.semmle.com/QL/ql-handbook/>`__.
- For further information about writing queries in QL, see `Writing QL queries <https://help.semmle.com/QL/learn-ql/ql/writing-queries/writing-queries.html>`__.
.. note::
To run the queries featured in this training presentation, we recommend you download the free-to-use `QL for Eclipse plugin <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/getting-started.html>`__.
This plugin allows you to locally access the latest features of QL, including the standard QL libraries and queries. It also provides standard IDE features such as syntax highlighting, jump-to-definition, and tab completion.
A good project to start analyzing is `exiv2 <https://github.com/Exiv2/exiv2>`__–a suitable snapshot to query is available by visiting the link on the slide.
Alternatively, you can query any project (including exiv2) in `the query console <https://lgtm.com/query/project:1506532406873/lang:cpp/>`__ on LGTM.com.
Note that results generated in the query console are likely to differ to those generated in the QL plugin as LGTM.com analyzes the most recent revisions of each project that has been added–the snapshot available to download above is based on an historical version of the code base.
.. Include language-agnostic section here
.. include:: intro-ql-general.rst
.. include:: intro-cpp-specific.rst
Oops
====
.. code-block:: cpp
int write(int buf[], int size, int loc, int val) {
if (loc >= size) {
// return -1;
}
buf[loc] = val;
return 0;
}
- The return statement has been commented out (during debugging?)
- The if statement is now dead code
- No bounds checking!
.. note::
Heres a simple (artificial) bug, which well develop a QL query to catch.
This function writes a value to a given location in an array, first trying to do a bounds check to validate that the location is within bounds. However, the return statement has been commented out, leaving a redundant if statement and no bounds checking.
This case can act as our “patient zero” in the variant analysis game.
A simple QL query
=================
.. literalinclude:: code-snippets/empty-if-cpp.ql
:language: ql
.. note::
We are going to write a simple query which finds “if statements” with empty “then” blocks, so we can highlight the results like those on the previous slide. The query can be run in the `query console on LGTM <https://lgtm.com/query>`__, or in your `IDE <https://lgtm.com/help/lgtm/running-queries-ide>`__.
A `QL query <https://help.semmle.com/QL/ql-handbook/queries.html>`__ consists of a “select” clause that indicates what results should be returned. Typically it will also provide a “from” clause to declare some variables, and a “where” clause to state conditions over those variables. For more information on the structure of query files (including links to useful topics in the `QL language handbook <https://help.semmle.com/QL/ql-handbook/index.html>`__), see `Introduction to query files <https://help.semmle.com/QL/learn-ql/ql/writing-queries/introduction-to-queries.html>`__.
In our example here, the first line of the query imports the `C/C++ standard QL library <https://help.semmle.com/qldoc/cpp/>`__, which defines concepts like “IfStmt” and “Block”.
The query proper starts by declaring two variables–ifStmt and block. These variables represent sets of values in the database, according to the type of each of the variables. For example, ifStmt has the type IfStmt, which means it represents the set of all if statements in the program.
If we simply selected these two variables::
from IfStmt ifStmt, Block block
select ifStmt, block
We would get a result row for every combination of blocks and if statements in the program. This is known as a cross-product, because there is no logical condition linking the two variables. We can use the where clause to specify the condition that we are only interested in rows where the “block” is the “then” part of the if statement. We do this by specifying::
block = ifStmt.getThen()
This states that the block is equal to (not assigned!) the “then” part of the ``ifStmt``. ``getThen()`` is an operation which is available on any IfStmt. One way to interpret this is as a filtering operation – starting with every pair of block and if statements, check each one to whether the logical condition holds, and only keep the row if that is the case.
We can add a second condition that specifies the block must be empty::
and block.isEmpty()
The ``isEmpty()`` operation is available on any Block, and is only true if the “block” has no children.
Finally, we select a location, at which to report the problem, and a message, to explain what the problem is.
Structure of a QL query
=======================
A **query file** has the extension ``.ql`` and contains a **query clause**, and optionally **predicates**, **classes**, and **modules**.
A **query library** has the extension ``.qll`` and does not contain a query clause, but may contain modules, classes, and predicates.
Each query library also implicitly defines a module.
**Import** statements allow the classes and predicates defined in one module to be used in another.
.. note::
QL queries are always contained in query files with the file extension “.ql”. `Quick queries <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/quick-query.html>`__, run in `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/home-page.html>`__, are no exception: the quick query window maintains a temporary QL file in the background.
Parts of queries can be lifted into `QL library files <https://help.semmle.com/QL/ql-handbook/modules.html#library-modules>`__ with the extension “.qll”. Definitions within such libraries can be brought into scope using “import” statements, and similarly QLL files can import each others definitions using “import” statements.
Logic can be encapsulated as user-defined `predicates <https://help.semmle.com/QL/ql-handbook/predicates.html>`__ and `classes <https://help.semmle.com/QL/ql-handbook/types.html#classes>`__, and organized into `modules <https://help.semmle.com/QL/ql-handbook/modules.html>`__. Each QLL file implicitly defines a module, but QL and QLL files can also contain explicit module definitions, as we will see later.
Predicates in QL
================
A predicate allows you to pull out and name parts of a query.
.. container:: column-left
.. literalinclude:: code-snippets/empty-if-cpp.ql
:language: ql
.. container:: column-right
.. literalinclude:: code-snippets/empty-if-cpp-predicate.ql
:language: ql
.. note::
A QL predicate takes zero or more parameters, and its body is a condition on those parameters. The predicate may (or may not) hold. Predicates may also be recursive, simply by referring to themselves (directly or indirectly).
You can imagine a predicate to be a self-contained from-where-select statement, that produces an intermediate relation, or table. In this case, the ``isEmpty`` predicate will be the set of all blocks which are empty.
Classes in QL
=============
A QL class allows you to name a set of values and define (member) predicates on them.
A class has at least one supertype and optionally a **characteristic predicate**; it contains the values that belong to *all* supertypes *and* satisfy the characteristic predicate, if provided.
Member predicates are inherited and can be overidden.
.. code-block:: ql
class EmptyBlock extends Block {
EmptyBlock() {
this.getNumStmt() = 0
}
}
.. note::
`Classes <https://help.semmle.com/QL/ql-handbook/types.html#classes>`__ model sets of values from the database. A class has one or more supertypes, and inherits `member predicates <https://help.semmle.com/QL/ql-handbook/types.html#member-predicates>`__ (methods) from each of them. Each value in a class must be in every supertype, but additional conditions can be stated in a so-called “characteristic predicate”, which looks a bit like a zero-argument constructor.
In the example, declaring a variable “EmptyBlock e” will allow it to range over only those blocks that have zero statements.
Classes in QL continued
=======================
.. container:: column-left
.. literalinclude:: code-snippets/empty-if-cpp-predicate.ql
:language: ql
.. container:: column-right
.. literalinclude:: code-snippets/empty-if-cpp-class.ql
:language: ql
.. note::
As shown in this example, classes behave much like unary predicates, but with ``instanceof`` instead of predicate calls to check membership. Later on, we will see how to define member predicates on classes.
Iterative query refinement
==========================
- Common workflow: Start with a simple query, inspect a few results, refine, repeat.
- For example, empty then branches are not a problem if there is an else.
- Exercise: How can we refine the query to take this into account?
Hints:
- Use member predicate ``IfStmt.getElse()``
- Use ``not exists(...)``
.. note::
QL makes it very easy to experiment with analysis ideas. A common workflow is to start with a simple query (like our “redundant if-statement” example), examine a few results, refine the query based on any patterns that emerge and repeat.
As an exercise, refine the redundant-if query based on the observation that if the if-statement has an “else” clause, then even if the body of the “then” clause is empty, its not actually redundant.
Model answer
============
.. literalinclude:: code-snippets/empty-if-java-model.ql
.. note::
You can explore the results generated when this query is run on exiv2 in LGTM `here <https://lgtm.com/query/4641433299746527262/>`__.
What next?
==========
Try working through the next QL training topic: **Introduction to data flow**.

Просмотреть файл

@ -1,147 +0,0 @@
Oops
====
.. code-block:: csharp
int write(int buf[], int size, int loc, int val) {
if (loc >= size) {
// return -1;
}
buf[loc] = val;
return 0;
}
- The return statement has been commented out (during debugging?)
- The if statement is now dead code
- No bounds checking!
.. note::
Heres a simple (artificial) bug, which well develop a QL query to catch.
This function writes a value to a given location in an array, first trying to do a bounds check to validate that the location is within bounds. However, the return statement has been commented out, leaving a redundant if statement and no bounds checking.
This case can act as our “patient zero” in the variant analysis game.
A simple QL query
=================
.. literalinclude:: code-snippets/empty-if-cpp.ql
:language: ql
.. note::
We are going to write a simple query which finds “if statements” with empty “then” blocks, so we can highlight the results like those on the previous slide. The query can be run in the query console on LGTM, or in your IDE.
A QL query consists of a “select” clause that indicates what results should be returned. Typically it will also provide a “from” clause to declare some variables, and a “where” clause to state conditions over those variables. For more information on the structure of query files (including links to useful topics in the QL language handbook), see Introduction to query files.
In our example here, the first line of the query imports the C/C++ standard QL library, which defines concepts like “IfStmt” and “Block”.
The query proper starts by declaring two variables–ifStmt and block. These variables represent sets of values in the database, according to the type of each of the variables. For example, ifStmt has the type IfStmt, which means it represents the set of all if statements in the program.
If we simply selected these two variables:
from IfStmt ifStmt, Block block
select ifStmt, block
We would get a result row for every combination of blocks and if statements in the program. This is known as a cross-product, because there is no logical condition linking the two variables. We can use the where clause to specify the condition that we are only interested in rows where the “block” is the “then” part of the if statement. We do this by specifying:
block = ifStmt.getThen()
This states that the block is equal to (not assigned!) the “then” part of the ifStmt. `getThen()` is an operation which is available on any IfStmt. One way to interpret this is as a filtering operation – starting with every pair of block and if statements, check each one to whether the logical condition holds, and only keep the row if that is the case.
We can add a second condition that specifies the block must be empty:
and block.isEmpty()
The isEmpty() operation is available on any Block, and is only true if the “block” has no children.
Finally, we select a location, at which to report the problem, and a message, to explain what the problem is.
Structure of a QL query
=======================
A query file has the extension .ql and contains a query clause, and optionally predicates, classes, and modules.
A query library has the extension .qll and does not contain a query clause, but may contain modules, classes, and predicates.
Each query library also implicitly defines a module.
Import statements allow the classes and predicates defined in one module to be used in another.
.. note::
QL queries are always contained in query files with the file extension “.ql”. Quick queries, run in QL for Eclipse, are no exception: the quick query window maintains a temporary QL file in the background.
Parts of queries can be lifted into QL library files with the extension “.qll”. Definitions within such libraries can be brought into scope using “import” statements, and similarly QLL files can import each others definitions using “import” statements.
Logic can be encapsulated as user-defined predicates and classes, and organized into modules. Each QLL file implicitly defines a module, but QL and QLL files can also contain explicit module definitions, as we will see later.
Predicates in QL
================
A predicate allows you to pull out and name parts of a query.
.. container:: column-left
.. literalinclude:: code-snippets/empty-if-cpp.ql
:language: ql
.. container:: column-right
.. literalinclude:: code-snippets/empty-if-cpp-predicate.ql
:language: ql
.. note::
A QL predicate takes zero or more parameters, and its body is a condition on those parameters. The predicate may (or may not) hold. Predicates may also be recursive, simply by referring to themselves (directly or indirectly).
You can imagine a predicate to be a self-contained from-where-select statement, that produces an intermediate relation, or table. In this case, the isEmpty predicate will be the set of all blocks which are empty.
Classes in QL
=============
.. container:: column-left
.. literalinclude:: code-snippets/empty-if-cpp-predicate.ql
:language: ql
.. container:: column-right
.. literalinclude:: code-snippets/empty-if-cpp-class.ql
:language: ql
.. note::
As shown in this example, classes behave much like unary predicates, but with instanceof instead of predicate calls to check membership. Later on, we will see how to define member predicates on classes.
Iterative query refinement
==========================
Common workflow: Start with a simple query, inspect a few results, refine, repeat.
For example, empty then branches are not a problem if there is an else.
Exercise: How can we refine the query to take this into account?
Hints:
- Use member predicate IfStmt.getElse()
- Use not exists(...)
.. note::
QL makes it very easy to experiment with analysis ideas. A common workflow is to start with a simple query (like our “redundant if-statement” example), examine a few results, refine the query based on any patterns that emerge and repeat.
As an exercise, refine the redundant-if query based on the observation that if the if-statement has an “else” clause, then even if the body of the “then” clause is empty, its not actually redundant.
Model answer
============
.. literalinclude:: code-snippets/empty-if-java-model.ql
What next?
==========
Try working through an 'Introduction to dataflow'.

Просмотреть файл

@ -1,64 +1,25 @@
Information
===========
- Pressing 'h' highlights code snippets
- Pressing 'p' toggles speaker notes (if they're on the current slide)
- Pressing 'f' toggles fullscreen viewing
- Pressing 'w' toggles widescreen
- Pressing 'o' toggles overview mode
Getting started
===============
- If you are a completely new to QL, try the `QL detective tutorials <https://help.semmle.com/QL/learn-ql/ql/beginner/ql-tutorials.html>`__.
- To learn more about the main features of QL, try looking at the `QL language handbook <https://help.semmle.com/QL/ql-handbook/>`__.
- For further information about writing queries in QL, see `Writing QL queries <https://help.semmle.com/QL/learn-ql/ql/writing-queries/writing-queries.html>`__.
.. rst-class:: agenda-slide
Setup
=====
.. container:: set-up
Download:
- `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/install-plugin-free.html>`__
- Snapshot: `exiv2 <https://www.google.com/url?q=http://downloads.lgtm.com/snapshots/cpp/exiv2/Exiv2_exiv2_b090f4d.zip&sa=D&ust=1558103276046000& usg=AFQjCNFOJMgAMNChZHpMO9QEY62W-mYI1Q>`__
.. note::
To run the queries featured in this training presentation, we recommend you download the free-to-use `QL for Eclipse plugin <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/getting-started.html>`__.
This plugin allows you to locally access the latest features of QL, including the standard QL libraries and queries. It also provides standard IDE features such as syntax highlighting, jump-to-definition, and tab completion.
A good project to start analyzing is `exiv2 <https://github.com/Exiv2/exiv2>`__–a suitable snapshot to query is available by visiting the link on the slide.
Alternatively, you can query any project (including exiv2) in `the query console <https://lgtm.com/query/project:1506532406873/lang:cpp/>`__ on LGTM.com.
Note that results generated in the query console are likely to differ to those generated in the QL plugin as LGTM.com analyzes the most recent revisions of each project that has been added–the snapshot available to download above is based on an historical version of the code base.
A few years ago, somewhere between Earth and Mars...
====================================================
.. image:: ../_static-training/curiosity.png
:scale: 50 %
Start with a problem...
=======================
Crashing bug found in Curiositys landing module through routine testing.
Patching is still possible mid-flight, but what if there are more such issues?
.. image:: ../_static-training/curiosity2.png
:scale: 50 %
.. container:: image-box
.. image:: ../_static-training/curiosity.png
.. note::
When the Curiosity Rover was on its way to Mars in 2012, a flight software developer at NASA JPL discovered a mission-critical bug through manual code review. The problem occurred in Curiositys Entry, Descent and Landing software–the software responsible for the Rovers descent through the Martian atmosphere and landing it safely on the surface. of Mars.
When the Curiosity Rover was on its way to Mars in 2012, a flight software developer at NASA JPL discovered a mission-critical bug through manual code review. The problem occurred in Curiositys Entry, Descent, and Landing software–the software responsible for the Rovers descent through the Martian atmosphere and landing it safely on the surface. of Mars.
The bug, which had gone undetected by traditional solutions, was likely to prevent the capsules parachutes from opening, resulting in the Rover crashing onto the red planets rocky surface.
Zoom in on the code
===================
(For illustration only, not actually NASA code!)
.. code-block:: cpp
void fire_thrusters(double vectors[12]) {
@ -83,10 +44,13 @@ Zoom in on the code
However, theres no sanity checking, and a developer might call it with an array thats too short, holding direction information for only one of the thrusters.
The function will then read past the end of the array, and unpredictable results occur.
Write a query...
================
...to find all instances of the problem.
Complete text of the analysis (nothing left out!):
.. code-block:: ql
import cpp
@ -110,15 +74,16 @@ Write a query...
Find all instances!
===================
.. image:: ../_static-training/curiosity2.png
:scale: 50 %
- When applied to the code, the query found the original bug and around 30 others.
- Three of those were in the same entry, descent and landing module.
When applied to the code, the query found the original bug and around 30 others.
- All were fixed with a mid-flight patch.
Three of those were in the same entry, descent and landing module.
.. container:: image-box
All were fixed with a mid-flight patch.
.. image:: ../_static-training/curiosity2.png
.. note::
@ -130,23 +95,19 @@ All were fixed with a mid-flight patch.
.. rst-class:: background2
.. rst-class:: myclass
How it all works
================
Analysis overview
=================
.. image:: ../_static-training/analysis-overview.png
:scale: 75 %
- The database schema is (source) language specific, as are queries and libraries.
- Multi-language code bases are analyzed one language at a time.
.. container:: image-box
.. image:: ../_static-training/analysis-overview.png
.. note::

Просмотреть файл

@ -1,9 +1,215 @@
.. Make language-specific slideshow by including the relevant bits and pieces from the
.. intro-to-ql folder
Introduction to QL for Java
===========================
Introduction to variant analysis for Java
=========================================
Information
===========
- Pressing ``p`` toggles extra notes (if they're on the current slide)
- Pressing ``f`` toggles full screen viewing
- Pressing ``o`` toggles overview mode
Getting started and setting up
==============================
To try the examples in this presentation you should download:
- `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/install-plugin-free.html>`__
- Snapshot: `Apache Struts <https://downloads.lgtm.com/snapshots/java/apache/struts/apache-struts-7fd1622-CVE-2018-11776.zip>`__
More resources:
- If you are completely new to QL, try the `QL detective tutorials <https://help.semmle.com/QL/learn-ql/ql/beginner/ql-tutorials.html>`__.
- To learn more about the main features of QL, try looking at the `QL language handbook <https://help.semmle.com/QL/ql-handbook/>`__.
- For further information about writing queries in QL, see `Writing QL queries <https://help.semmle.com/QL/learn-ql/ql/writing-queries/writing-queries.html>`__.
.. note::
To run the queries featured in this training presentation, we recommend you download the free-to-use `QL for Eclipse plugin <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/getting-started.html>`__.
This plugin allows you to locally access the latest features of QL, including the standard QL libraries and queries. It also provides standard IDE features such as syntax highlighting, jump-to-definition, and tab completion.
A good project to start analyzing is `Apache Struts <https://github.com/apache/struts>`__–a suitable snapshot to query is available by visiting the link on the slide.
Alternatively, you can query any project (including Apache Struts) in `the query console <https://lgtm.com/query/project:1878521151/lang:java/>`__ on LGTM.com.
Note that results generated in the query console are likely to differ to those generated in the QL plugin as LGTM.com analyzes the most recent revisions of each project that has been added–the snapshot available to download above is based on an historical version of the code base.
.. Include language-agnostic section here
.. include:: intro-ql-general.rst
.. include:: intro-java-specific.rst
Oops
====
.. code-block:: java
int write(int[] buf, int size, int loc, int val) {
if (loc >= size) {
// return -1;
}
buf[loc] = val;
return 0;
}
- The return statement has been commented out (during debugging?)
- The if statement is now dead code
- No explicit bounds checking, will throw ``ArrayIndexOutOfbounds``
.. note::
Heres a simple (artificial) bug, which well develop a QL query to catch.
This function writes a value to a given location in an array, first trying to do a bounds check to validate that the location is within bounds. However, the return statement has been commented out, leaving a redundant if statement and no bounds checking.
This case can act as our “patient zero” in the variant analysis game.
A simple QL query
=================
.. literalinclude:: code-snippets/empty-if-java.ql
:language: ql
.. note::
We are going to write a simple query which finds “if statements” with empty “then” blocks, so we can highlight the results like those on the previous slide. The query can be run in the `query console on LGTM <https://lgtm.com/query>`__, or in your `IDE <https://lgtm.com/help/lgtm/running-queries-ide>`__.
A `QL query <https://help.semmle.com/QL/ql-handbook/queries.html>`__ consists of a “select” clause that indicates what results should be returned. Typically it will also provide a “from” clause to declare some variables, and a “where” clause to state conditions over those variables. For more information on the structure of query files (including links to useful topics in the `QL language handbook <https://help.semmle.com/QL/ql-handbook/index.html>`__), see `Introduction to query files <https://help.semmle.com/QL/learn-ql/ql/writing-queries/introduction-to-queries.html>`__.
In our example here, the first line of the query imports the `Java standard QL library <https://help.semmle.com/qldoc/java/>`__, which defines concepts like “IfStmt” and “Block”.
The query proper starts by declaring two variables–ifStmt and block. These variables represent sets of values in the database, according to the type of each of the variables. For example, ifStmt has the type IfStmt, which means it represents the set of all if statements in the program.
If we simply selected these two variables::
from IfStmt ifStmt, Block block
select ifStmt, block
We would get a result row for every combination of blocks and if statements in the program. This is known as a cross-product, because there is no logical condition linking the two variables. We can use the where clause to specify the condition that we are only interested in rows where the “block” is the “then” part of the if statement. We do this by specifying::
block = ifStmt.getThen()
This states that the block is equal to (not assigned!) the “then” part of the ``ifStmt``. ``getThen()`` is an operation which is available on any IfStmt. One way to interpret this is as a filtering operation – starting with every pair of block and if statements, check each one to whether the logical condition holds, and only keep the row if that is the case.
We can add a second condition that specifies the block must be empty::
and block.isEmpty()
The ``isEmpty()`` operation is available on any Block, and is only true if the “block” has no children.
Finally, we select a location, at which to report the problem, and a message, to explain what the problem is.
Structure of a QL query
=======================
A **query file** has the extension ``.ql`` and contains a **query clause**, and optionally **predicates**, **classes**, and **modules**.
A **query library** has the extension ``.qll`` and does not contain a query clause, but may contain modules, classes, and predicates.
Each query library also implicitly defines a module.
**Import** statements allow the classes and predicates defined in one module to be used in another.
.. note::
QL queries are always contained in query files with the file extension “.ql”. `Quick queries <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/quick-query.html>`__, run in `QL for Eclipse <https://help.semmle.com/ql-for-eclipse/Content/WebHelp/home-page.html>`__, are no exception: the quick query window maintains a temporary QL file in the background.
Parts of queries can be lifted into `QL library files <https://help.semmle.com/QL/ql-handbook/modules.html#library-modules>`__ with the extension “.qll”. Definitions within such libraries can be brought into scope using “import” statements, and similarly QLL files can import each others definitions using “import” statements.
Logic can be encapsulated as user-defined `predicates <https://help.semmle.com/QL/ql-handbook/predicates.html>`__ and `classes <https://help.semmle.com/QL/ql-handbook/types.html#classes>`__, and organized into `modules <https://help.semmle.com/QL/ql-handbook/modules.html>`__. Each QLL file implicitly defines a module, but QL and QLL files can also contain explicit module definitions, as we will see later.
Predicates in QL
================
A predicate allows you to pull out and name parts of a query.
.. container:: column-left
.. literalinclude:: code-snippets/empty-if-java.ql
:language: ql
.. container:: column-right
.. literalinclude:: code-snippets/empty-if-java-predicate.ql
:language: ql
.. note::
A `QL predicate <https://help.semmle.com/QL/ql-handbook/predicates.html>`__ takes zero or more parameters, and its body is a condition on those parameters. The predicate may (or may not) hold. Predicates may also be `recursive <https://help.semmle.com/QL/ql-handbook/predicates.html#recursive-predicates>`__, simply by referring to themselves (directly or indirectly).
You can imagine a predicate to be a self-contained from-where-select statement, that produces an intermediate relation, or table. In this case, the isEmpty predicate will be the set of all blocks which are empty.
Classes in QL
=============
A QL class allows you to name a set of values and define (member) predicates on them.
A class has at least one supertype and optionally a **characteristic predicate**; it contains the values that belong to *all* supertypes *and* satisfy the characteristic predicate, if provided.
Member predicates are inherited and can be overidden.
.. code-block:: ql
class EmptyBlock extends Block {
EmptyBlock() {
this.getNumStmt() = 0
}
}
.. note::
`Classes <https://help.semmle.com/QL/ql-handbook/types.html#classes>`__ model sets of values from the database. A class has one or more supertypes, and inherits `member predicates <https://help.semmle.com/QL/ql-handbook/types.html#member-predicates>`__ (methods) from each of them. Each value in a class must be in every supertype, but additional conditions can be stated in a so-called “characteristic predicate”, which looks a bit like a zero-argument constructor.
In the example, declaring a variable “EmptyBlock e” will allow it to range over only those blocks that have zero statements.
Classes in QL continued
=======================
.. container:: column-left
.. literalinclude:: code-snippets/empty-if-java-predicate.ql
:language: ql
.. container:: column-right
.. literalinclude:: code-snippets/empty-if-java-class.ql
:language: ql
.. note::
As shown in this example, classes behave much like unary predicates, but with ``instanceof`` instead of predicate calls to check membership. Later on, we will see how to define member predicates on classes.
Iterative query refinement
==========================
- Common workflow: Start with a simple query, inspect a few results, refine, repeat.
- For example, empty then branches are not a problem if there is an else.
- Exercise: How can we refine the query to take this into account?
Hints:
- Use member predicate ``IfStmt.getElse()``
- Use ``not exists(...)``
.. note::
QL makes it very easy to experiment with analysis ideas. A common workflow is to start with a simple query (like our “redundant if-statement” example), examine a few results, refine the query based on any patterns that emerge and repeat.
As an exercise, refine the redundant-if query based on the observation that if the if-statement has an “else” clause, then even if the body of the “then” clause is empty, its not actually redundant.
Model answer
============
.. literalinclude:: code-snippets/empty-if-java-model.ql
.. note::
You can explore the results generated when this query is run on apache/struts in LGTM `here <https://lgtm.com/query/1269550358355690774/>`__.
What next?
==========
Try working through the next QL training topic: **Introduction to data flow**.