メインコンテンツ

ISO/IEC TS 17961 [padcomp]

Comparison of padding data

説明

ルール定義

パディング データの比較。1

Polyspace 実装

このチェッカーは、パディング データのメモリ比較をチェックします。

すべて展開する

問題

パディング データのメモリ比較は、関数 memcmp を使用して、2 つの構造体全体を比較する場合に発生します。この処理では、構造体のパディングで格納された無意味なデータが比較されます。

次に例を示します。


typedef struct structType {
    char member1;
    int member2;
    //...
}myStruct;

myStruct var1;
myStruct var2;
//...
if(memcmp(&var1,&var2,sizeof(var1)))//Noncompliant 
{
//...
}

リスク

構造体のメンバーが異なるデータ型を持っている場合、コンパイラはメモリ内のデータ アライメントのために追加のパディングを導入します。パディングの例については、ローカル変数サイズのより高い推定値 (Polyspace Code Prover)を参照してください。

これらの追加のパディング バイトの内容に意味はありません。C 標準では、さまざまなコンパイラが独自のパディングを自由に実装できるように、それらのバイトのコンテンツが不確定になることを許容しています。memcmp で構造体のバイト単位の比較を実行する場合、パディングに格納された意味のないデータも比較されます。対応するメンバーが同じ値であっても、2 つのデータ構造体が等しくないという誤った結論になる可能性があります。

修正方法

2 つの構造体を 1 回の試行で比較するのではなく、構造体のメンバーごとに比較します。

効率的なコードにするには、メンバーごとに比較を行う関数を作成します。2 つの構造体を比較するには、この関数を使用します。

構造体がパディングを含まないことがわかっている場合のみ、構造体のバイト単位の比較に memcmp を使用します。通常、パディングが行われないようにするには、特定の属性または #pragma pack などのプラグマを使用します。ただし、このような属性やプラグマは、必ずしもすべてのコンパイラでサポートされているとは限らず、コードの実装はそれぞれ異なります。構造体にビット フィールドが含まれる場合、このような属性やプラグマを使用しても、パディングを防ぐことはできません。

例 - memcmp を使用した構造体の比較
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define fatal_error() abort()

typedef struct s_padding
{
    char c;            
    int i;
    unsigned int bf1:1;    
    unsigned int bf2:2;
    unsigned char buffer[20];
} S_Padding ;

/* Function that guarantees safe access to the input memory */
extern int trusted_memory_zone(void *ptr, size_t sz); 

int func(const S_Padding *left, const S_Padding *right)
{

    if (!trusted_memory_zone((void *)left, sizeof(S_Padding)) ||
        !trusted_memory_zone((void *)right, sizeof(S_Padding))) {
        fatal_error();
    }

    if (0 == memcmp(left, right, sizeof(S_Padding))) 
    {
        return 1;
    }
    else
        return 0;
}

この例では、memcmp を使用して left および right が指す 2 つの構造体をバイト単位で比較しています。構造体の各メンバーに格納された値が同じでも、パディング バイトに使われる意味のない値が同じでなければ、この比較によって等しくないという結果になる可能性があります。

修正 — メンバーごとに構造体を比較

1 つの修正方法として、構造体のメンバーを個別に比較します。

メモ

memcmp を使用して、配列全体を比較できます。配列のメンバーはすべてデータ型が同じです。配列の格納にはパディング バイトは必要ありません。

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

#define fatal_error() abort()

typedef struct s_padding
{
    char c;         
    int i;
    unsigned int bf1:1;    
    unsigned int bf2:2;
    unsigned char buffer[20];
} S_Padding ;

/* Function that guarantees safe access to the input memory */
extern int trusted_memory_zone(void *ptr, size_t sz); 

int func(const S_Padding *left, const S_Padding *right)
{
    if (!trusted_memory_zone((void *)left, sizeof(S_Padding)) ||
        !trusted_memory_zone((void *)right, sizeof(S_Padding))) {
        fatal_error();
    }

    return ((left->c == right->c) &&                
            (left->i == right->i) &&
            (left->bf1 == right->bf1) &&
            (left->bf2 == right->bf2) &&
            (memcmp(left->buffer, right->buffer, 20) == 0)); 
}

チェック情報

決定可能性:決定不可能

バージョン履歴

R2019a で導入


1 Extracts from the standard "ISO/IEC TS 17961 Technical Specification - 2013-11-15" are reproduced with the agreement of AFNOR. Only the original and complete text of the standard, as published by AFNOR Editions - accessible via the website www.boutique.afnor.org - has normative value.