星期二, 10月 14, 2014

避免不當的使用 Macro 造成的 Memory Leak



這次我們談談七大讓工程師黯然消魂的問題中排名第七的問題, 外號 -- “吸星大法"

嵌入式程式開發人員一般來說,
會使用使用系統預設提供的API 來進行取得(allocate) 和釋放(free)  heap memory的工作


例如下面的程式碼
void some_function(void) {
   int*pi;


   pi = (int *) os_malloc_b(sizeof(int));


   /*do something for pi */
   os_mfree(pi);
}


這個例子中, os_malloc_b() 是allocate memory 的 API,
os_mfree() 是free memory 的 API


但是有時候 allocate memory 的方式不是那麼直覺的,(例如自以為是的架構長直接下令統一風格)
而是透過Macro 來allocate  memory,
看下面這個範例


#define OS_ALLOC_MSG_PTR(p, type) \
            P = (type *) os_malloc_b(sizeof(type))


#define OS_FREE_MSG(p)    os_mfree(p)


boolean memory_leak_function(void) {
   T_MSG*pMsg;   


   OS_ALLOC_MSG_PTR(pMsg,T_MSG);        //1


  /* fill some data in the message */
  if (os_send_msg(Task_A,pMsg) < 0 ) {       //2
      return false;                                        //3
  }
}


這段程式在 //1 的地方用 Macro allocate 一塊memory 用來當作送出去的message ,
然後在//2 呼叫 os_send_msg 送給 Task A,
由 Task A 處理完畢之後,
free 掉這塊收到的 message


這段程式乍看之下沒有錯 (但是天底下哪有這麼好的事情)
主要會發生的問題是//2 send message 的時候可能有失敗的情形, (誰叫你們用的CPU處理速度這麼慢)
大多數的程式開發人員都會記得處理錯誤的case ,  (如果連這個都沒處理, 就應該拖出午門斬首)
例如 //3
但是會忘記 free 掉原先那塊不用的memory.(因為不會馬上死人, 所以這個問題很難被抓到)
這樣系統就會久久當一次機(因為 memory 不夠用), 成為懸而未解的問題


正確的寫法如下,
增加 //4, 釋放掉memory 再回error code.


  if (os_send_msg(Task_A,pMsg) < 0 ) {      
      OS_FREE_MSG(pMsg);                          //4
      return false;                           
  }
}

沒有留言: