代碼分析平台CodeQL學習手記(二)
在上一篇文章中,我們為讀者介紹了CodeQL平台相關的基本概念,並演示了如何編寫和運行簡單的QL程序。在本文中,我們開始為讀者介紹一些簡單的數據類型,以便為將來的編程工作打好基礎。
基本數據類型及其內建函數
現在,我們開始學習QL語言中的基本數據類型,包括整型、浮點型、日期型、布爾型以及字元串類型。需要注意的是,對於QL語言來說,其支持的數據類型都帶有相應的內建函數——通俗來說,就是系統已經為我們寫好的函數,我們直接拿來就能用了。舉例來說,如果我們想求一個整數的絕對值,直接調用內建函數abs()即可,例如-6.abs()。更一般地說,調用某種類型的變數的通用形式為:直接在變數後面加上一個點號,然後加上要調用的內建函數即可。同時,我們還可以通過點號將多個函數串聯起來,也就是對變數連續進行多種處理,例如,對於一個整型變數a,先求絕對值,再開平方,我們可以將這個處理過程表示為:a.abs().sqrt()。
讀者可能已經發現,在查詢控制台中,當我們在變數後面輸入點號之後,會自動彈出一個含有該類型的變數所有可能的函數列表,這時,我們可以通過滑鼠點選所需的函數,具體如下所示:
另外,當查詢控制台檢測到潛在的語法錯誤後,它會在代碼行號左邊顯示一個紅色的「x」號,或者在相應的字元下面顯示紅色的波浪線。例如,當我們給一個字元串變數賦予一個整數值,並調用絕對值和開平方的函數時,查詢控制台就會給出相應的提示:
字元串類型
字元串類型的變數用來存放以雙引號開頭和結尾的字元序列,即字元串。例如:
from string s
where s = "hello"
select s
其中,在from語句中,我們定義了一個字元串類型的變數s,然後,我們在where語句中,將字元串」hello」賦值給了變數s,最後,我們在select語句中返回變數s的值。如果在查詢控制台運行上述代碼的話,運行結果將為:
hello
注意,上面的運行結果中,並沒有出現雙引號。這是因為,雙引號是一個特殊字元:字元串通常使用雙引號"..."來表示開始和結束,所以雙引號本身不會顯示出來。讀到這裡,讀者可能會問:如果字元串本身恰好包含一個"字元的話,那該怎麼表示呢?這個時候,就該轉義字元\上場了。具體來說,只要在雙引號前面加上一個反斜杠,雙引號就不再表示字元串的開始或結束位置的指示符,而是表示雙引號自身了,具體如下所示:
from string s
where s = "he\"llo"
select s
現在,上述代碼的運行結果會變為:
he"llo
您可能還會問:如果要顯示錶示轉義字元的反斜杠的話,該怎麼辦呢?很簡單,只要在反斜杠的前面再加上一個反斜杠就行了。下面列出的是常見的轉義字元:
n \" 表示字元"
n \\ 表示字元\
n \n 表示換行符
n \r 表示回車符
n \t 表示製表符
同時,QL語言還為字元串類型提供了許多內置的函數,按照官方的說法,就是內置謂詞,例如charAt()函數,該函數可以接收一個表示字元串下標的整型參數,並返回指定下標處的字元。準確來說,該函數的返回值的類型仍然是字元串類型,只不過只包含單個字元而已。請看下面的示例代碼:
from string s
where s = "hello"
select s.charAt(0)
上述代碼的運行結果為:
h
從上面的結果可以看出,字元串元素的下標是從0開始算起的。此外,字元串類型內置的函數有二十多個,這裡就不一一介紹了,具體可以訪問QL的語言規範(https://help.semmle.com/QL/ql-spec/language.html#built-ins-for-string)。
整型與浮點型
簡單來說,整型變數用於保存整數,如306;而浮點型變數則用於保存浮點數,也就是帶小數位的數,如3.14。例如:
from float x, int y
where x = 3.6 and y = 3
select x.pow(y)
就本例來說,上述代碼實際上就是計算3.6的3次方,運行結果為:
同樣的,整型和浮點型也內建了許多函數,例如,abs()函數等,並且,它們的大部分函數的名稱和作用都是相同的,感興趣的讀者可以參閱QL的語言規範(https://help.semmle.com/QL/ql-spec/language.html#built-ins-for-string)。
日期型
下面,我們編寫一個查詢,來計算從今年十月一到2019年12月18日為止已經過去了多少天了,具體如下圖所示:
運行結果如下所示:
需要注意的是,上面代碼中的"01/10/2019"是一個字元串,而函數toDate()是字元串類型的內置函數,其作用是將指定的字元串轉換為日期值。同樣的,日期型也提供了許多內置的函數,如getMonth()函數可以用來提取日期值中的月份部分,具體如下所示:
運行上述代碼後,提取到的月份如下所示:
對於日期型數據來說,除了上面介紹的daysTo()和getMonth()函數外,還有多種函數可以供我們使用,感興趣的讀者可以參閱QL的語言規範(https://help.semmle.com/QL/ql-spec/language.html#built-ins-for-string)。
布爾型
布爾型變數用來存放布爾值,即false(假)或者 true(真)。為了便於讀者理解,這裡舉例說明:
from boolean b
where b = false
select b.booleanNot()
在上面的代碼中,我們定義了一個布爾型變數b,並將其賦值為false,最後返回對變數b進行邏輯非操作後的值。上述代碼的運行結果為:
true
其中,上面的函數booleanNot()的作用,是執行邏輯非運算,也就是取反:真變假,假變真。這裡邏輯變數b原來的值為假(false),取反後,自然就變成真(true)了。接下來,我們再來看看booleanAnd()函數,它能夠用來實現一個邏輯值與另一個(通過參數傳入的)邏輯值的邏輯與運算:
from boolean b
where b = false
select b.booleanAnd(true)
上述代碼的運行結果為:
false
這是因為,只有當兩個邏輯值都為真時,其邏輯與運算的結果才為真。下面,我們再來看看用於實現邏輯或運算的函數,即booleanOr()。下面,我們舉例說明:
from boolean b
where b = false
select b.booleanOr(true)
與上面的函數相似,它也需要傳入一個邏輯值或表達式作為其參數。上述代碼的運行結果為:
true
對於邏輯或運算來說,只要參加運算的值中有一個為真,那麼,其結果就為真。接下來,我們繼續考察用來實現異或運算的函數,即booleanXor()函數,演示代碼如下所示:
from boolean bwhere b = falseselect b.booleanXor(true)
上述示例代碼的運行結果為:
true
這是因為,對於異或運算來說,只要兩個邏輯值不相等,其結果就為真;否則,其結果為假。最後,我們來看一下將邏輯值轉換為字元串的函數:toString()函數,具體代碼如下所示:
運行結果如下所示:
儘管字面上看,與邏輯值中的假值即false是一樣的,但是,實際上它們是完全不同的兩種數據類型——這裡輸出的值是一個字元串。
小結
在上一篇文章中,我們為讀者介紹了CodeQL平台相關的基本概念,並演示了如何編寫和運行簡單的QL程序。在本文中,我們進一步為讀者介紹了一些基本的數據類型。在下一篇文章中,我們將為讀者詳細與代碼分析緊密相關的一些數據類型。
備註:本系列文章乃本人在學習CodeQL平台過程中所做的筆記,希望能夠對大家有點滴幫助——若果真如此的話,本人將備感榮幸。
參考資料:https://help.semmle.com/