2016-11-16 7 views
1

これはthis oneへのフォローアップの質問です。ファイルとバッファのクラスセグメントエラーを見つける

コピーコンストラクタと割り当てコンストラクタをクラスFileBufferに追加して、ダブルフリーとメモリ破損を修正しました。しかし、そのリモートサーバはセグメンテーションエラーがあると報告します。クラスFileまたはBufferセグメント障害を引き起こす方法はありますか?私は、セグメントの障害は通常、スタックに関連していると思う。しかし、私はこれらの2つのクラスにスタック操作を持っていません。

Buffer.h

#ifndef __BUFFER_H__ 
#define __BUFFER_H__ 

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

class Buffer 
{ 

private: 
    char * buffer; 
    int size; 
    Buffer(const Buffer &); 
    Buffer& operator=(const Buffer &); 

public: 
    Buffer(int size); 
    ~Buffer(); 
    void reverse(int size); 


    friend class File; 
}; 

#endif 

Buffer.cc:

#include "Buffer.h" 
#include "Exception.h" 


Buffer::Buffer(int size) 
{ 
    this -> size = size; 
    this -> buffer = (char *)malloc(size); 
    if(this -> buffer == NULL) 
    throw Exception(errno); 
} 

Buffer::~Buffer() 
{ 
    // // if(this -> buffer != NULL) 
    // { 
    free(this -> buffer); 
    // this -> buffer = NULL; 
    // } 
} 

void Buffer::reverse(int size) 
{ 
    char tmp; 
    int i; 
    char * tmpb = this -> buffer; 
    for(i = 0; i < size/2; i++) 
    { 
    tmp = tmpb[i]; 
    tmpb[i] = tmpb[size - i - 1]; 
    // printf("exchange %x with %x\n", tmp & 0xff, tmpb[i] & 0xff); 

    tmpb[size - i - 1] = tmp; 
    } 
} 

ファイル.h:

#ifndef __FILE_H__ 
#define __FILE_H__ 

#include "Buffer.h" 
#include "Exception.h" 
#include <stdio.h> 
#include <cerrno> 

class File 
{ 

private: 
    FILE * f; 
    File(const Buffer &); 
    File& operator=(const File &); 



public: 
    int whence; 
    // Note: opening the same file twice for writing ("w") 
    // at the same time is forbidden 
    File(const char* name, const char *mode); 
    ~File(); 

    int read(Buffer& buffer, int size); 
    void write(Buffer& buffer, int size); 
    void seek(int pos); 
    void close(); 
    // void seek(long offset, int whence); 
    long size(); 
}; 

#endif 

File.cc:

#include "File.h" 


File::File(const char* name, const char *mode) 
{ 
    f = fopen(name, mode); 
    if(f == NULL) 
    throw Exception(errno); 
} 

File::~File() 
{ 
    if(f != NULL) 
    fclose(f); 
} 

int File::read(Buffer& buffer, int size) 
{ 
    clearerr(this -> f); 
    size_t tmp; 
    tmp = fread(buffer.buffer, 1, size, this -> f); 

    // printf("%ld bytes read\n", tmp); 
    // for(int i = 0; i < tmp; i++) 
    // printf("%x ", buffer.buffer[i] & 0xff); 
    // printf("\n"); 

    if(feof(this -> f) != 0) 
    return EOF; 
    if(ferror(this -> f) != 0) 
    throw Exception(errno); 

    return tmp; 
} 

void File::write(Buffer& buffer, int size) 
{ 
    size_t tmp; 
    clearerr(this -> f); 
    tmp = fwrite(buffer.buffer, 1, size, this -> f); 

    // printf("%ld bytes written\n", tmp); 
    // for(int i = 0; i < tmp; i++) 
    // printf("%x ", buffer.buffer[i] & 0xff); 
    // printf("\n"); 

    if(ferror(this -> f) != 0) 
    throw Exception(errno); 
} 

void File::seek(int pos) 
{ 
    int ret = fseek(this -> f, pos, this -> whence); 
    if(ret != 0) 
    throw Exception(errno); 
} 

void File::close() 
{ 
    int tmp; 
    if(this -> f != NULL) 
    tmp = fclose(this -> f); 
    this -> f = NULL; 
    if(tmp != 0) 
    throw Exception(errno); 
} 

long File::size() 
{ 
    if(fseek(this -> f, 0, SEEK_END) != 0) 
    throw Exception(errno); 

    long tmp = ftell(this -> f); 
    if(tmp == -1) 
    throw Exception(errno); 

    if(fseek(this -> f, 0, SEEK_SET) != 0) 
    throw Exception(errno); 
    return tmp; 
} 

