メインコンテンツ

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

CERT C++: INT31-C

Ensure that integer conversions do not result in lost or misinterpreted data

説明

ルール定義

整数の変換でデータの喪失や誤った解釈が発生しないようにします。1

Polyspace 実装

ルール チェッカーは以下の問題をチェックします。

  • 整数変換のオーバーフロー

  • 意図しない値をもつ memset の呼び出しです

  • 符号変化する整数の変換のオーバーフロー

  • 汚染された符号変化の変換

  • 符号なし整数の変換のオーバーフロー

チェッカーの拡張

次の場合は、より厳密な解析を実行するように、このチェッカーを拡張します。

  • 入力値が不明であり、入力のサブセットのみがエラーの原因となっている場合、既定の Bug Finder 解析では "整数変換のオーバーフロー""符号変化する整数の変換のオーバーフロー"、または "符号なし整数の変換のオーバーフロー" を検出しない場合があります。特定のシステム入力値を原因とするこれらの問題の有無をチェックするには、より厳密な Bug Finder 解析を実行してください。特定のシステム入力値から欠陥を見つけるための Bug Finder チェッカーの拡張を参照してください。

  • 既定の Bug Finder 解析では、現在の解析境界の外部からの特定の入力に関する "汚染された符号変化の変換" 問題にフラグを設定しない場合があります。Polyspace 解析での汚染のソースを参照してください。Polyspace 解析の現在のスコープ以外から発生したすべてのデータを汚染されたものと見なすには、コマンド ライン オプション [-consider-analysis-perimeter-as-trust-boundary] を使用します。

すべて展開する

問題

整数変換のオーバーフローは、整数をより小さい整数型に変換する場合に発生します。変数に元の値を表現するだけの十分なバイト数がない場合、変換はオーバーフローします。

異なる浮動小数点型への正確なストレージ割り当てはプロセッサに依存します。ターゲット プロセッサ タイプ (-target)を参照してください。

リスク

整数変換のオーバーフローにより、未定義の動作が発生します。

修正方法

修正方法は欠陥の根本原因によって異なります。多くの場合、結果の詳細には欠陥につながる一連のイベントが表示されます。このイベント リストを使用して、オーバーフローの発生した計算で変数がどのように現在の値を取得したのかを確認します。そのシーケンス内のどのイベントについても修正を実装できます。結果の詳細にイベント履歴が表示されない場合は、ソース コード内で右クリック オプションを使用して逆のトレースを行い、これまでの関連するイベントを確認できます。Polyspace デスクトップ ユーザー インターフェイスでの Bug Finder の結果の解釈も参照してください。

この欠陥は次のようにして修正できます。

  • すべての値に適応できるように、変換の結果に対してより大きいデータ型を使用。

  • オーバーフローにつながる値をチェックし、適切なエラー処理を実行。

一般的に、より小さい整数型への変換は避けます。

以下の修正例を参照してください。

問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。

例 - int から char への変換
char convert(void) {

    int num = 1000000;

    return (char)num; //Noncompliant
}

return ステートメントで、整数変数 numchar に変換されています。しかし、1000000 を表現するには少なくとも 20 ビットが必要なため、8 ビットまたは 16 ビットの文字では表現できません。そのため、変換演算はオーバーフローします。

修正 — 変換の種類を変更

1 つの修正方法として、数全体を表現できる別の整数型に変換することができます。

long convert(void) {

    int num = 1000000;

    return (long)num;
}
問題

意図しない値をもつ memset の呼び出しですは、Polyspace® Bug Finder™ により、不正確な可能性のある引数をもつ関数 memset または wmemset の使用が検出された場合に発生します。

void *memset (void *ptr, int value, size_t num) は、ptr が指すメモリ ブロックの最初の num バイトを指定の value で埋めます。引数 value が不正確である場合、メモリ ブロックは意図されていない値で初期化されます。

意図されていない初期化は、次のような場合に発生することがあります。

