Basic syntax of CodeQL notes (2)


Preface

      Learn to use CodeQL for code auditing. Basic Grammar includes concepts and examples. This article is part of queries and classes.


1. Inquiry

     The query is the result output after the entire QL language is run. There are two query types:

  • The first is that the select query clause is defined in the module
  • Query predicates, which means we can define them in the current module or import them from other modules

1.select query clause

     1) The select clause format is as follows (usually at the end of the file), where the from and where statement parts are optional. We can define variables in from, assign values ​​to variables and filter query results in where, and finally display the results in select.

from /* ... variable declarations ... */
where /* ... logical formula ... */
select /* ... expressions ... */

     2) Some keywords can also be used in the select statement:

  • as keyword, followed by a name. The function is similar to as in SQL. It provides a "label" for the result column and allows them to be used in subsequent select expressions.
  • The order by keyword is followed by the result column names one by one. The function is equivalent to order by in SQL, which is used to sort the results, and the asc (ascending order) or desc (descending order) keyword can be optional after the result column name.

     3) The official example is as follows. The first picture results return the results of the select clause query, and the second picture adds a sorting

from int x, int y
where x = 3 and y in [0 .. 2]
select x, y, x * y as product, "product: " + product

Insert image description here
Insert image description here

2. Query predicate

     1) The query predicate is a non-member predicate, and query is used as an annotation at the beginning. It returns all tuples of the predicate evaluation results. Here is an official example:

query int getProduct(int x, int y) {
    
    
  x = 3 and
  y in [0 .. 2] and
  result = x * y
}

Insert image description here
     2) The advantage of writing query predicates over writing select clauses is that you can call the predicates in other parts of the code. For example, we can call getProduct in the class:

query int getProduct(int x, int y) {
    
    
  x = 3 and
  y in [0 .. 2] and
  result = x * y
}
class MultipleOfThree extends int {
    
    
  MultipleOfThree() {
    
     this = getProduct(_, _) }
}

from MultipleOfThree m  
select m

     3) In this way, our query results will have two, one is the built-in #select, and the other is getProduct
Insert image description here
Insert image description here
     4) In contrast to the two, the select clause is like an anonymous predicate, and you cannot call it later. Adding query comments to predicates is also helpful when debugging your code. This way you can explicitly see the set of tuples that the predicate evaluates to.

2. Type

1 Overview

     QL is a statically typed language, so every variable must have a declared type. In QL a type is a set of values. For example, type int is a set of integers. Values ​​can belong to multiple collections, which means that a value can have multiple types. Types in QL include primitive types, classes, character types, field-like types, algebraic data types, type unions, and database types.

2. Primitive type

     These types are built into QL and are always available in the global namespace, regardless of the database we are querying.

  • boolean: This type contains the values ​​true and false.
  • float: This type contains 64-bit floating point numbers, such as 6.28 and -0.618.
  • int: This type contains 32-bit two's complement integers, such as -1 and 42.
  • string: This type contains a limited string of 16 characters.
  • date: This type contains a date (and optionally a time).

3. Classes

     1) We can define our own types in CodeQL, and one method defines a class.
     2) Classes provide an easy way to reuse and structure code, for example, you can group related values ​​together, define member predicates on those values, and define subclasses to override member predicates.
     3) A class in QL does not "create" a new object, it just represents a logical property. A value belongs to a specific class if it satisfies this logical property.
     4) Define a class that requires the following parameters:

  • class keyword
  • The name of the class. This is an identifier starting with a capital letter
  • The supertype of a class derived from classes via extends and / or instanceof
  • The body of the class, enclosed in curly braces

     5) Official case:

class OneTwoThree extends int {
    
    
  OneTwoThree() {
    
     // characteristic predicate
    this = 1 or this = 2 or this = 3
  }

  string getAString() {
    
     // member predicate
    result = "One, two or three: " + this.toString()
  }

  predicate isEven() {
    
     // member predicate
    this = 2
  }
}

     6) In CodeQL, classes allow multiple inheritance, but the following operations are illegal:

  • cannot inherit itself
  • Cannot inherit final class
  • Incompatible types cannot be inherited, please refer to: https://codeql.github.com/docs/ql-language-reference/annotations/#annotations-overview

4. The main body of the class

     1) The body of a class can contain the following:

  • Declaration of characteristic predicates
  • Any number of member predicate declarations
  • Any number of field declarations

     2) In a class, we can use this to refer to the class itself. When we define a class, the class also inherits all non-private member predicates and fields from its parent class, which we can override.

5. Feature predicate

     Similar to the constructor of a class in other languages, which can only define one, we can use this in the characteristic predicate to limit the possible values ​​​​in the class. In the above example, OneTwoThree is restricted to integers from 1-3.

6.Member predicate

     These predicates only apply to members of a specific class. We can call member predicates on values.

	(OneTwoThree).getAString()
	// 结果是 One, two or three: 1

7.Field

     Fields are variables declared in the body of a class, and there can be any number of field declarations in the subject of a class. We can apply these variables to predicates in the class. The usage is similar to this. The fields must be restricted to the characteristic predicate. Official case:

class SmallInt extends int {
    
    
  SmallInt() {
    
     this = [1 .. 10] }
}

class DivisibleInt extends SmallInt {
    
    
  SmallInt divisor;   // declaration of the field `divisor`
  DivisibleInt() {
    
     this % divisor = 0 }

  SmallInt getADivisor() {
    
     result = divisor }
}

from DivisibleInt i
select i, i.getADivisor()

     In this case, the SmallInt divisor is declared and a divisor field is defined, constrained in the characteristic predicate, and then used in the declaration of the member predicate getADivisor.
Insert image description here

8. Concrete class

     The above examples are all concrete classes, which are defined by restricting the values ​​in a larger type. The values ​​in a concrete class are also those values ​​in the intersection of supertypes that also satisfy the characteristic predicates of the class.

9.Abstract class

     Abstract classes are defined using the keyword abstract before the keyword class. I believe we have come into contact with abstract concepts in many other languages ​​(such as java). An abstract class can also be called a metaclass, which defines the predicates and fields of its subclasses. The format is as follows:

abstract class SqlExpr extends Expr {
    
    
  ...
}

Guess you like

Origin blog.csdn.net/qq_44029310/article/details/127598097