EN JP CN

PORTING.SIGNED.CHAR

PORTING.SIGNED.CHAR

明示的に符号を指定しない 'char' の使用

PORTING チェッカーは、異なるコンパイラ内で特定の実装詳細に依存する可能性があるコードを識別します。PORTING.SIGNED.CHAR チェッカーは、明示的に符号が指定されずに 'char' が使用されている C コードの状況を検出します(このチェッカーは、このような符号の問題が C++ コンパイラによって示されるため、C だけに当てはまります)。

脆弱性とリスク

'char' データ型は C 標準規格では正確に定義されていないため、インスタンスが符号ありと見なされたり、見なされなかったりする場合があります。コンパイラによっては、コンパイラオプションを使用して 'char' の符号を切り替えることができます。ただし、開発者にとり、コードの移植時に問題が発生しないように常に明確なコードを記述することがベストプラクティスです。

軽減と防止

必ず、'char' 型の符号を指定してください。常に厳密に使用される typedef または #define を使用して定義することをお勧めします。

脆弱コード例

1   static char *s = "Hello, \xABWorld\xBB!\n"; 

2   /* return next char, or -1 upon end of stream */
3   int get_next_char() { 
4     return *s ? *s++ : -1;
5   } 

6   int main() { 
7     int ch;
8     while ((ch = get_next_char()) > 0) {
9       putchar(ch);
10    }
11    return 0;
12  }

この例では char 型が符号なしの場合に予測どおりに機能し、'World' が引用符で囲まれ、標準出力に文字列が表示されます (Latin-1 エンコーディング)。

Hello, «World»!

char が符号付きの場合、開き引用符までの文字列の一部だけが表示されます。

Hello, 

修正コード例

1   typedef unsigned char UCHAR;
2   static UCHAR *s = "Hello, \xABWorld\xBB!\n";

3   /* return next char, or -1 upon end of stream */
4   int get_next_char() { 
5     return *s ? *s++ : -1;
6   } 

7   int main() { 
8     int ch;
9     while ((ch = get_next_char()) > 0) {
10       putchar(ch);
11    }
12    return 0;
13  }

修正コードでは、char ではなく、unsigned char を使用します。while ループの条件を (ch = get_next_char()) != -1) に変更しても、このストリームは 'xFF' 文字で終了するので問題は修正されません。