4

私はプロキシサーバーを書いていますが、誰かが説明してくれることを望んでいた奇妙なバグに遭遇しました。

クライアントからGETリクエストの最初の行を受信して​​います。たとえば、クライアントはリクエストを送信します。

GET http://en.wikipedia.org/wiki/Special:Random HTTP/1.0
Host: en.wikipedia.org
...

そして、このリクエストをサーバーに転送します。

ただし、特定のWebアドレスでは、次の問題が発生します。

GET http://map.media6degrees.com/orbserv/curl=http%3A%2F%2Fwww.masteringemacs.org%2Farticles[trunc] HTTP/1.0

char buffer[MAXLINE_LENGTH]この行を、文字列を保持するのに十分な長さのに読み込みます。

受信したgetリクエストを印刷すると

printf(buffer);

印刷される文字列は次のとおりです。

GET http://map.media6degrees.com/orbserv/hbpix?pixId=2869&curl=http0X0.0000000000015P-10220.0000000.000000www.masteringemacs.org0.000000articles0.00000020100.000000110.000000010.000000running-shells-in-emacs-overview204741995430849962482228271154502456423284733956118041206315879167624419264810411254941012469231829496710329852458403099883653794777355548418601638730167027236864.000000 HTTP/1.0

%3A、%​​2Fなどは文字列形式になっているようです。

実行するprintf("%s", buffer);と、正しい期待される出力が得られます

編集:私はこれが起こっている理由を理解しています。なぜこれがこのように起こっているのか興味があります。printfが「文字列フォーマット」であるという値は、スタック上の任意の領域からのものですか?%3A et alは有効なフォーマット文字列ですか?

4

4 に答える 4

7

1)関数プロトタイプを見ると、printf()がフォーマット文字列と0個以上の引数を期待していることがわかります。したがって、厳密に言えば、「printf(string)」は正しくありません。

SYNOPSIS
       #include <stdio.h>

       int printf(const char *format, ...);
       int fprintf(FILE *stream, const char *format, ...);
       int sprintf(char *str, const char *format, ...);
       int snprintf(char *str, size_t size, const  char  *format,
       ...);

2)最初の引数フォーマット文字列として解釈され、見つかった「%XXX」エントリはプレースホルダーとして解釈されます。それがどのように聞こえるかはまさに起こっていることです:)

3)もちろん、解決策はprintf ("%s", string)

4)またはputs(string)代わりに使用します:)

于 2012-12-03T21:33:36.827 に答える
5

printfのフォーマットパラメータとして入力文字列を使用しないでください。

正しく機能するには、「%...」項目が含まれていてはなりません。これらは、パラメータリストにアクセスするためのprintf()関数への特別なコマンドです。

于 2012-12-03T21:32:10.597 に答える
1

および関数ファミリーの引数formatでは、エスケープ文字として扱われます。あなたの生の入力にはそれらのいくつかがあり、それらを解釈しようとしています。printfscanf%printf

于 2012-12-03T21:33:06.357 に答える
0

printf(string)を使用する場合、出力される文字列はNULLになる可能性があります。
これが私がこれで目にする唯一の問題です。printf関数は提供された形式に従ってすべてのva_list引数を読み取るため、NULLポインターを渡すとクラッシュする可能性があります。LLVM 4.1では、次の警告が表示されます。

Format string is not a literal string (potentially insecure)

これは私の個人的な意見です:文字列がNULLでないことが確実な場合(おそらくアサーションを介して検証し、リリースでそのアサーションを削除する)、printf(string)を使用できます。文字列がNULLまたは無効である可能性があることを確認してから、リテラル文字列を使用してください。

于 2012-12-03T22:15:05.773 に答える