問題リスク考えられる解決方法
2 番目の引数が '0' であり、0'\0' ではない。文字 '0' の ASCII 値は 48 (10 進数)、0x30 (16 進数)、069 (8 進数) であり、0 (あるいは '\0') ではない。'0' で初期化する場合は、ASCII 値のいずれかを使用する。それ以外の場合は 0 または '\0' を使用する。
2 番目の引数と 3 番目の引数がおそらく逆になっている。たとえば、3 番目の引数はリテラルであり、2 番目の引数はリテラルではない。順序が逆になっていると、意図されていないサイズのメモリ ブロックが不適切な引数で初期化される。引数の順序を入れ替える。
2 番目の引数が 1 バイトで表現できない。2 番目の引数が 1 バイトで表現できず、またのメモリ ブロックの各バイトがその引数で埋められると想定されている場合、初期化は想定どおりにはなされない。

引数にビット マスクを適用してラップまたは切り捨てを行い、1 バイトで表現できるような結果を生成する。ビット マスクを適用する際は、想定どおりの結果が生成されることを確認する。

たとえば、memset(a, -13, sizeof(a))memset(a, (-13) & 0xFF, sizeof(a)) で置き換える。

修正方法

修正方法は欠陥の根本原因によって異なります。多くの場合、結果の詳細には欠陥につながる一連のイベントが表示されます。そのシーケンス内のどのイベントについても修正を実装できます。結果の詳細にイベント履歴が表示されない場合は、ソース コード内で右クリック オプションを使用して逆のトレースを行い、これまでの関連するイベントを確認できます。Polyspace デスクトップ ユーザー インターフェイスでの Bug Finder の結果の解釈も参照してください。

以下の修正例を参照してください。

問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。

例 - 1 バイトで表現できない値
#include <string.h>

#define SIZE 32
void func(void) {
    char buf[SIZE];
    int c = -2;
    memset(buf, (char)c, sizeof(buf)); //Noncompliant
}

この例では、(char)c は 1 バイトで表現できません。

修正 — ビット マスクの適用

1 つの修正方法として、ビット マスクを適用して結果が 1 バイトで表現できるようにします。ただし、その結果が許容可能な初期化値となることを確認してください。

#include <string.h>

#define SIZE 32
void func(void) {
    char buf[SIZE   ];
    int c = -2;
    memset(buf, c & 0xFF, sizeof(buf));
}
問題

符号変化する整数の変換のオーバーフローは、符号なしの整数を符号付き整数に変換する際に発生します。変数に、元の定数と符号ビットの両方を表現するだけの十分なバイト数がない場合、変換はオーバーフローします。

異なる浮動小数点型への正確なストレージ割り当てはプロセッサに依存します。ターゲット プロセッサ タイプ (-target)を参照してください。

修正方法

修正方法は欠陥の根本原因によって異なります。多くの場合、結果の詳細には欠陥につながる一連のイベントが表示されます。そのシーケンス内のどのイベントについても修正を実装できます。結果の詳細にイベント履歴が表示されない場合は、ソース コード内で右クリック オプションを使用して逆のトレースを行い、これまでの関連するイベントを確認できます。Polyspace デスクトップ ユーザー インターフェイスでの Bug Finder の結果の解釈も参照してください。

以下の修正例を参照してください。

問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。

例 - unsigned char から char への変換
char sign_change(void) {
    unsigned char count = 255;

    return (char)count; //Noncompliant
}

return ステートメントで、符号なしの文字変数 count が符号付き文字に変換されています。しかし char は 8 ビットであり、1 ビットは定数の符号、7 ビットは数字の表現に使われます。255 は 8 ビットを使用するため、変換演算によりオーバーフローが起きます。

修正 — 変換の種類を変更

1 つの修正方法として、より大きい整数型を使用することができます。int を使用すると、符号と数値を表現する十分なビット数が得られます。

int sign_change(void) {
    unsigned char count = 255;

    return (int)count;
}
問題

汚染された符号変化の変換は、セキュリティで保護されないソースに由来し、符号付きから符号なしに暗黙的または明示的に変換される値を調べます。

たとえば、size_t を引数として使用する関数では、引数が暗黙的に符号なし整数に変換されます。size_t を暗黙的に変換する関数のいくつかを、以下に挙げます。

