メインコンテンツ

整数の精度を超過しました

精度の代わりに整数サイズを使用する操作により発生する可能性のある未定義の動作

説明

この欠陥は、演算の整数式で整数精度を超える整数サイズが使用された場合に発生します。一部のアーキテクチャでは、メモリ内の整数サイズに符号とパディング ビットが含まれることがあります。これらのアーキテクチャでは、整数の値相当のビット数にすぎない精度よりも整数サイズの方が大きくなります。

リスク

整数の精度に対する演算に整数サイズを使用すると、整数オーバーフロー、ラップ アラウンド、または予期しない結果を引き起こす可能性があります。たとえば、符号なし整数は 64 ビットのメモリに格納できますが、その値を表現するには 48 ビットのみを使用します。この整数に対する 56 ビット左シフト演算は未定義の動作です。

整数のサイズがその精度と等しいと仮定すると、異なるアーキテクチャ間でプログラム移植性の問題が発生する場合もあります。

修正方法

整数のサイズをその精度の代わりに使用しないようにします。整数の精度を求めるには、精度計算ルーチンを実装するか、__builtin_popcount() などの組み込み関数を使用します。

すべて展開する

#include <limits.h>

unsigned int func(unsigned int exp)
{
    if (exp >= sizeof(unsigned int) * CHAR_BIT) {
        /* Handle error */
    }
    return 1U << exp;
}

この例では、関数は左シフト演算を使用して 2 の exp 乗の値を返します。演算では、1U のビットを左に exp 位置だけシフトします。if ステートメントでは、演算でビットをシフトする位置数 expunsigned int のサイズよりも大きくなっていないことを確認しています。しかし、unsigned int にパディング ビットが含まれる場合、sizeof() により返される値は unsigned int の精度よりも大きくなります。その結果、exp の一部の値が大きくなりすぎる可能性があり、シフト演算が未定義の動作になる場合があります。

修正 — unsigned int の精度を計算する関数を実装

1 つの修正方法として、設定されたビット数をカウントして unsigned int の精度を計算する関数 popcount() を実装します。

#include <stddef.h>
#include <stdint.h>
#include <limits.h>

size_t popcount(uintmax_t);
#define PRECISION(umax_value) popcount(umax_value)


unsigned int func(unsigned int exp)
{
    if (exp >= PRECISION(UINT_MAX)) {
        /* Handle error */
    }
    return 1 << exp;
}




size_t popcount(uintmax_t num)
{
    size_t precision = 0;
    while (num != 0) {
        if (num % 2 == 1) {
            precision++;
        }
        num >>= 1;
    }
    return precision;
} 

結果情報

グループ: 数値
言語: C | C++
既定値: オフ
コマンド ライン構文: INT_PRECISION_EXCEEDED
影響度: Low

バージョン履歴

R2018b で導入