与文件i/o相关的c++程序末尾的Segfault

Segfault at end of c++ program related to file i/o

本文关键字:c++ 程序 Segfault 文件      更新时间:2023-10-16

我正在进行一个密码学项目,我们的密码需要能够读取和写入文件。我的一个合作伙伴实现了阅读功能,现在我们遇到了一个奇怪的问题。如果用户没有提供输出文件,我们的程序会正确运行,没有错误,但如果提供了输出文件,则会在完成后(返回0)出现segfault。然而,程序只在我的机器上出现故障。我的团队成员运行的是OS X和Fedora,而我运行的是Ubuntu,如果这很重要的话。我们所有人都在使用c++11进行编译,尽管我在技术上指定了c++0x。

int main(int argc, char** argv)
 {
   std::string usageWarning =  "usage: [-i/--input fileName] [-o/--output fileName] 
   [-        k/--key 32bitKey] [-n/--nonce numEncryptions]";
   int nonce = 1;
   std::string inputFile;
   std::string outputFile;
   std::string key;
   bool hasInputFile = false;
   bool hasOutputFile = false;    
   bool hasKey = false;
   std::ofstream out;
   if (argc < 2) {
    std::cerr << usageWarning << std::endl;
    return 1;
   }
  //Parse command line input
  for( int i = 1; i < argc; i++ ) {
    if (0 == strncmp(argv[i], "-n", 2) || 0 == strncmp(argv[i], "--nonce", 7)) {
      i = i + 1;
      nonce = std::stof(argv[i]);
    }
    else if (0 == strncmp(argv[i], "-i", 2) || 0 == strncmp(argv[i], "--input", 7)) {
      i = i + 1;
      inputFile = argv[i];
      hasInputFile = true;
    }
    else if (0 == strncmp(argv[i], "-o", 2) || 0 == strncmp(argv[i], "--output", 8)) {
      i = i + 1;
      outputFile = argv[i];
      out.open(outputFile);
      std::streambuf *coutbuf = std::cout.rdbuf(); //save old buf
      std::cout.rdbuf(out.rdbuf()); 
      hasOutputFile = true;
    }
    else if (0 == strncmp(argv[i], "-k", 2) || 0 == strncmp(argv[i], "--key", 5)) {
      i = i + 1;
      key = argv[i];
      hasKey = true;
    }
    else {
      std::cerr << "Unrecognized option." << std::endl;
      std::cerr << usageWarning << std::endl;
      return 1;
    }
  }
  Serpent serpent; 
  unsigned char testKey[] = {0x00, 0x00, 0x00, 0x00, 
                0x00, 0x00, 0x00, 0x00, 
                0x00, 0x00, 0x00, 0x00, 
                0x00, 0x00, 0x00, 0x00};
  unsigned char plaintext[16] = 
   {0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00};
 if (hasKey) {
   unsigned char new_key[32];
   int index = 0;
   for (int i = 0; i < key.length() - 2; i++) {
     std::stringstream ss;
     ss << std::hex << key[i] << key[i+1];
     int n;
     ss >> n;
     unsigned char x = (unsigned char)n;
     new_key[index] = x;
     index += 1;
     i += 1;
   }
   memcpy(testKey, new_key, sizeof(testKey));
 }
 if (hasInputFile) {
    unsigned char new_plaintext[16];
    std::ifstream in(inputFile);
    unsigned char  x;
    int index = 0;
    std::string temp_string = "";
    while (in >> std::noskipws >> x) {
      std::cout << "X: " << std::hex << x << std::endl;
      temp_string += x;
      if (temp_string.length() == 2) {
        std::stringstream ss;
        ss << std::hex << temp_string;
        int n = 0;
        ss >> n;
        unsigned char y = (unsigned char)n;
        new_plaintext[index] = y;
        index += 1;
        temp_string = "";
      }
    }
   // Set plaintext to be theplaintext we read in from file
    memcpy(plaintext, new_plaintext, sizeof(plaintext));  
 }
 else {
 }

  serpent.setKeySize(sizeof(testKey)/sizeof(*testKey));
  serpent.setKey(testKey);
  serpent.generateSubKeys();
  std::cout << "TESTING" << std::endl;
  int encryptionRound = 0;

  while (encryptionRound < nonce) {
    std::cout << std::dec << "================================ ROUND <<
    encryptionRound << " ================================n" << std::endl;
    serpent.encrypt(plaintext);
    std::cout << std::dec << "============================ END ROUND " << 
    encryptionRound     << " ============================n"<< std::endl;
    encryptionRound++;
  }

 if (hasOutputFile){
    out.close();
  }

 return 0;
 }

我运行了Valgrind并得到了以下输出,但我对io业务非常缺乏经验,不知道该如何处理这些信息。

==3131== Memcheck, a memory error detector
==3131== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==3131== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==3131== Command: ./SerpentOpt -n 1 -o output.txt
==3131== 
==3131== Invalid read of size 8
==3131==    at 0x4EC7328: std::ostream::flush() (in /usr/lib/x86_64-
linux gnu/libstdc++.so.6.0.16)
==3131==    by 0x4E97F9B: std::ios_base::Init::~Init() (in /usr/lib/x86_64-linux- 
gnu/libstdc++.so.6.0.16)
==3131==    by 0x5385900: __run_exit_handlers (exit.c:78)
==3131==    by 0x5385984: exit (exit.c:100)
==3131==    by 0x536B773: (below main) (libc-start.c:258)
==3131==  Address 0x7fefffd88 is just below the stack ptr.  To suppress, use: --   
workaround-gcc296-bugs=yes
==3131== 
==3131== 
==3131== Process terminating with default action of signal 11 (SIGSEGV)
==3131==  Bad permissions for mapped region at address 0x4224580
==3131==    at 0x4224580: ??? (in /lib/x86_64-linux-gnu/ld-2.15.so)
==3131==    by 0x4EC732D: std::ostream::flush() (in /usr/lib/x86_64-linux-  
gnu/libstdc++.so.6.0.16)
==3131==    by 0x4E97F9B: std::ios_base::Init::~Init() (in /usr/lib/x86_64-linux-   
gnu/libstdc++.so.6.0.16)
==3131==    by 0x5385900: __run_exit_handlers (exit.c:78)
==3131==    by 0x5385984: exit (exit.c:100)
==3131==    by 0x536B773: (below main) (libc-start.c:258)
==3131== 
==3131== HEAP SUMMARY:
==3131==     in use at exit: 0 bytes in 0 blocks
==3131==   total heap usage: 10,745 allocs, 10,745 frees, 493,629 bytes allocated
==3131== 
==3131== All heap blocks were freed -- no leaks are possible
==3131== 
==3131== For counts of detected and suppressed errors, rerun with: -v
==3131== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

感谢您的帮助!

这是你给自己带来悲伤的地方:

  out.open(outputFile);
  std::streambuf *coutbuf = std::cout.rdbuf(); //save old buf
  std::cout.rdbuf(out.rdbuf()); 

现在有两个对象都指向同一个buf。猜猜一个对象被破坏并清理了它的资源,然后第二个对象开始执行析构函数后会发生什么。