2

The following code gives a segmentation fault:

#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 http://stackoverflow.com/questions/1855704/c-binary-file-i-o-to-from-containers-other-than-char-using-stl-algorithms 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;
}

The input binary file contains unsigned int data and its size as reported by ls -l is 231*(5+1)4 = 5544 bytes. I tried reading the file and storing the data in a vector and found that vector size is 231(5+1) = 1386. Analysis of the core file using gdb gives the following output.

    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

Any suggestions? Thanks.

8
  • Nothing seems wrong as far as I can see, but can you give more information about ii_t? Also, have you tried running it through valgrind? Commented Nov 4, 2011 at 4:28
  • I had tried valgrind and it didnt mention any memory leaks. ii_t is from stackoverflow.com/questions/1855704/…. Finally I solved the problem by not using ii_t :) Commented Nov 4, 2011 at 4:55
  • If you comment out the copy() line, does it still segfault? Commented Nov 4, 2011 at 4:57
  • @fileoffset yea, you are right. It was coming from copy - but because of the ii_t class. When I removed it - the seg fault vanished - though it took so much of my time :) Commented Nov 4, 2011 at 4:58
  • OK. Michael seems to have fixed the problem. BUT this ii_t class is not designed to read complex classes like boost::multi_array<uint, 2>. Complex classes have constructors and this iterator writes over the object using read(). This destroys the original content. This class is only designed for use with POD types (ie anything that does not have constructor and if a structure non of its members have constructors). Commented Nov 4, 2011 at 15:38

1 Answer 1

2

The problem is that the ii_t<> input iterator class from the referred SO answer is 'reading' one too many items because the wrapped istream doesn't return EOF until the the dereference of the iterator after the one that returned the last item in the file. The extra returned data item is corrupting the allocated memory block in the multi_array object.

If you change the ii_t<> class to the following, you should get better behavior:

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

The relevant changes are in the bool operator!=(ii_t const& rhs) function, where, if necessary, a dummy read is performed (then undone) on the wrapped istream to determine if the istream is at the EOF.

Note that I'm making no claim that this is the best technique to handle the EOF situation, but it seems to work.

Sign up to request clarification or add additional context in comments.

5 Comments

Thank you so much. Verified that the segmentation violation is not present now.
OK. I see the problem. The std::copy is going to check the state of the stream after the ++ operation. But because this does nothing it will always be true. Thus when you the de-reference it (and it fails) it has no way to know that it has gone wrong and therefore the object used is now a copy of the last object.
In this case we now have two array object that are using the same internal buffer. This leaves the user code open to double delete and other problems associated with a shared buffer. So as noted above on the OP question ii_t is not designed to work with non POD types. (NOTE: this does not change the fact the Michael has fixed the code for the POD type).
@Loki: I don't think the problem is a user error - it's that after the last item is read from the file, EOF hasn't been set, so the iterator doesn't compare equal to the 'empty' iterator. That indicates that another dereferece is OK - but the read for that deref will return EOF instead of data (so the static T result is left unchanged). I don't think what I've added to ii_t is the best way to handle this, but it seemed easiest without completely changing ii_t.
@Michael Burr: You are correct. I just needed some time to analyses the usage (and have deleted that comment). Your fix is good. ;-(

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.