これはthis oneへのフォローアップの質問です。ファイルとバッファのクラスセグメントエラーを見つける
コピーコンストラクタと割り当てコンストラクタをクラスFile
とBuffer
に追加して、ダブルフリーとメモリ破損を修正しました。しかし、そのリモートサーバはセグメンテーションエラーがあると報告します。クラス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スクリプトは、セグメント障害の源ではありません。私はこれを確認することができます。テストサーブが、バグの主なバージョンの多くのバージョンを提供して、File
、Buffer
、およびException
をテストできることに注意してください。
*「セグメント障害は通常スタックに関連していると思います」* - そうですか?何があなたをそう思わせたのですか? – UnholySheep
また、実際にクラッシュを再現できましたか? (例:あなたの実装をテストする 'main'は正確に何をしますか?)はいの場合、それはどこで起こりますか? – UnholySheep
@ UnholySheep私はそのサーバーにアクセスできない。だから正直なところ、私はあなたの質問に答える方法を知らない。私が知っていることは、フォルトインジェクションを使用して自分のコードをテストすることだけです。私はFile、Buffer、Exceptionを実装しています。テストが失敗すると、エラーメグが表示されます。このテストサーバーは、例外的な方法でテストを行っていますが、具体的な指示はありません。 –