メインコンテンツ

CWE Rule 474

Use of Function with Inconsistent Implementations

R2023a 以降

説明

ルールの説明

The code uses a function that has inconsistent implementations across operating systems and versions.

Polyspace 実装

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

  • 信号ハンドラー内からの信号呼び出し

  • 旧式の標準関数が使用されています

すべて展開する

問題

この問題は、Windows® プラットフォームで信号ハンドラーから関数 signal() を呼び出す場合に発生します。

この欠陥は、Visual Studio コンパイラを指定した場合にのみ検出されます。コンパイラ (-compiler) を参照してください。

リスク

関数 signal() は、信号と信号ハンドラー関数を関連付けます。信号の受信後にこの関連付けが削除される Windows などのプラットフォーム上では、"信号ハンドラー内で" 再度関数 signal() を呼び出して、関連付けを再設定することができます。

ただし、信号ハンドラーを永続的にするこの試みによって、競合状態が引き起こされやすくなります。Windows プラットフォームでは、信号ハンドラーが実行を開始してから、関数 signal が再度呼び出されるまでの間に、アクティブになっているのは既定の信号処理 SIG_DFL です。この間に 2 つ目の信号が受信されると、ユーザーの期待に反して、カスタム信号ハンドラーではなく既定の信号ハンドラーが示されます。

修正方法

Windows プラットフォームでは信号ハンドラーから signal() を呼び出さないようにします。

例 — 信号ハンドラーからの signal() の呼び出し
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>



volatile sig_atomic_t e_flag = 0;

void sig_handler(int signum)
{
    int s0 = signum;
    e_flag = 1;
	
	/* Call signal() to reestablish sig_handler 
	upon receiving SIG_ERR. */
   
    if (signal(s0, sig_handler) == SIG_ERR)  //Noncompliant
    {
        /* Handle error */       
    }
}

void func(void)
{
        if (signal(SIGINT, sig_handler) == SIG_ERR)
        {
            /* Handle error */
            
        }
  /* more code */
}        
      

この例では、sig_handler() の定義にハンドラーが SIG_ERR をキャッチした際の signal() の呼び出しが含まれています。Windows プラットフォームでは、信号ハンドラーは永続的ではありません。このコードは、競合状態を発生させる可能性があります。

この問題は、visual15.x などのコンパイラを解析用として指定した場合にのみ検出されます。

修正 — 信号ハンドラーから signal() を呼び出さない

Windows 上で信号ハンドラーを永続的にする試みを避けます。コードで Windows プラットフォームで永続的な信号ハンドラーを使用する必要がある場合、徹底的なリスク解析をしてから永続的な信号ハンドラーを使用します。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>



volatile sig_atomic_t e_flag = 0;


void sig_handler(int signum)
{
    int s0 = signum;
    e_flag = 1;
    /* No call to signal() */
}

int main(void)
{
    
        if (signal(SIGINT, sig_handler) == SIG_ERR)
        {
            /* Handle error */
            
        }
}
 
問題

この問題は、C/C++ コーディング規約でレガシ、削除済み、非推奨、または旧式とされている標準関数ルーチンが使用された場合に発生します。

旧式の関数規格リスク置換関数
asctimePOSIX.1-2008 で使用終了スレッドセーフでない。strftime または asctime_s
asctime_rPOSIX.1-2008 で使用終了安全でない関数 sprintf に基づく実装。strftime または asctime_s
bcmp

4.3BSD で使用終了

POSIX.1–2001 でレガシとマークされている。

最初の異なるバイトを見つけたら関数から戻るため、タイミング攻撃に対して脆弱になる。 memcmp
bcopy

4.3BSD で使用終了

POSIX.1–2001 でレガシとマークされている。

最初の異なるバイトを見つけたら関数から戻るため、タイミング攻撃に対して脆弱になる。 memcpy または memmove
brk および sbrkSUSv2 および POSIX.1-2001 でレガシとマークされている。 malloc
bsd_signalPOSIX.1–2008 で削除済み sigaction
bzeroPOSIX.1–2001 でレガシとマークされている。POSIX.1–2008 で削除済み。 memset
ctimePOSIX.1-2008 で使用終了スレッドセーフでない。strftime または asctime_s
ctime_rPOSIX.1-2008 で使用終了安全でない関数 sprintf に基づく実装。strftime または asctime_s
cuseridPOSIX.1–2001 で削除済み。再呼び出し可能でない。正確な機能が標準化されておらず、移植性の問題の原因となる。getpwuid
ecvt および fcvtPOSIX.1–2001 でレガシとマークされている。POSIX.1–2008 で削除済み再呼び出し可能でないsnprintf
ecvt_r および fcvt_rPOSIX.1–2001 でレガシとマークされている。POSIX.1–2008 で削除済み snprintf
ftimePOSIX.1–2008 で削除済み time, gettimeofday, clock_gettime
gamma, gammaf, gammal履歴が錯綜しているため、関数はどの規格でも指定されていない移植性の問題。tgamma, lgamma
gcvtPOSIX.1–2001 でレガシとマークされている。POSIX.1–2008 で削除済み。 snprintf
getcontextPOSIX.1–2008 で削除済み。移植性の問題。 POSIX スレッドを代わりに使用。
getdtablesizeBSD API 関数が POSIX.1-2001 に含まれていない移植性の問題。sysconf( _SC_OPEN_MAX )
gethostbyaddrPOSIX.1–2008 で削除済み再呼び出し可能でないgetaddrinfo
gethostbynamePOSIX.1–2008 で削除済み再呼び出し可能でないgetnameinfo
getpagesizeBSD API 関数が POSIX.1-2001 に含まれていない移植性の問題。sysconf( _SC_PAGESIZE )
getpassPOSIX.1–2001 で削除済み。再呼び出し可能でない。getpwuid
getwPOSIX.1-2001 に存在しない。 fread
getwdPOSIX.1-2001 でレガシとマークされている。POSIX.1–2008 で削除済み。 getcwd
indexPOSIX.1–2001 でレガシとマークされている。POSIX.1–2008 で削除済み。 strchr
makecontextPOSIX.1–2008 で削除済み。移植性の問題。 POSIX スレッドを代わりに使用。
memalignSunOS 4.1.3 で登場。4.4 BSD または POSIX.1-2001 にはなし posix_memalign
mktempPOSIX.1–2008 で削除済み。生成された名前が予測可能であり、競合状態の原因となることがある。mkstemp は競合リスクを除去
pthread_attr_getstackaddr および pthread_attr_setstackaddr stackaddr 属性の仕様にあいまいさがあり、移植性の問題の原因となるpthread_attr_getstack および pthread_attr_setstack
putwPOSIX.1-2001 に存在しない。移植性の問題。fwrite
qecvt および qfcvtPOSIX.1-2001 でレガシとマークされ、POSIX.1-2008 で削除済み snprintf
qecvt_r および qfcvt_rPOSIX.1-2001 でレガシとマークされ、POSIX.1-2008 で削除済み snprintf
rand_rPOSIX.1-2008 で旧式とマークされている  
re_compBSD API 関数移植性の問題regcomp
re_exesBSD API 関数移植性の問題regexec
rindexPOSIX.1–2001 でレガシとマークされている。POSIX.1–2008 で削除済み。 strrchr
scalbPOSIX.1–2008 で削除済み scalblnscalblnf または scalblnl
sigblock出典が不明な 4.3BSD シグナル API sigprocmask
sigmask出典が不明な 4.3BSD シグナル API sigprocmask
sigsetmask出典が不明な 4.3BSD シグナル API sigprocmask
sigstackインターフェイスが旧式であり、ほとんどのプラットフォームで実装されていない。移植性の問題。sigaltstack
sigvec出典が不明な 4.3BSD シグナル API sigaction
swapcontextPOSIX.1–2008 で削除済み移植性の問題。 POSIX スレッドを使用。
tmpnam および tmpnam_rPOSIX.1–2008 で旧式とマークされている。この関数は、呼び出されるたびに TMP_MAX 回目まで異なる文字列を生成。呼び出される回数が TMP_MAX 回を超えると、動作が処理系定義になる。 mkstemp, tmpfile
ttyslotPOSIX.1–2001 で削除済み。  
ualarmPOSIX.1–2001 でレガシとマークされている。POSIX.1–2008 で削除済み。エラーの指定が不十分。setitimer または POSIX timer_create
usleepPOSIX.1–2008 で削除済み。 nanosleep
utimeSVr4、POSIX.1-2001。POSIX.1-2008 で旧式とマークされている。  
valloc

4.3BSD で旧式とマークされている。

SUSv2 でレガシとマークされている。

POSIX.1-2001 から削除済み

 posix_memalign
vfork

POSIX.1-2008 から削除済み

以前の規格で指定が不十分。fork
wcswcsこの関数は最終的な ISO/IEC 9899:1990/Amendment 1:1995 (E) に含まれていなかった。  wcsstr
WinExecWinAPI ではこの関数を 16 ビット Windows 互換でのみ提供。 CreateProcess
LoadModuleWinAPI ではこの関数を 16 ビット Windows 互換でのみ提供。 CreateProcess
修正方法

修正方法は欠陥の根本原因によって異なります。上の表に記載されている修正と以下の修正付きのコード例を参照してください。

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

例 — 時刻の出力
#include <stdio.h>
#include <time.h> 

void timecheck_bad(int argc, char *argv[])
{
    time_t ticks; 

    ticks = time(NULL);
    printf("%.24s\r\n", ctime(&ticks));  //Noncompliant
}

この例では、関数 ctime が現在の時刻を書式設定して出力します。しかし、ctime はマルチスレッド プログラムで機能しないため、C99 以降で削除されています。

修正 — 別の時間関数

1 つの修正方法として、strftime を代わりに使用します。この関数は一定のバッファー サイズを使用するためです。

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

void timecheck_good(int argc, char *argv[])
{
    char outBuff[1025];
    time_t ticks; 
    struct tm * timeinfo;
    
    memset(outBuff, 0, sizeof(outBuff)); 
    
    ticks = time(NULL);
    timeinfo = localtime(&ticks);
    strftime(outBuff,sizeof(outBuff),"%I:%M%p.",timeinfo);
    fprintf(stdout, outBuff);
}

チェック情報

カテゴリ: API / Function Errors

バージョン履歴

R2023a で導入