86

strncpy()おそらくバッファオーバーフローから保護します。ただし、null で終了せずにオーバーフローを防ぐと、後続の文字列操作がオーバーフローする可能性が高くなります。したがって、これを防ぐために、次のことを行っています。

strncpy( dest, src, LEN );
dest[LEN - 1] = '\0';

man strncpy与えます:

のバイト以下がコピーさstrncpy()れることを除いて、機能は似ています。したがって、 の最初のバイトにnull バイトがない場合、結果は null で終了しません。nsrcnsrc

次のように一見無害に見えるものをnullで終了することなく:

   printf( "FOO: %s\n", dest );

...クラッシュする可能性があります。


より安全で優れた代替手段はありstrncpy()ますか?

4

11 に答える 11

50

strncpy()より安全な として使用することを意図したものではなく、strcpy()ある文字列を別の文字列の途中に挿入するために使用することを想定しています。

snprintf()やなどの「安全な」文字列処理関数はすべてvsnprintf()、バッファ オーバーフローの悪用などを軽減するために後の標準に追加された修正です。

ウィキペディアstrncat()は、独自の safe を作成する代わりに次のように言及していstrncpy()ます。

*dst = '\0';
strncat(dst, src, LEN);

編集

strncat()文字列がLEN文字以上である場合、文字列をnullで終了するときに、LEN文字を超えることを見逃しました。

とにかく、/whateverstrncat()などの自家製ソリューションの代わりに使用するポイントは、ライブラリでの実装がターゲット/プラットフォームに最適化される可能性があることです。memcpy(..., strlen(...))strncat()

もちろん、dst が少なくとも nullchar を保持していることを確認する必要があるため、正しい使用法は次のstrncat()ようになります。

if (LEN) {
    *dst = '\0'; strncat(dst, src, LEN-1);
}

strncpy()また、部分文字列を別の文字列にコピーするのにあまり役に立たないことも認めます.srcがn文字より短い場合、宛先文字列は切り捨てられます.

于 2009-09-21T11:12:29.863 に答える
27

もともと、第7 版の UNIXファイル システム (DIR(5) を参照) には、ファイル名を 14 バイトに制限するディレクトリ エントリがありました。ディレクトリ内の各エントリは、inode 番号用の 2 バイトと名前用の 14 バイトで構成され、14 文字になるように null が埋め込まれますが、必ずしも null で終了するとは限りません。これらのディレクトリ構造で動作するように設計されているというのが私の信念ですstrncpy()。少なくとも、その構造では完全に動作します。

検討:

  • 14 文字のファイル名がヌルで終了していませんでした。
  • 名前が 14 バイトより短い場合は、全長 (14 バイト) までヌルが埋め込まれます。

これはまさに次の方法で実現できます。

strncpy(inode->d_name, filename, 14);

そのstrncpy()ため、元のニッチなアプリケーションに理想的に適合しました。偶然にも、null で終わる文字列のオーバーフローを防ぐことが目的でした。

(長さ 14 までのヌル パディングは重大なオーバーヘッドではないことに注意してください。バッファの長さが 4 KB で、20 文字を安全にコピーすることだけが必要な場合、余分な 4075 ヌルは深刻な過剰であり、簡単に長いバッファーに素材を繰り返し追加すると、2 次動作につながります)。

于 2009-09-21T11:33:54.713 に答える
26

安全なコピーを行うstrlcpyのようなオープン ソースの実装が既にあります。

http://en.wikipedia.org/wiki/Strlcpy

参照には、ソースへのリンクがあります。

于 2009-09-21T11:32:00.543 に答える
9

Strncpyは、プログラムのユーザーによるスタックオーバーフロー攻撃に対してより安全です。これは、説明したように、nullで終了しない文字列を出力するなど、プログラマーが行うエラーからユーザーを保護しません。

printfによって出力される文字数を制限することで、説明した問題によるクラッシュを回避できます。

char my_string[10];
//other code here
printf("%.9s",my_string); //limit the number of chars to be printed to 9
于 2009-09-21T22:33:42.567 に答える
8