注:Cスタイルのコードを使用する必要があります。それ以外の場合は、サーバーテストに失敗します。それは難しい要件です。まあ、あなたはこの要求が馬鹿だと思うかもしれません。しかし、これが要件です。多分、CとC++を混ぜている間に、悪い点を覚えていることがあるかもしれません。

サーバーには、実装をテストするための主な機能があります。 makeを使ってコンパイルするだけです。その結果、rcopyという名前のプログラムがファイルの内容を1バイトずつ反転させて新しいファイルに出力します。ここ

は、詳細なエラー出力である:

make: Entering directory `/home/vmcheck/testhome/co/rcopy' 
g++ -c rcopy.cc 
g++ -c Buffer.cc 
g++ -c Exception.cc 
g++ -c File.cc 
g++ rcopy.o Buffer.o Exception.o File.o -o rcopy 
make: Leaving directory `/home/vmcheck/testhome/co/rcopy' 
======== COMPILING AGAINST OUR TESTS ======== 
g++ -c -Wall -I./ t1.cc -ot1.o 
g++ -ot1 t1.o Buffer.o Exception.o File.o 
g++ -c -Wall -I./ t2.cc -ot2.o 
g++ -ot2 t2.o Buffer.o Exception.o File.o 
g++ -c -Wall -I./ t3.cc -ot3.o 
g++ -ot3 t3.o Buffer.o Exception.o File.o 
g++ -c -Wall -I./ t4.cc -ot4.o 
g++ -ot4 t4.o Buffer.o Exception.o File.o 
g++ -c -Wall -I./ t5.cc -ot5.o 
g++ -ot5 t5.o Buffer.o Exception.o File.o 
g++ -c -Wall -I./ t6.cc -ot6.o 
g++ -ot6 t6.o Buffer.o Exception.o File.o 
g++ -c -Wall -I./ t7.cc -ot7.o 
g++ -ot7 t7.o Buffer.o Exception.o File.o 
g++ -c -Wall -I./ f1.cc -of1.o 
gcc failed_read.c -ldl -shared -fPIC -o failed_read.so 
gcc failed_write.c -ldl -shared -fPIC -o failed_write.so 
failed_write.c:5:7: warning: conflicting types for built-in function ‘fwrite’ [enabled by default] 
g++ -of1 f1.o Buffer.o Exception.o File.o 
g++ -c -Wall -I./ f2.cc -of2.o 
g++ -of2 f2.o Buffer.o Exception.o File.o 

========= TESTING RCOPY ========== 
Run: large file 
size of input file: 16473 
Run: small file 
size of input file: 0 

========= TESTING EXCEPTION BEHAVIOUR ========== 
*** Test 1 *** 
*** Test 2 *** 
*** Test 3 *** 
bash: line 1: 22041 Segmentation fault  ./t3 
FAILED 

bashスクリプトは、セグメント障害の源ではありません。私はこれを確認することができます。テストサーブが、バグの主なバージョンの多くのバージョンを提供して、FileBuffer、およびExceptionをテストできることに注意してください。

+0

*「セグメント障害は通常スタックに関連していると思います」* - そうですか?何があなたをそう思わせたのですか? – UnholySheep

+0

また、実際にクラッシュを再現できましたか? (例:あなたの実装をテストする 'main'は正確に何をしますか?)はいの場合、それはどこで起こりますか? – UnholySheep

+0

@ UnholySheep私はそのサーバーにアクセスできない。だから正直なところ、私はあなたの質問に答える方法を知らない。私が知っていることは、フォルトインジェクションを使用して自分のコードをテストすることだけです。私はFile、Buffer、Exceptionを実装しています。テストが失敗すると、エラーメグが表示されます。このテストサーバーは、例外的な方法でテストを行っていますが、具体的な指示はありません。 –

答えて

1

無効なパラメータで呼び出された場合、可能なクラッシュの原因は、readおよびwriteのメソッドです。例えば、readはサイズ10のバッファで呼び出すことができますが、関数readは20バイトの読み込みを要求されます。この場合、バッファがオーバーフローします。

は、次の2つのソリューションを持っている:いずれかのあなたのバッファクラスはdinamicallyサイズを変更できるように変更するには、あなたは、例えば、バッファの最大サイズまでの書き込み/読み出し:それは同じになり

tmp = fread(buffer.buffer, 1, min(size, buffer.size), this -> f); 

writeの場合

関連する問題