符号拡張文字の値の不適切な使用
符号拡張によるデータ型変換は予期しない動作を引き起こす
説明
この欠陥は、取りうる負の値を含む符号付きまたはプレーンな char 変数をより大きい整数データ型に変換 (またはそのような変換を行う算術演算を実行) し、結果として得られる値を次のいずれかの方法で使用した場合に発生します。
EOFとの比較のため (==または!=を使用)配列インデックスとして
isalpha()またはisdigit()などのctype.hにある文字処理関数の引数として
負の値をもつ符号付き char 変数を int などのより大きい型に変換した場合、符号ビットが保持されます (符号拡張)。符号ビットを考慮したと考えられる状況でも、これが特定の問題の原因となる場合があります。
たとえば、符号付き char の値 -1 は、文字 EOF (ファイルの終端) を表すことができますが、これは無効な文字です。char 型の変数 var がこの値を取得するとします。var を char 型の変数として扱う場合、この無効な文字値を考慮するために特別なコードの記述が必要になる場合があります。ただし、var++ などの (整数プロモーションを伴う) 演算を実行する場合、値が 0 になり、この値は意図せず有効な値 '\0' を表します。算術演算を通じて無効な値が有効な値に遷移したことになります。
-1 以外の負の値の場合でも、符号付き char から符号付き int への変換は別の問題につながる場合があります。たとえば、符号付き char 値 -126 は unsigned char 値 130 (拡張文字 '\202' に対応) と等価です。この値を char から int に変換する場合、符号ビットは保持されます。さらに、結果として得られる値を unsigned int にキャストすると、予想外に大きな値 4294967170 が得られます (32 ビットの int を仮定)。コードで最終的な unsigned int 型の変数が unsigned char 型の値 130 になることを想定している場合、予期しない結果になる可能性があります。
この問題の根本的原因は、より大きい型への変換時の符号拡張です。ほとんどのアーキテクチャでは、値を格納するために 2 の補数表現を使用します。この表現では、最上位ビットは値の符号を示します。より大きい型に変換する場合、符号を保持するために、この符号ビットをより大きい型のすべての先頭ビットにコピーすることによって変換が実行されます。たとえば、char 値 -3 は 11111101 として表現されます (8 ビットの char を仮定)。int に変換すると、表現は次のようになります。
11111111 11111111 11111111 11111101
int 型で保持されます。ただし、unsigned int に変換すると、値 (4294967293) は元の char 値と同等な unsigned char と同じではなくなります。この問題を認識していない場合、コードで予期しない結果が生じる可能性があります。リスク
以下の場合、Bug Finder は、char からより大きいデータ型への変換または変数をより大きいデータ型に暗黙的に変換する算術演算の後での変数の使用にフラグを設定します。
変数値を EOF と比較する場合:
char値 -1 は無効な文字EOFまたは有効な拡張文字の値'\377'(unsigned charでの等価値 255 に対応) を表す可能性があります。char型の変数がintなどのより大きい型にキャストされると、符号拡張により、EOFまたは'\377'のいずれかを表すchar値 -1 はEOFのみを表すint値 -1 になります。unsigned char値 255 をint型の変数から復元することはできません。Bug Finder はこの状況にフラグを設定し、この変数を最初にunsigned charにキャストできるように (または、charからintへの変換やEOFと比較する前の変換演算を避けることができるように) します。こうすることでのみ、EOFとの比較が意味のあるものになります。符号拡張文字の値と EOF の比較を参照してください。変数値を配列インデックスとして使用する場合:
char型の変数がintなどのより大きい型にキャストされると、符号拡張により、すべての負の値の符号は保持されます。負の値を直接使用して配列にアクセスすると、バッファー オーバーフローまたはバッファー アンダーフローの原因になります。負の値を考慮している場合でも、考慮の方法によっては、不適切な要素が配列から読み取られる可能性があります。配列インデックスとして使用される符号拡張文字の値を参照してください。変数値を引数として文字処理関数に渡す場合:
C11 規格 (節 7.4) によると、
unsigned charまたはEOFとして表現できない整数引数を指定した場合、結果の動作は未定義になります。変換後の負のchar値はunsigned charまたはEOFとして表現できないため、Bug Finder はこの状況にフラグを設定します。たとえば、符号付きchar値 -126 はunsigned char値 130 と等価ですが、符号付きint値 -126 はunsigned charまたはEOFとして表現できません。
修正方法
より大きな整数データ型に変換する前に、符号付きまたはプレーンな char 値を明示的に unsigned char にキャストします。
char データ型を、文字を表現するためでなく、単純にメモリを節約するために小さいデータ型として使用する場合、符号拡張された char 値を使用すると、前述のリスクを回避できる可能性があります。その場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。
Polyspace ユーザー インターフェイスでのバグ修正または正当化による結果への対処 (Polyspace ユーザー インターフェイスで結果をレビューする場合)。
Polyspace Access でのバグ修正または正当化による結果への対処 (Polyspace Access) (Web ブラウザーで結果をレビューする場合)。
コードへの注釈付けと既知の結果または許容可能な結果の非表示 (IDE で結果をレビューする場合)
例
結果情報
| グループ: プログラミング |
| 言語: C | C++ |
| 既定値: 手書きコードはオン、生成コードはオフ |
コマンド ライン構文: CHARACTER_MISUSE |
| 影響度: Medium |
バージョン履歴
R2017a で導入