Ошибка сегментации при форсировании :: multi_array - PullRequest
1 голос
/ 04 ноября 2011

Следующий код дает ошибку сегментации:

#include <iostream>
#include <fstream>
#include "binItr.h"
#include <boost/multi_array.hpp>

using namespace std;

int main(){
   const char * xifile = "results/feretxiG1155V0P5T231K10.bin";

   const uint pSize = 5;
   const uint T = 231;

   ifstream xiFileId(xifile, ios::binary);

   typedef boost::multi_array<uint, 2> array_type;
   array_type xi(boost::extents[T][pSize + 1]);

   //the ii_t class in the following line is taken from /1331861/c-dvoichnyi-fail-vvoda-vyvoda-v-iz-konteinerov-krome-char-s-ispolzovaniem-algoritmov-stl written by http://stackoverflow.com/users/14065/loki-astari

   ii_t<uint> xi_in(xiFileId);

   copy(xi_in, ii_t<uint>(), xi.data());
   return 0;
}

Входной двоичный файл содержит данные unsigned int, а его размер, сообщенный ls -l, равен 231 * (5 + 1) 4 = 5544 байта. Я попытался прочитать файл и сохранить данные в векторе и обнаружил, что размер вектора равен 231 (5 + 1) = 1386. Анализ файла ядра с помощью gdb дает следующий вывод.

    Program terminated with signal 6, Aborted.

    #0  0x00007fb71130ea75 in raise (sig=<value optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
64   ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
   in ../nptl/sysdeps/unix/sysv/linux/raise.c

    (gdb) bt
    #0  0x00007fb71130ea75 in raise (sig=<value optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
    #1  0x00007fb7113125c0 in abort () at abort.c:92
    #2  0x00007fb7113484fb in __libc_message (do_abort=<value optimized out>, fmt=<value optimized out>) at ../sysdeps/unix/sysv/linux/libc_fatal.c:189
    #3  0x00007fb7113525b6 in malloc_printerr (action=3, str=0x7fb711425cd8 "double free or corruption (!prev)", ptr=<value optimized out>) at malloc.c:6266
    #4  0x00007fb711358e83 in __libc_free (mem=<value optimized out>) at malloc.c:3738
    #5  0x00000000004018c4 in __gnu_cxx::new_allocator<unsigned int>::deallocate (this=0x7fffc618d2f8, __p=0x2295290) at /usr/include/c++/4.4/ext/new_allocator.h:95
    #6  0x000000000040152f in boost::multi_array<unsigned int, 2ul, std::allocator<unsigned int> >::deallocate_space (this=0x7fffc618d290) at /usr/include/boost/multi_array.hpp:484
    #7  0x0000000000401077 in boost::multi_array<unsigned int, 2ul, std::allocator<unsigned int> >::~multi_array (this=0x7fffc618d290, __in_chrg=<value optimized out>) at /usr/include/boost/multi_array.hpp:468
    #8  0x0000000000400d4e in main () at segTest.cpp:30

Есть предложения? Спасибо.

1 Ответ

2 голосов
/ 04 ноября 2011

Проблема в том, что ii_t<> входной класс итератора из указанного SO-ответа «читает» слишком много элементов, потому что обернутый istream не возвращает EOF до разыменованияитератора после того, который возвратил последний элемент в файле.Дополнительный возвращаемый элемент данных повреждает выделенный блок памяти в объекте multi_array.

Если вы измените класс ii_t<> на следующий, вы должны получить более совершенное поведение:

template<typename T>
struct ii_t: public iterator<input_iterator_tag, void, void, void, void>
{
  ii_t(std::istream& str)
    :m_str(&str)
  {}
  ii_t()
    :m_str(NULL)
  {}
  ii_t& operator++()   {return *this;}  // increment does nothing.
  ii_t& operator++(int){return *this;}
  T& operator*()
  {
    // On the de-reference we actuall read the data into a local //// static ////
    // Thus we can return a reference
    static T result;
    m_str->read(reinterpret_cast<char*>(&result),sizeof(T));
    return result;
  }
  // If either iterator has a NULL pointer then it is the end() of stream iterator.
  // Input iterators are only equal if they have read past the end of stream.
  bool operator!=(ii_t const& rhs)
  {
      // we need to make sure we're not just about to hit EOF
      // if we already haven't
      if (m_str && m_str->good()) {
        char dummy;
        m_str->read(&dummy,1);
        if (m_str->good()) {
            m_str->putback(dummy);
        }
      }

      if (rhs.m_str && rhs.m_str->good()) {
        char dummy;
        rhs.m_str->read(&dummy,1);
        if (rhs.m_str->good()) {
            rhs.m_str->putback(dummy);
        }
      }

      bool lhsPastEnd  = (m_str == NULL)     || (!m_str->good());
      bool rhsPastEnd  = (rhs.m_str == NULL) || (!rhs.m_str->good());

      return !(lhsPastEnd && rhsPastEnd);
  } 

  private:
    std::istream*   m_str;
};

Соответствующие изменения внесены в функцию bool operator!=(ii_t const& rhs), где при необходимости выполняется фиктивное чтение (затем отменяется) для обернутого istream, чтобы определить, находится ли istream в EOF.

Обратите внимание, чтоЯ не утверждаю, что это лучший способ справиться с ситуацией EOF, но, похоже, он работает.

...