Showing posts with label QA_QE. Show all posts
Showing posts with label QA_QE. Show all posts

Monday, January 4, 2010

檢查 Run Time Memory Error 的工具

更多精彩请到 http://www.139ya.com

檢查 Run Time Memory Error 的工具

目 前市面上有不少專門檢查run time memory error 的工具,例如Purify、Insure++、Bounds Checker 以及Valgrind 等等;其中,Purify、Insure++與Valgrind,是筆者曾經實際使用過的產品;然而,就這三項工具的功能完備性來說,筆者主觀地認為 Purify 是小勝幾籌;再者,就使用者介面的簡易明瞭性來說,筆者也是主觀地較偏好 Purify。因此,後續的章節內容與其範例程式之偵測與說明,都將以 Purify 這項工具為主軸。

Purify 的歷史

Purify 的產品雛形,是由一位名叫 Reed Hastings 的工程師所獨力研發而成。憑藉著Purify 的產品雛形,Reed Hastings 於1991 年在美國加州創立了 Pure Software 公司;創業後的四年之間,公司的年營業額每年皆呈倍數成長,亮麗的表現使得 Pure Software 公司獲得 Morgan Stanley 的青睞,並在 Morgan Stanley 的輔導之下,順利地於1995 年在 NASDAQ 掛牌上市。1997 年,Rational Software 公司以七億五千萬美金併購了 Pure Software 公司;而Rational Software 公司則於2003 年,被IBM 以二十億美金所併購。

Pure Software 的創辦人 ── Reed Hastings,在大學時期的主修科目是數學,並曾經得到系上的 Smyth Prize。他在1983 年大學畢業之後,隨即加入由美國總統 Kennedy 所創立的和平志工隊 (Peace Corps Volunteer),到非洲的 Swaziland 教授兩年的數學課程;之後,他回到校園攻讀 Computer Science,並於1988 年取得 Stanford University 電腦科學系的碩士學位。

Purify 產品目前已被更名為 PurifyPlus,而且也推出了 Linux 平台的版本;本書在範例程式當中所使用的 Purif
yPlus,則是由 IBM 網站上所下載的 trial version。

備註:最近幾年很紅的線上租片公司 Netflix,就是由 Reed Hastings 所創辦的。



Uninitialized Memory Read (UMR)

所 謂「Uninitialized Memory Read」,是指某個變數尚未給定初始值之前(此時的變數內容值很可能是個亂數值),程式就去讀取它的內容值。除了少數的情況之外,UMR 通常不會直接造成 coredump 或 segmentation fault,但它有可能會造成不正確的運算結果,抑或間接地引發後續的 coredump 或 segmentation fault。


The Operation Beyond Array Bounds

不 論何種 data type 的 array,其 array element 的個數都是有限的。第一個 array element 的 starting address,是 array 的 lower bound;而最後一個 array element 的 ending address,則是 array 的 upper bound;因此,對 array 的任何運作,都必須侷限在 lower bound 與 upper bound 的範疇之內,才是合法有效的運作;如果存取的運作超出這個範疇,則程式很可能會因此發生 coredump 或 segmentation fault;因為存的運作(write operation),有可能破壞了其他資料結構的內容值;而取的運作(read operation),則是從錯誤的地方去讀取了某個值,而這個值很可能會造成後續的程式無法順利地運作。

Stack Bound Read/Write (SBR/SBW)

所謂「Stack Bound Read/Write」,是指程式對array object 的存取運作,超越了array object 的有效範疇,而且該 array object 的 storage,是從 stack frame 配置而來。

Array Bound Read/Write (ABR/ABW)

所 謂「Array Bound Read」或「Array Bound Write」,是指程式對 array object 的存取運作,超出其有效的範疇,而且 array object 的 storage,是從 data segment 或 heap area 配置而來。

Null Pointer Read/Write (NPR/NPW)


所謂「Null Pointer Read」或「Null Pointer Write」,是指某個 pointer 指向 NULL,亦即該 pointer 沒有指向任何的 object,但程式卻未能檢測其值是否為 NULL,即逕行透過它來執行存取的運作。

Freeing Mismatched Memory (FMM)

所 謂「Freeing Mismatched Memory」,是指「配置記憶體的函式」與「釋放記憶體的函式」不一致;例如,程式呼叫 calloc 函式,要到了一塊記憶體,使用完之後卻呼叫 delete 去歸還記憶體。當程式帶有 FMM 的錯誤時,是不太容易察覺的;因為 compiler 無法找出 FMM 的錯誤,而且 FMM 的錯誤通常不會直接造成 coredump;此時,PurifyPlus 即可上場救援,透過它來找出 FMM 的錯誤。對於可以取得或釋放記憶體資源的相關函式,PurifyPlus 能夠檢測出兩者是否一致的搭配組合為:

