c++ - 在类 File 和 Buffer 中查找段错误

标签 c++

这是 this one 的后续问题.

我通过向类 FileBuffer 添加复制构造函数和赋值构造函数来修复双重释放和内存损坏。但是该远程服务器报告存在段错误。有没有办法导致类 FileBuffer 段错误?我认为段错误通常与堆栈有关。但是我在这两个类中没有堆栈操作。

缓冲区.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

缓冲区.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

文件.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 脚本不是段错误的来源。我可以证实这一点。注意到测试服务可以提供许多不同版本的 buggy main 来测试 FileBufferException

最佳答案

当使用无效参数调用时,readwrite 方法可能会导致崩溃。例如,可以使用大小为 10 的缓冲区调用 read,但请求函数 read 读取 20 个字节。在这种情况下,您的缓冲区将溢出。

您有两个解决方案:要么更改缓冲区类以动态调整大小,要么读取/写入缓冲区的最大大小,例如:

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

write 也是如此。

关于c++ - 在类 File 和 Buffer 中查找段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40634551/

相关文章:

c++ - 具有重载运算符的无效操作数 <<

c++ - 删除 OpenCV 中的匹配项(关键点和描述符)

C++ 和 CMake : configure a template class from file

c++ - undefined reference (g++ 静态库编译)

c++ - operator new 已经有一个主体

c++ - 类中的 std::function 初始化

C++ 在循环中捕获异常并在循环结束后重新抛出?

c++ - 无法将创建的 .so 文件链接到 main.cpp

c++ - delete 和 delete [] 在 Visual C++ 中是否相同?

c++ - 为什么不需要导出模板类?