質問
Cプログラムで私を困惑させているので、これに関していくらか助けが必要です
2つの文字列(ベースとパス)があります
BASE: /home/steve/cps730
PATH: /page2.html
これは、sprintfを呼び出してコンテンツを結合する直前にprintfが読み取る方法です。ここにコードブロックがあります
int memory_alloc = strlen(filepath)+1;
memory_alloc += strlen(BASE_DIR)+1;
printf("\n\nAlloc: %d",memory_alloc);
char *input = (char*)malloc(memory_alloc+9000);
printf("\n\nBASE: %s\nPATH: %s\n\n",BASE_DIR,filepath);
sprintf(input, "%s%s",BASE_DIR,filepath); // :(
printf("\n\nPATH: %s\n\n",input);
では、最後のprintfステートメントがどのように戻るかを説明できますか
PATH: e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/stev
まったく理解できないため。
**プログラムのクラッシュを防ぐためにmallocステートメントに9000を追加しました(文字列のサイズが明らかに31バイトより大きいためです。
フル出力
Alloc: 31
BASE: /home/steve/cps730
PATH: /page2.html
PATH: /home/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/stev
Sending:
HTTP/1.0 404 Not Found
Date: Sat, 12 Sep 2009 19:01:53 GMT
Connection: close
編集...................これらの変数を使用するすべてのコード
const char *BASE_DIR = "/home/steve/cps730";
char* handleHeader(char *header){
//Method given by browser (will only take GET, POST, and HEAD)
char *method;
method = (char*)malloc(strlen(header)+1);
strcpy(method,header);
method = strtok(method," ");
if(!strcmp(method,"GET")){
char *path = strtok(NULL," ");
if(!strcmp(path,"/")){
path = (char*)malloc(strlen(BASE_DIR)+1+12);
strcpy(path,"/index.html");
}
free(method);
return readPage(path);
}
else if(!strcmp(method,"POST")){
}
else if(!strcmp(method,"HEAD")){
}
else{
strcat(contents,"HTTP/1.1 501 Not Implemented\n");
strcat(contents, "Date: Sat, 12 Sep 2009 19:01:53 GMT\n");
strcat(contents, "Connection: close\n\n");
}
free(method);
}
//Return the contents of an HTML file
char* readPage(char* filepath){
int memory_alloc = strlen(filepath)+1;
memory_alloc += strlen(BASE_DIR)+1;
printf("\n\nAlloc: %d",memory_alloc);
char *input = (char*)malloc(memory_alloc+9000);
printf("\n\nBASE: %s\nPATH: %s\n\n",BASE_DIR,filepath);
sprintf(input, "%s%s\0",BASE_DIR,filepath);
printf("\n\nPATH: %s\n\n",input);
FILE *file;
file = fopen(input, "r");
char temp[255];
strcat(contents,"");
if(file){
strcat(contents, "HTTP/1.1 200 OK\n");
strcat(contents, "Date: Sat, 12 Sep 2009 19:01:53 GMT\n");
strcat(contents, "Content-Type: text/html; charset=utf-8\n");
strcat(contents, "Connection: close\n\n");
//Read the requested file line by line
while(fgets(temp, 255, file)!=NULL) {
strcat(contents, temp);
}
}
else{
strcat(contents, "HTTP/1.0 404 Not Found\n");
strcat(contents, "Date: Sat, 12 Sep 2009 19:01:53 GMT\n");
strcat(contents, "Connection: close\n\n");
}
return contents;
}
解決
無効なポインタreadPage
を使用してpath
を呼び出します。これは、method
の呼び出しの直前に解放されるmalloc
ポインタで以前に割り当てられたメモリを指します。次の<=>はこのメモリを再利用でき、その後は何でも起こります...
他のヒント
まあ、明らかにこれは起こりえません:-)
あなたのヒープはすでに恐ろしく破損しています。
ファイルパス、入力、ベースで使用される実際のポインタ値を確認します。入力がファイルパスに非常に近いことに気付くでしょうか?
ファイルパス、ベースなどが最初にどのように作成されたのかも見てみますが、そこにバッファオーバーランがありますか?
このコードを試してください:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
const char* BASE_DIR = "/home/steve/cps730";
const char* filepath = "/page2.html";
int memory_alloc = strlen(filepath);
memory_alloc += strlen(BASE_DIR)+1;
printf("\n\nAlloc: %d",memory_alloc);
char *input = (char*)malloc(memory_alloc);
printf("\n\nBASE: %s\nPATH: %s\n\n",BASE_DIR,filepath);
sprintf(input, "%s%s",BASE_DIR,filepath); // :(
printf("\n\nPATH: %s\n\n",input);
return 0;
}
これに問題がない場合は、コードのどこかに間違っている必要があります。これは、未定義の動作が時々現れることです(無関係なコードの動作を台無しにします)。
(ところで、連結された文字列にはヌルターミネータが1つしか含まれないため、両方のstrlen呼び出しに+1を追加しませんでした。)
BASE_DIR
の値が繰り返されているため、filepath
またはinput
がsprintf
メモリ内で重複している可能性があります。
<=>と<=>の両方が実際にメモリを割り当てていることを確認してください。
最初の試みは、<=>と<=>のローカルコピーを作成してから<=>を呼び出すことです。
Aaah-問題を解決しようとしている間に、質問が変化するという追跡のスリル!
現在のコードは次のようになります:
const char *BASE_DIR = "/home/steve/cps730";
//Handles the header sent by the browser
char* handleHeader(char *header){
//Method given by browser (will only take GET, POST, and HEAD)
char *method;
method = (char*)malloc(strlen(header)+1);
strcpy(method,header);
method = strtok(method," ");
if(!strcmp(method,"GET")){
char *path = strtok(NULL," ");
if(!strcmp(path,"/")){
path = (char*)malloc(strlen(BASE_DIR)+1+12);
strcpy(path,"/index.html");
}
free(method);
return readPage(path);
}
...
質問:これがWebサーバーで実行されている場合、スレッド安全でない関数strtok()
を使用しても安全ですか?私は「はい、それは安全です」と仮定しますが、完全には納得していません。 header
文字列を印刷しましたか? path
の値を印刷しましたか?割り当てられたmalloc() + strcpy()
を本当にリークするつもりでしたか? BASE_DIR
シーケンスがinput
をfilepath
にコピーしないことに気付きましたか?
コードの元のバージョンは次で終了しました:
printf("\n\nPATH: %s\n\n", filepath);
したがって、元の提案された部分的な答え:
から印刷します
sprintf()
にフォーマットします。malloc()
?
(char *)
がすでに解放されたメモリを指している可能性はどのくらいですか?メモリを割り当てると、<=>が指すために使用された準ランダム領域で何が起こっているかもしれません。別の可能性は、<=>が返された関数のローカル変数へのポインターである可能性があります。したがって、<=>などの他のコードで再利用されているスタック内のランダムな場所を指します。
また、コメントで<=>が宣言されていることを確認し、その戻り値を確認する必要があるかもしれないと述べました。 '<=>'キャストはCでは必須ではなく(C ++で行われます)、多くの場合、コードが厳密にCであり、CおよびC ++でバイリンガルでない場合はキャストを含めません。
このコードは私のために機能します:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
const char *BASE_DIR = "/home/steve/cps730";
const char *filepath = "/page2.html";
int memory_alloc = strlen(filepath) + 1;
memory_alloc += strlen(BASE_DIR) + 1;
printf("\n\nAlloc: %d", memory_alloc);
char *input = (char*)malloc(memory_alloc + 9000);
printf("\n\nBASE: %s\nPATH: %s\n\n", BASE_DIR, filepath);
sprintf(input, "%s%s", BASE_DIR, filepath);
printf("\n\nPATH: %s\n\n", filepath);
printf("\n\nPATH: %s\n\n", input);
return(0);
}
余分な空行を生成します:
Alloc: 31
BASE: /home/steve/cps730
PATH: /page2.html
PATH: /page2.html
PATH: /home/steve/cps730/page2.html
何が起こっているかを把握する最も簡単な方法は、デバッガーで実行をトレースすることです(アセンブリコードのトレースにドロップする可能性があります)。
何が起こっているかについてのいくつかの推測:
- 別のスレッドによるメモリ破損(これが容易に再現可能な場合は考えにくい)
- ヒープの破損(
malloc()
呼び出し後に2つのコンポーネント文字列をダンプするため、起こりそうもないようです) - Jonathan Lefflerがコメントで述べたように、ヘッダーが欠落している可能性があり(おそらく
stdio.h
)、コンパイラーはprintf
/sprintf
呼び出しに対して誤った呼び出し/ stackクリーンアップシーケンスを生成しています。これが当てはまる場合は、コンパイル時に警告が表示されることを期待します-注意する必要があります。
使用しているコンパイラ/ターゲットは何ですか?
これを正しく行うには、コードを次のように変更します。
/* CHANGED: allocate additional space for "index.html" */
method = (char*)malloc(strlen(header)+1+10);
strcpy(method,header);
method = strtok(method," ");
if(!strcmp(method,"GET")){
char *path = strtok(NULL," ");
if(!strcmp(path,"/")){
/* CHANGED: don't allocate new memory, use previously allocated */
strcpy(path,"/index.html");
}
/* CHANGED: call function first and free memory _after_ the call */
char *result = readPage(path);
free(method);
return result;
}
提案
プログラムに明らかに問題はありません。 ( 更新: 今、明らかなことがあります。最初の1時間は数行しか投稿されておらず、重大なバグはありませんでした。 )さらに投稿する必要があります。以下にいくつかのアイデアを示します。
-
malloc(3)
はvoid *
を返すため、キャストする必要はありません。警告が表示されている場合は、<stdlib.h>
を含めなかったことを意味します。そうでない場合は、する必要があります。 (たとえば、64ビットシステムでは、gcc
のプロトタイプを作成しないことは非常に深刻です。64ビット環境の中には、K <!> amp; RCを実際にサポートしないものがあります:-) - 警告については、すべての警告をオンにしていることを確認してください。
-Wall
を使用すると、<=>でほとんどの機能を有効にできます。 - エラーの<=>の戻り値をチェックしていません。
-
.org / wiki / Electric_Fence "rel =" nofollow noreferrer ">電気フェンス 。多くの選択肢があります。私のリンクをご覧ください。