2016-11-16 17 views
1

這是對this one的後續問題。在文件和緩衝區中找到段錯誤

我通過向類FileBuffer添加了拷貝構造函數和賦值構造函數來修復了雙重空閒和內存損壞。但是那個遠程服務器報告存在分段錯誤。有什麼辦法可以導致類FileBuffer段錯誤?我認爲段故障通常與堆棧有關。但是我沒有在這兩個類中進行堆棧操作。

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; 
    } 
} 

File.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的程序,該程序逐字節地反轉文件的內容,然後輸出到新文件。

下面是詳細的錯誤輸出:

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,BufferException

+0

*「我認爲段錯誤通常與堆棧相關」* - 呃,不是?什麼讓你有那個想法? – UnholySheep

+0

另外,你真的能夠重現崩潰? (例如:測試你的實現的'main'究竟做了什麼?)如果是,它會發生在哪裏? – UnholySheep

+0

@UnholySheep我沒有訪問該服務器。所以老實說,我不知道如何回答你的問題。我所知道的是它使用故障注入來測試我的代碼。它編譯各種主程序,包括我的文件,緩衝區和異常的實現。如果測試失敗,它會給我一些錯誤megs。該測試服務器專門針對特殊的hehaviours進行測試,但沒有具體的指令告訴我測試中究竟是什麼。 –

回答

1

當使用無效參數調用時,可能的崩潰源是readwrite方法。例如,read可以用一個大小爲10的緩衝區調用,但函數read被請求讀取20個字節。在這種情況下,你會溢出你的緩衝區。

你有兩個解決方案:要麼你改變你的緩衝區類能夠dinamically調整,無論你讀/寫到緩衝區的最大尺寸,例如:

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

它去同爲write