いくつかの新しい代替案は、ISO / IEC TR 24731で指定されています(詳細については、 https: //buildsecurityin.us-cert.gov/dreams/bsi/articles/knowledge/coding/317-BSI.htmlを確認してください)。これらの関数のほとんどは、ターゲット変数の最大長を指定する追加のパラメーターを取り、すべての文字列がnullで終了_sし、以前の「安全でない」バージョンと区別するために(「安全」?)で終わる名前を持つようにします。 。1

残念ながら、それらはまだサポートを受けており、特定のツールセットでは使用できない場合があります。古いバージョンのVisualStudioは、古い安全でない関数を使用すると警告をスローします。

ツールが新しい関数をサポートしていない場合は、古い関数の独自のラッパーを作成するのはかなり簡単です。次に例を示します。

errCode_t strncpy_safe(char *sDst, size_t lenDst,
                       const char *sSrc, size_t count)
{
    // No NULLs allowed.
    if (sDst == NULL  ||  sSrc == NULL)
        return ERR_INVALID_ARGUMENT;

   // Validate buffer space.
   if (count >= lenDst)
        return ERR_BUFFER_OVERFLOW;

   // Copy and always null-terminate
   memcpy(sDst, sSrc, count);
   *(sDst + count) = '\0';

   return OK;
}

必要に応じて関数を変更できます。たとえば、オーバーフローすることなく、常に可能な限り多くの文字列をコピーすることができます。_TRUNCATE実際、VC ++実装は、として渡すとこれを実行できますcount




1もちろん、ターゲットバッファのサイズについては、正確である必要があります。3文字のバッファをstrcpy_s()指定しても、25文字のスペースがあると言った場合でも、問題が発生します。

于 2009-09-21T10:57:03.687 に答える
5

strlcpy()ここで指定されたを使用します。http://www.courtesan.com/todd/papers/strlcpy.html

libc に実装がない場合は、次の実装を試してください。

size_t strlcpy(char* dst, const char* src, size_t bufsize)
{
  size_t srclen =strlen(src);
  size_t result =srclen; /* Result is always the length of the src string */
  if(bufsize>0)
  {
    if(srclen>=bufsize)
       srclen=bufsize-1;
    if(srclen>0)
       memcpy(dst,src,srclen);
    dst[srclen]='\0';
  }
  return result;
}

(2004 年に私によって書かれました - パブリック ドメインに専念します。)

于 2009-09-21T12:18:59.560 に答える
4

私はいつも好んでいます:

 memset(dest, 0, LEN);
 strncpy(dest, src, LEN - 1);

後で修正するアプローチですが、それは実際には好みの問題です。

于 2009-09-21T10:59:04.773 に答える
4

の代わりにstrncpy()、使用できます

snprintf(buffer, BUFFER_SIZE, "%s", src);

size-1以下は、ヌル以外の文字を からsrcにコピーしdest、ヌル ターミネータを追加するワンライナーです。

static inline void cpystr(char *dest, const char *src, size_t size)
{ if(size) while((*dest++ = --size ? *src++ : 0)); }
于 2009-09-21T14:41:41.387 に答える
3

strncpy は、利用可能な文字列バッファーを直接操作します。メモリを直接操作する場合は、バッファー サイズを変更する必要があり、'\0' を手動で設定できます。

単純な C にはこれ以上の代替手段はないと思いますが、生のメモリを扱うときに注意を払う必要がある場合は、それほど悪くはありません。

于 2009-09-21T10:45:31.800 に答える
2

これらの機能は、設計された以上に進化してきたため、「理由」はありません。「方法」を学ぶだけです。残念ながら、少なくとも Linux のマニュアル ページには、これらの関数の一般的なユース ケースの例が欠けており、レビューしたコードに多く の誤用があることに気付きました。ここにいくつかのメモを作成しました: http://www.pixelbeat.org/programming/gcc/string_buffers.html

于 2009-09-21T13:33:52.823 に答える
2

新しい拡張機能に依存することなく、私は過去に次のようなことをしました:

/* copy N "visible" chars, adding a null in the position just beyond them */
#define MSTRNCPY( dst, src, len) ( strncpy( (dst), (src), (len)), (dst)[ (len) ] = '\0')

そしておそらく:

/* pull up to size - 1 "visible" characters into a fixed size buffer of known size */
#define MFBCPY( dst, src) MSTRNCPY( (dst), (src), sizeof( dst) - 1)

新しい「組み込み」(?) 関数の代わりにマクロを使用するのはなぜですか? 以前はかなりの数の異なる unix があり、日常的に C を使用していたときに移植しなければならなかった他の非 UNIX (非 Windows) 環境もありました。

于 2009-09-21T23:04:27.320 に答える