Boost logo

Boost Users :

Subject: [Boost-users] seg fault on windows with Boost threads, istringstream, mingw
From: Tod Courtney (tcourtney_at_[hidden])
Date: 2009-01-29 14:49:53


Hi

I am working on a multithreaded application for linux and windows using
Boost threads. For windows, we have been developing with MinGW G++
3.4.4 (packaged in cygwin). My application uses a producer-consumer
model where one thread produces tasks definitions and multiple worker
threads complete the tasks.

I discovered that our application runs fine on linux but crashes with a
SIGSEGV fault on windows, at least when compiled with MinGW. When
compiling the same application with MSVC it works fine.

The SIGSEGV crash is not always in the exact same place in the code, but
is very likely to occur -- it happens 99% of the time when there are 3
or more worker threads. The code runs fine if there is only 1 worker
thread. If I try to use the debugger to get a stack trace, I find the
stack is corrupted so I can not see the method or source code lines that
caused the crash.

I have tried boost 1.36 and 1.37. I have tried MinGW g++ 3.4.4 (from
cygwin), 3.4.5 (main release) and 4.3 (alpha). I get the same results
in all cases. I have added the -mthreads flag to the compile and link
options for my application.

I believe the problem is related to this code, which uses a
istringstream to convert a string to a basic type (say a double):

template <typename T>
bool FromString(T &t,const std::string &s,
                std::ios_base &(*f)(std::ios_base &)=std::dec) {
    std::istringstream iss(s);
    return !(iss >> f >> t).fail();
}

The istringstream object is local to the conversion function, and each
istringstream is unique for each thread. So I wouldn't expect a
thread-related problem, unless istringstream has internal state stored
in static variables. However, if I replace that code with equivalent
calls to C-lib functions like 'atof', the problem goes away.

I have attached a test application, along with the makefile I use to
build it, that demonstrates this problem. This test application fails
for with a SIGSEGV when run with MinGW GCC 3.4.4 (from cygwin), MinGW
3.4.5 (current MinGW release) or MinGW GCC 4.3 alpha. It works fine
when I compile with MSVC or Cygwin GCC (non-mingw version based on
cygwin1.dll and pthreads).

I hope there is a solution but at this point and hope for some help
answering these questions:

1) Is there a multi-thread bug in the MinGW implementation istringstream?

2) Is there a problem with my build process? Am I missing a flag or
using the wrong variation of a library?

3) Is this problem unique to my machine or reproducible by others?

4) Has anyone else encountered a similar issue?

If you have experience with using Boost threads with MinGW I would love
to hear any pointers or suggestions you can share. If you try this test
application with MinGW G++ and it works I would love to know it. If
multiple people can confirm this is a bug, I want to submit it to either
the MinGW or Boost threads dev. teams.

Thanks in advance for your help,
Tod Courtney

-- 
Tod Courtney
Delcross Technologies LLC
tcourtney_at_[hidden], www.delcross.com
(217) 363-3396 ext 103

mingw34: test.cpp
        c:\\MinGW\\bin\\g++ -mthreads -o mingw34 test.cpp -I c:\\boost\\boost_1_37_0 -L c:\\boost\\boost_1_37_0\\stage\lib -lboost_thread-mgw34-mt

newmingw43: test.cpp
        c:\\mingw4\\bin\\g++ -mthreads -o newmingw43 test.cpp -I c:\\boost\\boost_1_37_0 -L c:\\boost\\boost_1_37_0\\stage\\lib -lboost_thread-mgw43-mt

nocygwin: test.cpp
        /usr/bin/g++ -mthreads -o nocygwin test.cpp -I /cygdrive/c/boost/boost_1_37_0 -L /cygdrive/c/boost/boost_1_37_0/stage/lib -mno-cygwin -lboost_thread-mgw34-mt

cygwin: test.cpp
        /usr/bin/g++ -o cygwin test.cpp -I /cygdrive/c/boost/boost_1_37_0 -L /cygdrive/c/boost/boost_1_37_0/stage/lib -lboost_thread_pthread-gcc34-mt-1_37


#include <string>
#include <vector>
#include "boost/bind.hpp"
#include "boost/thread.hpp"
#include "boost/thread/barrier.hpp"

using namespace std;

boost::mutex msgMutex;

////////////////////////////////////////////////////////////////////////
/// threadsafe tracing method
void msg(const std::string &str) {
  boost::mutex::scoped_lock lock(msgMutex);
  cout<<str<<endl;
}

////////////////////////////////////////////////////////////////////////
/// method run by each worker thread
bool exec(std::vector<string> * vec) {
  char buff[256];
  // wait here until all threads have been created
  msg(string("START THREAD: "));
  // now do the work
  for(size_t n=0;n<vec->size();n++) {
    string val=(*vec)[n];
    double d=0;
    d=atof(val.c_str());

    // COMMENTING OUT THE NEXT TWO LINES AVOIDS THE SIGSEGV
    istringstream iss(val);
    iss>>d;

    sprintf(buff,"value=%lf",d);
    msg(string(buff));
  }
  msg("EXEC DONE: ");
  return true;
}

////////////////////////////////////////////////////////////////////////
/// main method: parse inputs and create worker threads
int main(int argc, char **argv) {
  int numThreads=0;
  if (argc==2)
    numThreads=atoi(argv[1]);
  else
    cout<<"USAGE: "<<argv[0]<<" <numthreads>"<<endl;

  boost::thread **worker;
  vector<string> **vec;
  worker=new boost::thread*[numThreads];
  vec=new vector<string>*[numThreads];
  for(int n=0;n<numThreads;n++) {
    vec[n]=new vector<string>;
    for(int m=0;m<10;m++) {
      ostringstream oss;
      oss<<n<<"."<<m;
      vec[n]->push_back(oss.str());
    }
    worker[n]=new boost::thread(boost::bind(&exec,vec[n]));
  }

  // wait until all threads to end
  for(int n=0;n<numThreads;n++) {
    worker[n]->join();
    delete worker[n];
    delete vec[n];
  }
  delete [] worker;
  delete [] vec;
}


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net