C++安全编码:函数

函数

数组作为函数参数时,必须同时将其长度作为函数的参数

由于C语言风格的数组,默认没有结束符,当读取数组时需要自己根据数组长度进行判断。(这个也是C/C++)比其他语言运行效率高的一点原因。

严禁对公共接口API函数的参数进行ASSERT操作

对于设计成API的函数,必须对参数进行合法性判断,严禁在API实现过程中产生CRASH。
ASSERT,第一会产生crash,release版本又无效;所以assert就显得没有意义。

不对内容进行修改的指针型参数,定义为const

如果参数是指针型参数,且内容不会被修改,请定义为const类型。

谨慎使用不可重入函数

不可重入函数在多线程环境下其执行结果不能达到预期效果,需谨慎使用。常见的不可重入函数包括:
rand, srand
getenv, getenv_s
strtok
strerror
asctime, ctime, localtime, gmtime
setlocale
atomic_init
tmpnam
mbrtoc16, c16rtomb, mbrtoc32, c32rtomb
gethostbyaddr
gethostbyname
inet_ntoa

可重入概念(简而言之是可以重复进入,异步信号安全):若一个程序或子程序可以“在任意时刻被中断然后操作系统调度执行另外一段代码,这段代码又调用了该子程序不会出错”,则称其为可重入(reentrant或re-entrant)的。即当该子程序正在运行时,执行线程可以再次进入并执行它,仍然获得符合设计时预期的结果。与多线程并发执行的线程安全不同,可重入强调对单个线程执行时重新进入同一个子程序仍然是安全的。
一个函数是可重入的,则该函数应当满足下述条件:

  • 不能含有静态(全局)非常量数据。
  • 不能返回静态(全局)非常量数据的地址。
  • 只能处理由调用者提供的数据。
  • 不能依赖於单实例模式资源的锁。
  • 调用(call)的函数也必需是可重入的。

可重入维基百科
可重入与线程安全:
可重入与线程安全两个概念都关系到函数处理资源的方式。但是,他们有重大区别

可重入概念会影响函数的外部接口,而线程安全只关心函数的实现。
大多数情况下,要将不可重入函数改为可重入的,需要修改函数接口,使得所有的数据都通过函数的调用者提供。
要将非线程安全的函数改为线程安全的,则只需要修改函数的实现部分。一般通过加入同步机制以保护共享的资源,使之不会被几个线程同时访问。
操作系统背景与CPU调度策略:
可重入是在单线程操作系统背景下,重入的函数或者子程序,按照后进先出的线性序依次执行完毕。
多线程执行的函数或子程序,各个线程的执行时机是由操作系统调度,不可预期的,但是该函数的每个执行线程都会不时的获得CPU的时间片,不断向前推进执行进度。
可重入函数未必是线程安全的;线程安全函数未必是可重入的。
例如,一个函数打开某个文件并读入数据。这个函数是可重入的,因为它的多个实例同时执行不会造成冲突;但它不是线程安全的,因为在它读入文件时可能有别的线程正在修改该文件,为了线程安全必须对文件加“同步锁”。(存疑!!!)
另一个例子,函数在它的函数体内部访问共享资源使用了加锁、解锁操作,所以它是线程安全的,但是却不可重入。因为若该函数一个实例运行到已经执行加锁但未执行解锁时被停下来,系统又启动该函数的另外一个实例,则新的实例在加锁处将转入等待。如果该函数是一个中断处理服务,在中断处理时又发生新的中断将导致资源死锁。fprintf函数就是线程安全但不可重入。
下述例子,是线程安全的,但不是可重入的。

int function()
{
 mutex_lock();
 ...
 function body
 ...
 mutex_unlock();
}

多线程执行时,获得了互斥锁的线程总能获得CPU时间片,向前推进执行进度,最终解开互斥锁,使得别的线程也能获得互斥锁进入临界区。但是,如果在单线程背景下第一次执行该函数时已经获得互斥锁进入临界区,这时该函数被重入执行,这将在重新申请互斥锁时被饿死(starvation),因为获得了互斥锁的该函数的第一次执行将永远没有机会再获得CPU时间片。

字符串或指针作为函数参数时,请检查参数是否为NULL

如果字符串或者指针作为函数参数,为了防止空指针引用错误,在引用前必须确保该参数不为NULL,如果上层调
用者已经保证了该参数不可能为NULL,在调用本函数时,在函数开始处可以加ASSERT进行校验。 例如下面的代
码,因为BYTE *p有可能为NULL,因此在使用前需要进行判断。

在函数的开始处对参数进行ASSERT操作(API除外)

ASSERT用于检测代码设计上的错误,如果ASSERT被触发,说明代码的设计不符合编码人员的预期。 在函数的开始
处,对参数进行必要的ASSERT操作,可以在测试阶段有效地检验编码人员对代码设计上的预期。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章