1

I have having some sort of memory or winsock issue that only occurs when c++ code is compiled in release mode.

Evidence that its a memory issue:

A previous unknown bug was fixed, by commenting out two lines of code. These two lines of code seem harmless. they were left overs from old versions. This indicates that somewhere I am using un-initialized memory. XS_Client is used as a base class.

        class XS_Client
        {
        private:

            /* these two lines of comments fixed the bug */
            /***********************************************
            enum { max_length = 1024 };
            char data_[max_length];
            **********************************************/

            void * context_;
            void * socket_;
            boost::thread t_;
            volatile bool should_run_;              
        public:
            XS_Client(void *context, short type, const std::string &address)
            : context_(context), socket_(XS_Socket::NewSocket(context_,type))
            {
                XS_Socket::Connect(socket_,address);
        #ifdef _OUTPUTD
                std::cout << address << " XS_Client: " << GetCurrentThreadId() << std::endl;
        #endif
                boost::thread   t(boost::bind(&XS_Client::thread_func, this));
                t_.swap(t);
            }

            void SetSockOpt(int option, const void *optval,size_t optvallen)
            {
                int rc = xs_setsockopt(socket_,option,optval,optvallen);
                if ( rc != 0 )
                    std::cout << "xs_setsockopt error: " << xs_strerror(errno) << std::endl;
            }

            virtual ~XS_Client()
            {
                if ( should_run_ )
                    Stop();
            }

            void thread_func() {
                /* Create an empty message */
                xs_msg_t msg;

                while (should_run_)
                {
                    //int bytes_recvd = xs_recv(socket_,data_,max_length,0);
                    int rc = xs_msg_init (&msg);
                    if ( rc != 0 )
                        std::cout << "xs_msg_init error: " << xs_strerror(errno) << std::endl;
                    assert (rc == 0);
                    /* Block until a message is available to be received from socket */
                    int bytes_recvd = xs_recvmsg (socket_, &msg, 0);

        #ifdef _DEBUG 
                    std::cout << "received " << bytes_recvd << std::endl;
        #endif;

                    if ( bytes_recvd == -1 )
                    {

                        if ( xs_errno() == ETERM ) 
                        {
                            should_run_ = false;
                            std::cout << "ETERM received" << xs_strerror(errno) << std::endl;
                            break;
                        }

                        if ( !should_run_ )
                            xs_msg_close (&msg);
                        else
                        {
                            std::cout << "receive error!" << xs_strerror(errno) << std::endl;
                            boost::this_thread::sleep(boost::posix_time::milliseconds(100u));
                        }
                    }
                    else 
                    {

        #ifdef _DEBUG 
                        //std::cout << "received " << xs_msg_data(&msg) << std::endl;
        #endif;
                        OnMsg(xs_msg_data(&msg),bytes_recvd);

                        /* Release message */
                        xs_msg_close (&msg);
                    }

                }

                int rc = xs_close (socket_);        
                if ( rc != 0 )
                    std::cout << "xs_close error: " << xs_strerror(errno) << std::endl;

                Cleanup();
            }

            virtual void OnMsg(const void *msg, int bytes_recvd)
            {
                std::cout << "virtual void OnMsg received " << bytes_recvd << std::endl;
            }

            virtual void Stop()
            {
                should_run_ = false;
                t_.timed_join(boost::posix_time::milliseconds(2000));
            }

            virtual void Cleanup()
            {
            }


        };

Evidence that its a windows/socket issue:

The real bug is that my tcp socket (localhost) never gets data. However this only occurs when I am using both boost::asio and crossroads/0mq in same process. Also, the bug does not occur if I start the process through the debugger.

So when I compile in "realesewithdebuginfo" mode the bug only occurs when not in the debugger. same exact compiled code.

question1: what tool is recommended for c++ code analysis and/or windows api call analysis? Also, the problem is not easily recreated, so a static analysis may be best. i use lots of templates, boost::asio::udp, multiple treading libraries. multiple socket/io libraries.

question2: what is available on the windows side to see if I am causing a deadlock due to socket i/o mis-us-sages by external libraries?

tyvm4yh

jaybny
  • 1,026
  • 2
  • 13
  • 29
  • Try 32-bit and 64-bit builds, porting to Linux gives you access to better tools such as Valgrind. – Steve-o Oct 11 '12 at 02:05
  • linux port is the plan.. hence cmake... but currently communicating with .net on single server and no VMs. – jaybny Oct 11 '12 at 03:26

1 Answers1

2

The main difference between running under a debugger and not is the debug heap. To switch the debug heap off, you can use the _NO_DEBUG_HEAP environment variable. You can set this globally, but you're much better off doing it just for your debugging runs, as in this answer:

https://stackoverflow.com/a/1060929/1618406

If this reproduces the bug, but you're having difficulty actually debugging (because of the optimised code), I'd just temporarily disable optimisations for your release build. Just don't forget to switch them back on again...

Pretty much every time, switching the debug heap off and disabling optimisations has let me reproduce this kind of bug in the debugger, and then debug it without too much hassle.

Additionally, if you use Windows 7, you may find the Program Compatibility Assistant is stepping in and doing something that makes your program work, even though it shouldn't:

http://www.virtualdub.org/blog/pivot/entry.php?id=319

You can supposedly disable this in your program's manifest, but I prefer to have it disabled using the Group Policy Editor, e.g.:

http://www.howtogeek.com/howto/4161/disable-program-compatibility-assistant-in-windows-7-and-vista/

Disabling the Program Compatibility Assistant is highly recommended if you ever run your program outside the debugger...

Community
  • 1
  • 1
Tom Seddon
  • 2,648
  • 1
  • 19
  • 28