0

バッファを扱うときにstrcpyが安全ではないことは知っていますが、私のコードではこれを持っています

static char    buf[HUGE_BUFFER_SIZE + 1];
char servername[200];
int length = 0;
char *out = NULL;
        length = strlen(buf);
        out = alloca(strlen(servername) + length + 5);
        length = strlen(servername);
        strcpy(out, servername);
        out[length] = ' ';
        out[length + 1] = 0;
        strcat(out, buf);

strcpy を strlcpy に変更し、arg3 に sizeof を使用すると、出力が文字化けします。memcpy を使用するよりも簡単な方法はありますか (私がしなければならないように見えますか?)。関数と strnlens/alloca のコピーを減らして上記を達成する簡単な方法はありますか?

4

3 に答える 3

2

使用する方が簡単かもしれませんsnprintf()

char out[1000];  // Or however large you need.
int len = snprintf(out, sizeof(out), "%s %s", servername, buf);
if (len >= sizeof(out)) {
    // Result would have overflowed the buffer and has been truncated.
}

条件付きでは>=なく注意してください。>

snprintf()書き込まれたテキストの長さを返します。終了ヌルバイトは含まれません。したがって、戻り値がバッファサイズと等しい場合、それは最後の文字が切り捨てられたことを意味します(snprintf()結果の文字列は常にnullで終了するため)。

于 2012-09-27T03:39:51.173 に答える
1

私はこのようにします:

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

#define HUGE_BUFFER_SIZE 4096

int main (int argc, char **argv) {
  static char buf[HUGE_BUFFER_SIZE + 1];
  char servername[200];
  int target_len, servername_len, buf_len = 0;
  char *out = NULL;

  strcpy(buf, "this is my test buffer!");
  strcpy(servername, "127.0.0.1");

  /* Notice the uses of strnlen.  Each of these fixes the maximum number of characters that will be scanned. */
  servername_len = strnlen(servername, HUGE_BUFFER_SIZE+1) + 1;
  buf_len = strnlen(buf, 200) + 4;
  target_len = servername_len, buf_len;

  if ((out = alloca(target_len)) == NULL)
    return EXIT_FAILURE; /* alloc failed, die quickly! */

  /* At this point, you've measured the length of servername and buf using strlen, so it should really be impossible to run beyond the length of your buffer, but we're going to be careful, anyway */
  out[0] = '\0';
  strncat(out, servername, servername_len);
  strncat(out, buf, buf_len);

  printf("%s\n", out);

  return EXIT_SUCCESS;
}

(コピー/貼り付けエラー、またはシステム上のさまざまなライブラリと私の側のクロスプラットフォームの混乱を除けば、これをファイルに貼り付け、コンパイルして実行できるはずです。「127.0.0.1thisis私のテストバッファ!」を出力として)

strcpy、strcat、strncpy、strlcpyのいずれの場合でも、すべてのstr関数は、作成する文字列の末尾にnullターミネータをドロップすることに注意してください。手動でnullターミネータを設定する必要があるのは、「out [0] ='\ 0'」というステートメントで行ったように、まったく新しい文字列を開始するときだけです。

また、strlcatではなくstrnlenとstrncatを使用したことに注意してください。関数が何を返すかを除いて、strlcatとstrncatの違いはドキュメントからわかりません。

とにかく、バッファオーバーランのセキュリティホールがすべての関数呼び出しを明確に制限することを回避できるはずです。strncpyとstrncatは、コピーするデータの量を制限します。strnlenは、システムが「\0」を検索する期間を制限します。


編集:私の元のソリューションには、valgrindが明らかにしたエラーが実際にありました。私はbufもservernameも初期化していませんでした。他の何かが魔法のようにbufを初期化しているように見えましたが、valgrindは、サーバー名をターゲットとしてstrcatを呼び出すと、初期化されていないデータに基づいて決定が下されると報告しました。 doh

変数を文字列リテラルで初期化するためにstrcatを呼び出した理由がわからないため、strcpyに切り替えました。もちろん、変数にコピーしている文字列を正確にアプリケーションにハードコーディングしているので、ここでは完全に安全です。

于 2012-09-27T04:00:53.983 に答える
0

出力が文字化けしている必要がある理由は、sizeofを使用している可能性があるためだと思いますout。ただし、outはバッファではなくポインタであるため、3番目の引数のサイズとして4(またはポインタのサイズ)のみを効率的に渡すことができます。3文字を超えてコピーしないことで、残りは初期化されません。ごみを表示するメモリ

strncpyを使用して、コピーする長さを3番目の引数として渡すことができます。

于 2012-09-27T03:34:12.953 に答える