PORTING.SIGNED.CHAR

使用“char”但没有明确指定符号规范

PORTING 检查器会标识那些可能依赖于不同编译器中特定实施细则的代码。PORTING.SIGNED.CHAR 检查器检测那些在 C 代码中使用了“char”但没有明确指定符号的情况。(该检查器仅适用于 C,因为 C++ 编译器会解决这些符号规范问题。)

漏洞与风险

char 数据类型并未在 C 标准中进行精确的定义,因此某个实例可能被视为有符号,也可能被视为无符号。某些编译器允许使用编译器选项来转换 char 的符号,但开发人员的最佳做法是始终编写无歧义的代码,以避免移植代码时出现问题。

缓解与预防

始终指定“char”类型的符号。最好是使用 typedef 或 #define 定义,然后在各处都严格执行该定义。

漏洞代码示例

复制
   static char *s = "Hello, \xABWorld\xBB!\n"; 
   /* return next char, or -1 upon end of stream */
   int get_next_char() { 
     return *s ? *s++ : -1;
   } 
   int main() { 
     int ch;
     while ((ch = get_next_char()) > 0) {
       putchar(ch);
    }
    return 0;
  }

当本示例中的字符没有符号时,它按预期方式工作,且在标准输出时打印字符串,并将“World”放在角引号中(采用 Latin-1 编码):

复制
Hello, B«WorldB»!

当字符型有符号时,代码仅打印部分字符串,一直打印到开角引号处:

复制
Hello,

修正代码示例

复制
   typedef unsigned char UCHAR;
   static UCHAR *s = "Hello, \xABWorld\xBB!\n";
   /* return next char, or -1 upon end of stream */
   int get_next_char() { 
     return *s ? *s++ : -1;
   } 
   int main() { 
     int ch;
     while ((ch = get_next_char()) > 0) {
       putchar(ch);
    }
    return 0;
  }

在经修复的代码中,使用 unsigned char 代替 char。 将 while 循环的条件改为 (ch = get_next_char()) != -1) 无法修复问题,因为无论如何,流都将在 '\xFF' 处终止。