"new" versus "delete"
"new []" versus "delete []"
"malloc" versus "free"
"calloc" versus "free"
"realloc" versus "free"
"XtMalloc" versus "XtFree" (X Windows APIs)

Free Memory Read/Write (FMR/FMW)

所 謂「Free Memory Read」或「Free Memory Write」,是指之前取得的記憶體資源,已經歸還給系統,但因程式的疏失或邏輯上的錯誤,使得某個 pointer 還依然指向該記憶體資源,並陸續地透過該 pointer 對其執行讀取或寫入的運作。

Dangling Pointer 與FMR/FMW

所 謂「Dangling Pointer」,是指某個 pointer 在一開始時,是指向一個活生生的 object,之後這個 object 可能因為衰老而壽終正寢,抑或遭逢意外而不幸身亡,但該 pointer 卻渾然不知,還是繼續對這個已經不存在的 object 執行讀取或寫入的運作,並因此引發FMR 或FMW 的錯誤。

之前所看到的 fmr_fmw.c 程式,由於主要目的是在做示範,故其所犯之錯誤看來是十分愚蠢;但在實際的軟體研發過程中,由dangling pointer 所引發的 FMR 與 FMW,是很有可能發生的。舉例來說,現在一般的軟體架構,大都採取 layered design 的設計;也就是說,有些 software components 是隸屬於底層,假設叫做 kernel layer components,簡稱 kernel layer;而有些則是隸屬於上層,假設叫做 application layer components,簡稱 application layer;當 kernel layer 遇到某個 CreateMyObj event,並因此配置了許多data type 叫做 MyObj 的 objects;之後、application layer 遇到 GetMyObjHdl event,因此application layer 向kernel layer 要求,希望能取得由 kernel layer 所配置的所有資料型態為 MyObj 的object 之address (即handle),並透過 array of pointer 或 pointer pool,在 application layer 記下這些 handles;當 kernel layer 遇到DestroyMyObj event,並因此將所有資料型態為 MyObj 的 objects 歸還給作業系統,但卻在歸還之後,忘了通知 application layer,它已經將所有的 objects 都釋放掉了;此時,application layer 認為它所保持的handles,依然指向實質存在的 objects,但因實際上都已經不存在,所以這些 handles 也就變成了dangling pointers,因此後續的讀或寫之運作,將會引發 FMR 或 FMW 的錯誤。

這種由 layered design 所引起的 dangling pointer,可以透過 callback mechanism 來解決;亦即 application layer 必須向 kernel layer 註冊 DestroyMyObj event 以及 callback function;而 kernel layer 在遇到 DestroyMyObj event 時,一定要透過 callback function 去通知 application layer,讓 application layer 有機會對 array of pointer 或 pointer pool 的內容,執行適當的清除運作。

Free Unallocated Memory (FUM)

所謂「Free Unallocated Memory」,是指程式所指定要歸還的記憶體資源之位址,之前已經被歸還過了,抑或從來就不曾被配置過;因此,該次的歸還運作是多此一舉。

Memory Leak (MLK)

所謂「Memory Leak」,是指程式沒有將記憶體資源做妥善的利用,以致於造成閒置或浪費的情形;而這種情形就如同沒有將水龍頭關緊,使得涓滴的自來水不斷地被浪費掉,因此將之稱為 memory leak。

筆 者將memory leak 的來源分為兩種:一、lost memory block;二、undeallocated memory block。其中,lost memory block 是指程式把某塊記憶體資源給搞丟了;而 undeallocated memory block 則是指程式已經不再使用某塊記憶體資源,但仍然把持著該記憶體資源的使用權利 (有可能是「忘記」或是「不願意」釋放記憶體資源)。

Lost Memory Block

所 謂「Lost Memory Block」,是指原本指向某 2 MB memory block 的 pointer,被程式更動後指向另外一塊 4 MB memory block,導致沒有任何的 pointer 指向之前的 2 MB memory block;此時,這塊 2 MB memory block 就成了被搞丟、被遺忘的記憶體資源。

若以日常生活的例子來比喻 lost memory block,它就像是自己買了一把螺絲起子,但在使用過後,由於沒有保持物歸原處的習慣,用完就隨手丟、隨處放,導致最後忘了螺絲起子放在哪裡,而且怎麼 找就是找不到;通常,在遍尋不可得的情況下,只好到修繕材料店再買一把螺絲起子;但如此一來,就造成了金錢與資源的浪費。

Undeallocated Memory Block

