メインコンテンツ

CWE Rule 135

Incorrect Calculation of Multi-Byte String Length

R2023a 以降

説明

ルールの説明

The software does not correctly calculate the length of strings that can contain wide or multi-byte characters.

Polyspace 実装

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

  • 文字列操作で格納先バッファーがオーバーフローしています

  • ナロー文字列またはワイド文字列の不適切な使用

  • ポインターの信頼性の低いキャスト

すべて展開する

問題

この問題は、特定の文字列操作関数によって、その格納先バッファー引数にバッファー サイズを超えるオフセットで書き込まれた場合に発生します。

たとえば、関数 sprintf(char* buffer, const char* format) を呼び出す際に、buffer より大きいサイズの定数文字列 format を使用する場合などです。

リスク

バッファー オーバーフローにより、メモリ破損やシステム停止といった予期しない動作を引き起こす可能性があります。また、バッファー オーバーフローは、コード インジェクションのリスクにもつながります。

修正方法

1 つの解決策として、代替となる関数を使用して、書き込まれる文字の数を制限します。次に例を示します。

  • 書式設定されたデータを文字列に書き込むのに sprintf を使用している場合は、代わりに snprintf_snprintf または sprintf_s を使用して長さを制御します。あるいは、asprintf を使用して、格納先バッファーに必要なメモリを自動で割り当てます。

  • 書式設定されたデータを可変引数リストから文字列に書き込むのに vsprintf を使用している場合は、代わりに vsnprintf または vsprintf_s を使用して長さを制御します。

  • ワイド文字列をコピーするのに wcscpy を使用している場合は、代わりに wcsncpywcslcpy または wcscpy_s を使用して長さを制御します。

別の解決策として、バッファー サイズを増やします。

例 — sprintf の使用におけるバッファー オーバーフロー
#include <stdio.h>

void func(void) {
    char buffer[20];
    char *fmt_string = "This is a very long string, it does not fit in the buffer";

    sprintf(buffer, fmt_string);  //Noncompliant
}

この例では、bufferchar 要素を 20 個格納できますが、fmt_string はより大きいサイズとなっています。

修正 — snprintfsprintf の代わりに使用

1 つの修正方法として、関数 snprintf を使用して長さを制御します。

#include <stdio.h>

void func(void) {
    char buffer[20];
    char *fmt_string = "This is a very long string, it does not fit in the buffer";

    snprintf(buffer, 20, fmt_string);
}
問題

この問題は、ナロー文字列をワイド文字列関数に渡したり、ワイド文字列をナロー文字列関数に渡したりした場合に発生します。

ナロー文字列またはワイド文字列の不適切な使用は、ナロー文字列とワイド文字列が同じサイズになるオペレーティング システムでは欠陥を報告しません。

リスク

ワイド文字列関数にナロー文字列 (またはその逆) を使用すると、予期しない動作または未定義の動作になる可能性があります。

ワイド文字列をナロー文字列関数に渡す場合、以下の問題が発生する可能性があります。

  • データの切り捨て。文字列に null バイトが含まれている場合、strncpy() を使用するコピー操作が早期に終了する可能性があります。

  • 不適切な文字列長。strlen() は最初の null バイトまでの文字列の文字数を返します。ワイド文字列には、その最初の null バイトの後ろに追加文字が含まれている場合があります。

ナロー文字列をワイド文字列関数に渡す場合、以下の問題が発生する可能性があります。

  • バッファー オーバーフロー。wcsncpy() を使用するコピー操作で、格納先文字列に、コピーの結果を格納するためのメモリが十分にない場合があります。

修正方法

ナロー文字列関数にナロー文字列を使用します。ワイド文字列関数にワイド文字列を使用します。

例 — strncpy() にワイド文字列を渡す
#include <string.h>
#include <wchar.h>

void func(void)
{
    wchar_t wide_str1[]  = L"0123456789";
    wchar_t wide_str2[] =  L"0000000000";
    strncpy(wide_str2, wide_str1, 10); //Noncompliant 
}

この例では、strncpy() は 10 個のワイド文字列を wide_strt1 から wide_str2 にコピーします。wide_str1 に null バイトが含まれている場合、コピー操作が途中で終了し、ワイド文字列が打ち切られる可能性があります。

修正 — wcsncpy() を使用してワイド文字列をコピー

1 つの修正方法として、wcsncpy() を使用して wide_str1wide_str2 にコピーします。

#include <string.h>
#include <wchar.h>

void func(void)
{
    wchar_t wide_str1[]  = L"0123456789";
    wchar_t wide_str2[] =  L"0000000000";
    wcsncpy(wide_str2, wide_str1, 10);
}
問題

この問題は、ポインターが宣言の型とは異なるデータ型に暗黙的にキャストされた場合に発生します。このような暗黙的なキャストは、たとえば、データ型 char へのポインターに整数のアドレスが割り当てられる場合に行われます。

この欠陥は、プロジェクトのコード言語が C の場合にのみ当てはまります。

リスク

ポインターを宣言の型とは異なるデータ型にキャストすると、バッファー オーバーフローなどの問題が発生する可能性があります。このキャストが暗黙的な場合、コーディング エラーを示す可能性があります。

修正方法

ポインターを宣言の型と異なるデータ型に "暗黙的に" キャストすることは避けます。

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

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

例 — ポインターの信頼性の低いキャスト エラー
 #include <string.h>
 
 void Copy_Integer_To_String()
 {
  int src[]={1,2,3,4,5,6,7,8,9,10};
  char buffer[]="Buffer_Text";
  strcpy(buffer,src);  //Noncompliant
  /* Defect: Implicit cast of (int*) to (char*) */
 }

srcint* ポインターとして宣言されています。strcpy ステートメントは、buffer へのコピーに際して、暗黙的に srcchar* にキャストします。C++ では、このようなキャストのコンパイルは失敗します。

修正 — ポインターをキャストしない

1 つの修正方法として、ポインター srcbuffer と同じデータ型で宣言することができます。

 #include <string.h>
  void Copy_Integer_To_String()
 {
  /* Fix: Declare src with same type as buffer */
  char *src[10]={"1","2","3","4","5","6","7","8","9","10"};  
  char *buffer[10];

  for(int i=0;i<10;i++)
    buffer[i]="Buffer_Text";

  for(int i=0;i<10;i++)
    buffer[i]= src[i];
  }

チェック情報

カテゴリ: String Errors

バージョン履歴

R2023a で導入