bcmp
memcpy
memmove
strncmp
strncpy
calloc
malloc
memalign

リスク

小さい負の数値を符号なしに変換すると、その結果は大きい正の数値となります。大きい正の数値により、セキュリティが脆弱になる可能性があります。たとえば、符号なしの値を以下で使用した場合がこれに該当します。

  • メモリ サイズ ルーチン — メモリ割り当ての問題の原因となります。

  • 文字列操作ルーチン — バッファー オーバーフローの原因となります。

  • ループ境界 — 無限ループの原因となります。

修正方法

符号なしの負の値の変換を避けるため、変換対象の値が許容範囲内にあることを確認します。たとえば、値がサイズを表す場合は、その値が負ではなく値の最大サイズより小さいことを検証します。

例 - メモリ値をサイズ引数で設定
#include <stdlib.h>
#include <string.h>

enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};

void bug_taintedsignchange(int size) {
    char str[SIZE128] = "";
    if (size<SIZE128) {
        memset(str, 'c', size); //Noncompliant
    }
}

この例では、バッファー char が作成され、memset を使用して埋められます。memset のサイズ引数は、関数の入力引数です。

memset を呼び出すことにより、size が符号なし整数へと暗黙的に変換されます。size が大きい負の数値である場合、その絶対値は整数で表現するには大きすぎる可能性があり、バッファー オーバーフローの原因となります。

修正 — size の値をチェック

1 つの修正方法として、size が有効範囲内にあるかどうかをチェックします。この修正では、size がゼロより大きくバッファー サイズより小さいかどうかを、memset を呼び出す前にチェックします。

#include <stdlib.h>
#include <string.h>

enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};

void corrected_taintedsignchange(int size) {
    char str[SIZE128] = "";
    if (size>0 && size<SIZE128) {
        memset(str, 'c', size);  
    }
}
問題

符号なし整数の変換のオーバーフローは、符号なしの整数をより小さい符号なしの整数型に変換する際に発生します。変数に元の定数を表現するだけの十分なバイト数がない場合、変換はオーバーフローします。

異なる浮動小数点型への正確なストレージ割り当てはプロセッサに依存します。ターゲット プロセッサ タイプ (-target)を参照してください。

リスク

整数変換のオーバーフローにより、未定義の動作が発生します。

修正方法

修正方法は欠陥の根本原因によって異なります。多くの場合、結果の詳細には欠陥につながる一連のイベントが表示されます。そのシーケンス内のどのイベントについても修正を実装できます。結果の詳細にイベント履歴が表示されない場合は、ソース コード内で右クリック オプションを使用して逆のトレースを行い、これまでの関連するイベントを確認できます。Polyspace デスクトップ ユーザー インターフェイスでの Bug Finder の結果の解釈も参照してください。

この欠陥は次のようにして修正できます。

  • すべての値に適応できるように、変換の結果に対してより大きいデータ型を使用。

  • オーバーフローにつながる値をチェックし、適切なエラー処理を実行。

一般的に、より小さい整数型への変換は避けます。

以下の修正例を参照してください。

問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。

例 - int から char への変換
unsigned char convert(void) {
    unsigned int unum = 1000000U;

    return (unsigned char)unum; //Noncompliant
}

return ステートメントで、符号なしの整数変数 unum が符号なしの文字タイプに変換されています。しかし、1000000 には少なくとも 20 ビットが必要なため、変換によりオーバーフローが生じます。C プログラミング言語の規格では、最大値に 1 を加えた値を法としてプログラムが結果を自動的に縮小するため、符号なしのオーバーフローはエラーとは見なされません。この例では、文字データ型は 2^8-1 しか表現できないため、unum2^8 を法として縮小されます。

修正 — 変換の種類を変更

1 つの修正方法として、数全体を表現できる別の整数型に変換することができます。たとえば、long です。

unsigned long convert(void) {
    unsigned int unum = 1000000U;

    return (unsigned long)unum;  
}

チェック情報

グループ: 03.整数 (INT)

バージョン履歴

R2019a で導入


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.