所謂「Undeallocated Memory Block」,是指程式已經不再使用某塊記憶體資源,但仍然把持著該記憶體資源的使用權利,使得這塊記憶體資源持續地處於閒置的狀態,直到 process 結束。

造成 undeallocated memory block 的原因有兩種:一、忘記歸還記憶體資源;二、故意佔著不放。通常,真正的原因是「忘記」,很少有程式故意佔著記憶體資源而不使用。

軟體測試的基本觀念

更多精彩请到 http://www.139ya.com

軟體測試的基本觀念

軟 體測試的議題,一般而言都可寫成專書來做論述,但在此節中,筆者僅就常見的以及本書所觸及的議題來做扼要的講述,並偏重於實作程式時的測試技術,所以沒有 對所有的議題做完整的論述;因此,想對軟體測試議題做通盤瞭解的讀者,則不妨上 amazon 網站鍵入 software testing 做搜尋,相信一定可以找到不少的專書著作。

Black Box Testing versus White Box Testing

在 說明正題之前,我們不妨來看個生活化的案例 ── Black Box Users versusWhite Box Users。什麼是black box users?大部分的人都是 black box users,也就是在購買家電或資訊產品時,只在乎它能完成什麼樣的功能以及如何使用,至於產品本身是如何完成該功能,使用者一點都不在乎;white box users 則是典型的好奇寶寶,這群使用者對於產品是如何完成各項功能,有著非常強烈的好奇心,而為了一窺箇中堂奧,凡是買回來的家電或資訊產品,幾乎都會遭到拆 解,以滿足其內心的好奇渴望。

看完 black box users 與white box users 的說明,相信在讀者的心中,對於什麼是 black box testing 與 white box testing,已經大致有譜了。所謂「Black Box Testing」,是指只知道受測元件的介面與功能等規格(例如它應當執行哪些功能,以及「什麼樣的 input 該得到什麼樣的 output」等等),但完全不瞭解或是完全不在乎受測元件是如何完成這些功能;在這樣的環境與條件下所執行的測試,就是 black box testing。

就「Test Case Design」而言,因為 black box test case 完全不涉及受測元件的內部架構與實作的細節,所以它的可重複使用性很高,而且不需要等到受測元件完成之後才能設計 test case。

所 謂「White Box Testing」,是指根據受測元件的規格、以及其內部的架構、實作的細節與設計意圖(design intention),而所執行的測試。white box testing 的優點是:除了可驗證實作細節的設計意圖之外,亦能操控受測元件的內部機制,使得測試者可以進一步地以更有效率的方式來測試受測元件;例如藉由操控內部的 某些機制,可以更方便地產生某些特殊的 input pattern,或是讓受測元件以更短的時間進入某種狀態等等。

就「Test Case Design」而言,white box test case 必須挑戰內部架構與實作細節的設計意圖,才能極大化其驗證的效果,所以設計 test case 的人最好不要找實作細節的執行者,以避免「當局者迷」所帶來的缺點與盲點;此外,由於 white box test case 與受測元件的內部架構與實作細節之相依程度很高,一旦受測元件改採不同的架構或實作方式,test case 就得重新設計,所以它的可重複使用性很低;最後,相較於 black box test case,white box test case 通常必須等到受測元件完成之後,才能開始設計,所以它在設計的時程上是受制於產品的研發進度。

Static Testing versus Dynamic Testing

所 謂「Static Testing」,顧名思義,就是在受測元件處於靜止的狀態下,對它所執行的測試;所謂「Dynamic Testing」,是指在受測元件處於活躍的狀態下,對它所執行的測試。以買車為例,到汽車展示場看車時,就是在執行 static testing,例如,打開車門進去坐坐,握握方向盤,用手觸摸內裝的質感,觀察其內裝的組裝品質與儀表版的配置,再走出車外用眼睛觀察烤漆的品質,用腳 踢踢輪胎,掀開引擎蓋看看引擎等等;跟汽車展商約定試車時間與地點,將車子駛上道路做試開,感受其馬力、扭力、引擎運轉的流暢性、避震的效果、隔音的靜謐 性以及轉彎的順暢度與離心力道等等,就是在執行 dynamic testing。

就軟體而言,只要程式碼還沒開始動工,就只能執行 static testing,例如 requirement validation、specification review、architecture review 等等,等到程式碼開始動工之後,才能依序展開各項的 dynamic testing,例如 unit test、integration test 與 systemtest 等等。

Validation versus Verification

簡 單地說,「Validation」是指「做對的事情 (do the right things)」,例如產品研發的大方向與目標對或不對、正確或不正確;而「Verification」則是指「把事情做對 (do the things right)」,例如專案的執行力好或不好,實作的技術能力精準或不精準。

