軟體測試 靜態分析 設計規範 -...
TRANSCRIPT
-
1
軟體測試靜態分析_設計規範
郭忠義
臺北科技大學資訊工程系
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
Buffer Overflow Stack overflow Array index error Format string bugs
2
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
Stack overflow 在程式執行時,電腦中的記憶體配置
global:存放全域變數與靜態變數 stack:存放區域變數、函數參數、return address
int a char arr[10]
heap:程式執行期間動態產生的變數 C:malloc、free C++:new、delete
3
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
Stack overflow 當一個函數被呼叫時,則會將其位置放入堆疊
當輸入或是複製的資料超出配置的stack大小,即導致stack overflow
4
Unallocated
Stack for b()
Stack for a()
Stack for Main()
main(void){ …a();… }a(){ …b();… }b(){ ……. }
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
Stack Overflow攻擊(1)
5
印出foo和boo的位址
檢查username和password是否正確
主程式中無呼叫hacker之指令,若能使hacker內容顯現則可表示攻擊成功
-
Stack Overflow攻擊(2)
Data of check_user()
Caller function
Return address of check_user()
Data of main()
Caller function
Return address of main()
……
……6
呼叫
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
如何預防Stack Overflow(1) 避免使用不對範圍進行檢查的函式
strcpy => strncpy Strcpy (目的字串,來源字串) strncpy (目的字串,來源字串,複製長度)
sprintf => snprintf strcat => strncat gets => fgets scanf => sscanf
sscanf(buf, “%s”, input) => sscanf(buf, “%19s”, input);
針對輸入輸出進行範圍檢查7
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
如何預防Stack Overflow(2)
8
此段程式碼可確保使用者輸入字串過長也不會覆蓋到宣告以外的區塊。
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
Array Indexing Error(1) 在C語言的程式中,string就是char陣列 陣列使用時,易被攻擊的典型情況
可令使用者改變或決定陣列索引值
可以建立任意大小的陣列
9
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
Array Indexing Error(2)
10
此程式可讓指定陣列元素,並改變其內容主程式中無呼叫bar之指令,若能使
bar內容顯現則可表示攻擊成功
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
Array Indexing Error(3)
11
以32位元電腦架構計算,可得以下資訊 bar函數的起始位置: 0040100016 = 419840010 IntVector起始位置: 0051004816 欲覆蓋的位置(return address所在位置): 0012FF8416
對於32-bits的作業系統而言,記憶體位址0012FF8416 = 10012FF8416
計算index應為多少才可覆蓋到return address 10012FF8416 = 0051004816 + index*4 index = 3FF07FCF16 = 10727596710
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
Array Indexing Error(4) 重新以1072725967 4198400執行ArrayIndexError.exe,即可
完成攻擊。
12
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
仍可產生可執行檔,且可執行
是一種隱性的錯誤
雖非語法錯誤,但執行期間可能發生無法預期的行為
1 void printSomething() {2 int i;3 int * target = null;45 for(i = 0; i < size; i++) {6 printf(“i = %d”, i);7 }89 printf(“%d”, *target);10 }
13
未解的警告
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
若程式在執行過程中使用大量的 malloc,而沒有使用 free ,會使記憶體耗盡
1 #define SIZE 1002 int main() {3 int i=0, result = 0;4 int *array;5 array = (int*) malloc(sizeof(int)*SIZE);6 // Assign value to the array7 for(i = 0; i < size; i++) {8 array[i] = i;9 }1011 for(i = 0; i < size; i++) {12 result += array[i];13 }14 }
Memory Leak
14
動態配置記憶體重新配置或回收
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
行數大於 80 行,無法完整顯示於一個畫面 難理解,需經常捲動畫面了解上下文
難以重複利用、難以維護、難有合適的函式名稱
一個函式做太多事,須將這種情況妥善分工。
15
長函式
1 void 班長() {2 辦班遊
22 規劃行程
42 收錢
62 維持秩序
82 }
1 void 風紀() {2 維持秩序3 … 4 }5 void 總務() {6 收錢7 …8 }9 void 康樂() {10 規劃行程11 …12 }
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
太過複雜的模組,可能使該模組與其他模組間產生不必要的耦合性(Coupling) 應將過於龐大的模組拆解成數個小模組
16
模組太過複雜須重構
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
一段重複的程式碼在一個或多個副程式中出現。
重複的程式碼應抽出改寫成副程式讓其他程式共享。
1 int function001(int scores[], int size){2 …12 int i, sum, average = 0;13 for (i = 0; i < size; i++) {14 sum += scores[i];15 }16 average = sum / size;17 return average;18 …30 }
1 int function002(int scores[], int size) {2 …12 int i, sum, average = 0;13 for (i = 0; i < size; i++) {14 sum += scores[i];15 }16 average = sum / size;17 return average;18 …30 }
17
重複程式碼
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
函式未加適當回傳值,無法得知副程式執行是否正常
18
1 int doJob() {2 char filePath;3 cin >> filePath;4 openAndProcessFile(filePath);5 // more processing with the file
….
此處假設開啟檔案從不會失敗,如此是否可能?
1 bool openAndProcessFile(char filePath) {2 ifstream ifs;3 ifs.open(filePath.c_str());4 if (!ifs.is_open())5 return false;
…10 return true;11 }
若檔案開啟失敗,回傳false
1 int main() {2 char filePath;3 cin >> filePath;4 bool isFileOpenedAndProcessed;5 isFileOpenedAndProcessed =6 openAndProcessFile(filePath);7 if(isFIleOpenedAndProcessed) {8 … // do something9 } else {10 … // error handling code
}} 檢查檔案開啟是否成功
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
良好的註解可提高可讀性
註解撰寫時機:複雜的演算法、輔助設計與思考
19
缺乏註解
1 RSSIMapCollection(List _stabilizes) {2 // Initialize a selection property for multiple stabilizations3 _stabilizes.addElement(Stabilize.NONE);4 _stabilizes.addElement(Stabilize.THRESHOLD);5 _stabilizes.addElement(Stabilize.AVERAGE);6 _stabilizes.addElement(Stabilize.WIEGHTED);7 _stabilizes.setSelectedItem(Stabilize.THRESHOLD);8 }
1 RSSIMapCollection(List _stabilizes) {23 _stabilizes.addElement(Stabilize.NONE);4 _stabilizes.addElement(Stabilize.THRESHOLD);5 _stabilizes.addElement(Stabilize.AVERAGE);6 _stabilizes.addElement(Stabilize.WIEGHTED);7 _stabilizes.setSelectedItem(Stabilize.THRESHOLD);8 }
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
函式須適當存取限制
函式沒加上適當存取限制,其他函式可無限制存取應保護的資料。
應根據設計原則,如資訊隱藏,設計函式。
20
1 int f(int x) {2 int r=0;34 r= sqrt(x);5 …
};
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
好的命名令人易讀易懂
Function name, local variable, parameter name
1 int main T() {2 boolean b = false;34 int xyz(int x, int y, int z) {5 int r = 0;6 r = (x + y) * z / 2;7 return r;8 }9 }
1 int main() {2 boolean isIsosceles = false;34 int calculateArea(int top, int bottom, int height) {5 int area = 0;6 area = (top + bottom) * height / 2;7 return area;8 }9 }
21
不適當的命名
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
迴圈的設計步驟,避免無法跳出,或不知何時跳出
設定初始條件
執行過程中,逐步修改初始條件
謹慎定義結束條件
1 for(int i = 1; (i % 2) ? ((i + 100) < 200) : ((i* 30) < 50); i++) {2 Do something3 }45 for(int i = 0; i
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
適當初始化變數
迴圈下標或條件值無適當初始化。
迴圈下標或條件值應適當地初始化。
23
1 int i;2 while (i
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
適當初始化變數
• Not good:
• Better solution:
1 int workHours, hourlyWage;2 int salary = workHours * hourlyWage;
1 int workHours = 40, hourlyWage = 120;2 int salary = workHours * hourlyWage;
24
寫程式總會宣告變數,每個變數都需正確初始化。
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
適當指定變數型態或轉型
強制轉型(Casting)是危險的語言構件 除非清楚欲轉換的型別,否則應盡量避免使用
因變數型態不一致,可能造成無法預期的執行結果
1 void testType() {2 unsigned short x = 65535;3 short y = x;45 for(int i = 0; i < y; i++) {6 Do something7 }8 }
25
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
增加可讀性、避免邏輯上的錯誤
1 int trapezoidArea(int top, int bottom, int height) {2 int area = top + bottom * height / 2;3 if (isOK && getX() * getY() == 2000 && !isFinished) {4 Do something return area;5 }6 return area;7 }
1 int trapezoidArea(int top, int bottom, int height) {2 int area = (top + bottom) * height / 2;3 if ((isOK) && (getX() * getY() == 2000) && (!isFinished)) {4 Do something5 }6 return area;7 }
26
適當運用括號
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
臃腫的畫面
View除呈現畫面功能的程式碼外,還含有其他程式碼,如Business Logic,失去簡單性。
27
// codes that create menus, buttons, and connects signals to slots (omitted)void MainWindown() {
// 開啟對話窗讓使用者輸入檔案路徑,讀取文字檔ead the text… while (ch!=EOF) { if (strcmp(line, “//ROOTNODE”)==0) {… // more business logic
}
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
存取檔案前確認檔案開啟
• 開啟檔案後沒有測試檔案是否正確載入就進行操作。
1 // include necessary header files.2 int main () {3 FILE * in;4 char input;5 in =fopen(“MyText.txt”, ”r”);6 do{ 7 fread(&input, sizeof(char), 1, in);8 … // process read‐in data9 }10 fclose(in);11 }
1 // include necessary header files.2 int main () {3 FILE *in;4 char input;5 in =fopen(“MyText.txt”, ”r”);6 if (in!=NULL) { 7 do {8 fread(&input, sizeof(char), 1, in);9 … // process read‐in data10 }11 } else {12 … // error-handling code13 }14 }
28
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
函式存在多餘變數,始終都沒有被存取及使用。 刪除函式中未曾使用過的變數。
1 int calculateClassAverage (int scores[], int size) {2 int rank = 0; // never used3 int i, sum, average = 0;4 for (i = 0; i < scores; i++) {5 sum += scores[i];6 } 7 return average;8 }
29
多餘變數
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
• 計算時沒有檢查是否會發生overflow或underflow– 計算應該檢查是否會發生overflow或underflow
1 int main () {2 short int addend = 30000; 3 short int augend = 30000;4 short sum = addend + augend;5 doSomething(sum);6 }
overflow1 int main () {2 short int addend, augend;3 scanf("%d %d“, &addend, &augend);4 if (addend + augend > MAX|| (addend + augend
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
1 int divisor;2 int dividend;3 scanf("%d %d",&divisor, dividend);45 if (divisor == 0) {6 printf(“divisor is 0”);7 }8 int quotient = dividend / divisor;9 …
}
1 int divisor;2 int dividend;3 scanf("%d %d",&divisor, dividend);45 int quotient = dividend / divisor;6 …
}
31
除數為0 除法運算未檢查除數是否為0
除法運算應檢查除數是否為0
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
1 #define SIZE 1002 int main() {3 int i=0;4 int data[SIZE];5 …6 for (i=0; i
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
1 typedef struct customer_s {2 char name[10];3 char title[10];4 char house[10];5 char street[10];6 char city[10];7 char postcode[10]; 8 char country[10];9 } customer_t;
1 typedef struct staff_s {2 char lastname[10];3 char firstname[10];4 char house[10];5 char street[10];6 char city[10];7 char postcode[10]; 8 char country[10];9 } staff_t;
33
資料叢集
常在不同地方成群出現的相同資料項
提出相同資料項,定義自訂資料型態。
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
1 typedef struct customer_s {2 char name[10];3 char title[10];4 address_t customerAddr;5 } customer_t;
1 typedef struct staff_s {2 char lastname[10];3 char firstname[10];4 address_t staffAddr;5 } staff_t;
1 typedef struct address_s {2 char house[10];3 char street[10];4 char city[10];5 char country[10];6 } Address_t;
34
資料叢集
提出相同資料項,定義自訂資料型態
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
• Not good: • Better solution:1 createMember( 2 char name[],3 char country[],4 char postcode[],5 char city[],6 char street[],7 char house[]) {8 …9 }
1 createMember( 2 char name[],3 address_t address) {4 …5 }
35
長參數
使用重構方法將過長的參數包裝成一個「struct 參數」
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
程式碼出現客戶端程式向一個套件函式請求另一個函式,然後在向後者再請求另一個函式。
• Not good:
• Better solution:
36
訊息鏈
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
• Not good:
• Better solution:
1 double potentialEnergy(double mass, double height) {2 return mass * 9.81 * height;3 }
1 double potentialEnergy(double mass, double height) {2 double GRAVITATION = 9.81;3 return mass * GRAVITATION * height;4 }
37
常數定義
應先用const或define關鍵字定義常數,後再使用。
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
1 if(i
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
• Not good: • Better solution:1 switch(weekday) {2 case ‘Monday’:3 printf(“國文課”);break;4 case ‘Tuesday’:5 printf(“英文課”);break;6 case ‘Thursday’:7 printf(“數學課”);break;8 }
1 switch(weekday) {2 case ‘Monday’:3 printf(“國文課”);break;4 case ‘Tuesday’:5 printf(“英文課”);break;6 case ‘Thursday’:7 printf(“數學課”);break;8 default:9 printf(“休息”);break;10 }
39
Switch是否有default 每個 switch-case ,都必須有default 動作。
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
• Better solution:
1 double x = 1e‐10, y1 = 20e‐10, y2 = 19e‐10;2 double y = y1 – y2;3 if(x == y) {4 printf(“X == Y”);//並不會成立5 }
1 double x = 1e‐10, y1 = 20e‐10, y2 = 19e‐10;2 double y = y1 – y2;3 if(fabs(x – y)
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
• Not good:
• Better solution:
1 // 計算一年獲利, 傳入參數(int amount)2 void countProfit(int amount, double rate) {3 _profit = amount * ( 1 + rate );4 }
1 // 計算一年獲利, 傳入參數(int amount, double rate)2 void countProfit(int amount, double rate) {3 _profit = amount * ( 1 + rate );4 }
41
註解和程式碼須一致
-
CODING STANDARD EXAMPLES
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
在下列位置加上空白
左大括號前加上空白
函式若有兩個以上參數,於逗號後加上空白
1 void encode(WIMAXBurst burst) {2 }34 void connect(char host, int port) {}5
43
空白 1
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
1 while (…) {}2 void connect ( int host[], int port ) {}4 WIMAXPDU pud = (WIMAXPDU) pdus.get(index);
以下情況不加空白
for, while, do, switch 關鍵字與左括號之間 函式的第一個參數與左括號之間
函式的最後一個參數與右括號之間
函式名稱與左括號之間
轉型(Type casting)宣告與變數之間
1 while(…) {}23 abstract void connect(char host, int port) {}45 WIMAXPDU pud = (WIMAXPDU)pdus.get(index);
44
空白 2
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
適時的空行有助於了解程式的組織
過多或不當的空行反而會造成凌亂
假設以下情況會加入一行空行
function 主體 for, while, if, switch 等迴圈控制 一段有組織且有意義的程式碼
45
空白列
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義46
縮排
假設以下情況會加入縮排與換行
左大括號不換行
右大括號換行,且與左大括號所在之行對齊
程式碼依內容階層深度縮排
case, default 關鍵字與 switch 對齊 break 關鍵字與內容縮排
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
區塊註解(/**…/)用途 檔案說明
函式介面說明
類別說明
除上述用途外,其餘使用單行註解
獨自使用一行
不加在Statement的分號之後
47
註解
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
每個檔案起始須包含一個註解區塊,說明檔名及授權。
1 /* MPEGTSManager.h2 *3 * Copyright (C) 2010 Software Development Research Center,4 * National Taipei University of Technology.5 * All rights reserved.6 *7 * This file is a part of NTUT DVB-H. NTUT DVB-H is free software: you
can8 * redistribute it and/or modify it under the terms of the GNU General 9 * License.10 * …20 */
48
區塊註解-檔案說明
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
1 /** Connect to the remote host. This function may throw2 * UnkownHostException, if the remote client specified by the host3 * is unable to resolved by DNS protocol.4 *5 * @param host the host name6 * @param port the TCP/UDP port number7 * @return error code; return 0 when successful8 */9 int connect(char host, int port) { }10 …
49
區塊註解-函式介面說明 包含函式名稱、參數用途及回傳變數說明。
介面說明以『/** 』起始,中間內容每行都以『*』開始,最後單獨一行『*/』結束。
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義50
命名規則-通用規則 為增進程式可讀性及可維護性,在coding standard中訂定明
確的程式命名規則相當重要
列舉(enum)名稱首字母大寫,若由多個單字組成,每個單字的第一個字母大寫。
若使用專有名詞縮寫,則全部大寫。
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
1 struct VariableExample2 {2 int iMember;3 int vector[20];4 }
1 struct VariableExample2 {2 int Member;3 int vectors[20];4 }
51
命名規則-變數 變數名稱不加形態(type)縮寫 Array、list等容器,名稱結尾加s表示複數,存取其中的元
素時,元素名稱不加s以示區別
-
軟體工程課程
國立臺北科技大學資訊工程系郭忠義
1 void CountTotal() {…}2 void transferDataToDB() {…}3 void TotalCount() {…}
1 void countTotal() {…}2 void transferDatatoDB() {…}3 void countTotal() {…}
52
命名規則-函式 函式命名一律小寫開始,從第二個單字開始,除介系詞(in
、to等)外,每個單字的第一個字母大寫。 每個函式表示一種操作,一律使用動詞作為第一個單字。