以患病求診為例,針對醫生所開立的處方,檢視其 是否「對症下藥」,就是在做 validation;就病人而言,檢視其是否「按時服藥」,就是在做 verification。就軟體而言,validation 是在檢視產品所提供的功能,是否為使用者所期盼的功能,以及是否滿足了使用者的需求等等,而 verification 則是在檢視產品是否依照當初所規劃的規格來設計與實作,以及完工後的品質是否符合標準等等。


衡量程式複雜度的方法

更多精彩请到 http://www.139ya.com

在軟體工程的領域中,有著各式各樣衡量軟體複雜度的方法;其中,有些衡量方法雖 然有其理論的論述基礎,但其計算過程則顯得有些繁瑣,例如 Function Points 與 Halstead's Software Science。以筆者的觀點而言,實用的 software metrics 除了必須具備一定程度的說服力之外,還得具備計算簡潔的特點;據此,筆者將為讀者介紹兩種 software metrics:一、cyclomatic complexity;二、information flow complexity。其中,cyclomatic complexity 是以 control flow 的觀點,去衡量程式碼的複雜度;而 information flow complexity 則是以 data flow 的觀點,去衡量程式碼的複雜度。

Cyclomatic Complexity

這 個「Cyclomatic Complexity」,是由 Thomas J. McCabe 在1976 年12 月於IEEE Transactions on Software Engineering 所提出的,其主要目的在衡量一個 software module 的 decision logic 之複雜度,並可根據複雜度的數值,來預測這個 software module 的可靠性與穩定度;如果 cyclomatic complexity 的值越大,則表示該 software module 的 decision logic 越複雜,出錯的機率或不穩定的程度也越高。

如果將某個 software module 的程式碼化為 control flow graph 之後,其中有 e 個 edges,n 個 nodes,則其 decision logic 的複雜度之計算公式為:

cyclomatic complexity = e – n + 2

這 個由 Thomas J. McCabe 所提出的 cyclomatic complexity,對軟體研發而言有兩個很重要的意義:一、就 software testing 而言,它表示至少需要多少個 test case,才能將 control flow graph 中的每一條 independent path,都走過一遍;二、如果其值過大,例如超過 20,則表示該 software module 的 decision logic 過於複雜,以及目前的軟體架構很可能有其不當之處;因此,應當再次檢視與分析整個 software architecture,以降低這個 software module 的 cyclomatic complexity。

當然,每樣 東西都有其好壞兩面;因此,cyclomatic complexity 亦有其未盡完善之處;其中,最為人所詬病的缺點為:一、對於 non-nested control flow 與 nested control flow 皆給予相同的 complexity,但實際上 nested control flow 應當比 non-nested control flow 來得複雜;二、k-way switch statement 之 k 值通常很大,但大部分的 k-way switch statement 的 control flow 是很單純的;例如,只是單純地將 enum 轉成 string literal;因此,k-way switch statement 通常會使得 cyclomatic complexity 失真。針對第一點, 筆者在稍後會提出一個 nested cyclomatic complexity 來做修正;至於第二點,則可視情況將k-way switch statement 的 complexity contribution 由計算式中刪除,以避免 cyclomatic complexity 失真。

Information Flow Complexity

所 謂「Information Flow Complexity」,顧名思義,就是在分析某個 software module 的 data flow complexity;它所考慮的要素有:一、讀取了哪些 parameters;二、更改了哪些 parameters (updated by value 的不列入計算,只計算updated by reference);三、呼叫了哪些functions (functions called);四、被哪些 functions 所呼叫 (functions that call this function);五、讀取了哪些 global variables;六、更改了哪些 global variables。待查妥所有的要素之值後,即可根據下列公式來計算 information flow complexity:

information flow complexity = length * (fan-in * fan-out)2

where length could be cyclomatic complexity or line of code

fan-in = functions called + parameter read + global variables read

fan-out = functions that call this function + parameter updated by reference + global variables updated

如 果某個 software module 的information flow complexity 之值很高,則表示該 software module 有可能是一個負載很重的關鍵點;例如,處理過多種類的資料抑或分派與協調過多種類的功能等等。就這個 information flow complexity 而言,筆者在蒐集與閱讀相關資料的過程中,並沒有看到任何的文獻提到,有什麼樣的典型參考值可以做為負載是否過重的判斷基準;所以,到底 information flow complexity 的值要大到多大,才算是負載過重,到目前為止似乎是沒有定論的;然而,即使沒有典型的參考值,工程師或專案團隊還是可以針對所有 software module 的 information flow complexity,求出它們的「中位數」與「四分位數」,來做為比較與判斷的基準。