Can't debug: assert error with gdb (no problem without)

I'm sorry if the title is really criptic, but I don't know how to phrase my problem.

I know I can't really ask for a solution, and I normally wouldn't but this is really escaping my abilities.

Antefacts.
I developed a program using the zeromq messaging library.
I got to a point where the program works and then started going multithreading: moving a message poller outside of the main thread.
This is supported by the library.
So I devised my thread, passed it a pointer to some parameters (including the pointer to the zmq context) and went ahead.

The Problem
The code in the child thread is the same code I had in the parent, save for the facts that functions parameters are stored in a structure that gets passed to the child.
I followed every function in the child and the parameters are correct.
The code does even work (as it should) when run normally, but hangs with an assert when run in debug.

I tried following every function I could, built the library with debug symbols, using gdb from the console...

I got nothing useful.
I still don't understand why it fails with the debugger attached, and why it runs without.

The culprit code is the following

        if ((pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET ||
             pgm_error->domain == PGM_ERROR_DOMAIN_IF) && (
             pgm_error->code != PGM_ERROR_INVAL &&
             pgm_error->code != PGM_ERROR_BADF &&
             pgm_error->code != PGM_ERROR_FAULT))

from pgm_socket.cpp:301
And here are a couple gdb outputs

Breakpoint 1, zmq::pgm_socket_t::init (this=0x7ffff0000930, 
    udp_encapsulation_=true, network_=<optimized out>) at pgm_socket.cpp:301
warning: Source file is more recent than executable.
301            if ((pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET ||
(gdb) stepi
0x00007ffff786488d    301            if ((pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET ||
(gdb) 
0x00007ffff786488f    301            if ((pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET ||
(gdb) 
0x00007ffff7864891    301            if ((pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET ||
(gdb) 
0x00007ffff7864894    301            if ((pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET ||
(gdb) 
0x00007ffff7864896    301            if ((pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET ||
(gdb) 
0x00007ffff7864899    301            if ((pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET ||
(gdb) 
0x00007ffff786489c    301            if ((pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET ||
(gdb) 
0x00007ffff786489e    301            if ((pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET ||
(gdb) 
0x00007ffff78648a1    301            if ((pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET ||
(gdb) 
0x00007ffff78648a3    301            if ((pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET ||
(gdb) 
0x00007ffff78648a6    301            if ((pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET ||
(gdb) 
376        if (sock != NULL) {
(gdb) 
Breakpoint 1, zmq::pgm_socket_t::init (this=0x7ffff0000930, 
    udp_encapsulation_=true, network_=<optimized out>) at pgm_socket.cpp:301
301            if ((pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET ||
(gdb) step
376        if (sock != NULL) {
(gdb) 
377            pgm_close (sock, FALSE);
(gdb) 

There is supposedly no way (and no reason) to jump from line 301 to 376, yet it happens.
After that there is a

return -1;

that triggers the assert that kills my code.

And I'm banging my head over this without so much as a hope of understanding what to do.

I can't really hope for a solution with this, but at least a suggestion as to how to proceed.

My code (if anyone really wanted to check it out) on github is under the project "saettang".

Stack corruption might be a possibility.

Without seeing the code, we can't possibly say.

, I can post the code no problem, this is the smallest minimal example iI couldd devise.

(android won't let me paste the code... I'll have to get to my computer.
Although even when I'll be able to show you the code, you'll still need the library cited above http://github.com/erupter/saettang

What value do pgm_error->domain and pgm_error->code have?

No matter how I compiled the relative library, the values are optimized out.
I tried explicitly configuring with -O0 but to no avail.

Here is my minimal test code.
It requires the Zmqcpp library found in my github project, as well as ZeroMQ library 3.2.2 compiled with pgm support.

/* 
     * File:   main.cpp
     * Author: erupter
     *
     * Created on January 9, 2013, 2:03 PM
     */
    
    /* 
     * File:   main.cpp
     * Author: erupter
     *
     * Created on January 9, 2013, 2:03 PM
     */
    
    #include <cstdlib>
    #include <net/if.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <sys/ioctl.h>
    #include <list>
    #include <zmqcpp.h>
    #define THREAD_CONTROL_IPC      "ipc://saetta_th_control"
    #define MULTICAST_ADDRESS       "239.192.1.1"
    #define MULTICAST_PORT          5678
    #define ROUTER_PORT             5679
    #define HEADER_CTRL             "CTRL"
    #define HEADER_SERVER_INFO      "SERVER_INFO"
    
    using namespace std;
    std::string _local_ip_address;
    std::stringstream ss;
    // custom struct to hold parameters to pass to child threads
    struct parameters{
        // pointer to context
        Zmqcpp::Context * zmqcont;
        // function pointer for callbacks
        void (*callback) (std::string);
        //ip string to connect to
        std::string ip;
        //if child should bind or connect
        int conntype;
        //topics to subscribe
        std::list<std::string> topics;
    };
    
    //child thread
    void *th_subscriber (void * params);
    //callback
    void server_location_callback(std::string ip);
    //service function to get the specified interface's address
    static inline bool get_iface_address(std::string interf);
    /*
     * 
     */
    int main(int argc, char** argv) {
    
        struct parameters myparams;
        printf( "Requested interface wlan0, attempting to fetch     address...\n");
        if (!get_iface_address("wlan0"))
            return (EXIT_FAILURE);
    
        //create the pgm address chaining various parameters defined     above plus the local ip address of the interface
        ss << "epgm://" << _local_ip_address << ";"     << MULTICAST_ADDRESS << ":" << MULTICAST_PORT     << std::endl;
    
        //create context
        Zmqcpp::Context* mycontext = new Zmqcpp::Context(1);
        
        //fill the parameters structure
        myparams.ip = ss.str();
        ss.str("");
        ss.str(HEADER_SERVER_INFO);
        myparams.topics.insert(myparams.topics.end(),ss.str());
        myparams.conntype = ZMQCPP_CONNECT;
        myparams.zmqcont=mycontext;
        myparams.callback=&server_location_callback;
        
        //create the connection string for the control socket
        ss.str("");
        ss << THREAD_CONTROL_IPC;
        //create the control socket
        Zmqcpp::Publisher *ctrlpublisher = new     Zmqcpp::Publisher(mycontext, THREAD_CONTROL_IPC, ZMQCPP_BIND);
        
        //create the child thread
        pthread_t th_hndl_subber;
        pthread_create(&th_hndl_subber, NULL, th_subscriber, (void     *)&myparams);
        
        
        while(1)
        {        
            //send control messages over the control socket
            ctrlpublisher->PubMsg(2,HEADER_CTRL,"Test");
            sleep(1);
        }
    
    
        //garbage collection
        void *status;
        pthread_join(th_hndl_subber, &status);
        printf("Main thread cleaning.\n");
        ctrlpublisher->~Publisher();
        mycontext->~Context();
        printf("Main thread cleaned succesfully.");
        return (EXIT_SUCCESS);
    }
    
    static inline bool get_iface_address(std::string interf)
    {
        int s;
        struct ifreq ifr = {};
        s = socket(PF_INET, SOCK_DGRAM, 0);
    
        strncpy(ifr.ifr_name, interf.c_str(), sizeof(ifr.ifr_name));
    
        if (ioctl(s, SIOCGIFADDR, &ifr) >= 0)
        {        
            _local_ip_address = inet_ntoa(((struct sockaddr_in     *)&ifr.ifr_addr)->sin_addr);
            printf("Detected interface IP address is %s.\nCreating     sockets on this address.\n", _local_ip_address.c_str());          
            return true;
        }    
        printf("Unable to get interface IP address: is the interface     configured?\n");
        return false;
        
    }
    
    void *th_subscriber (void * params)
    {
        //declare some service variables
        int th_continue=1;
        std::string server_ip;
        std::stringstream ss;
        std::string msgtype;
        std::string msgmaster = HEADER_SERVER_INFO;
        std::string temp;
    
        //recast the pointer to the parameter structure
        struct parameters *myparams = (struct parameters *) params;
    
        //create the subscriber for the real messages we would like to     get
        // THIS IS WHAT TRIGGERS THE ASSERT DURING DEBUG
        Zmqcpp::Subscriber *msgsubber = new     Zmqcpp::Subscriber(myparams->zmqcont,&(myparams->ip),     myparams->conntype);
    
        //have it subscribe to each topic we are told to
        for (std::list<std::string>::iterator it =     myparams->topics.begin(); it != myparams->topics.end(); it++)
        {
            cout << "Subscribing to <" << *it     <<">"<<std::endl;
            printf("Subscribing to: <%s>\n",it->c_str());
            msgsubber->SubscribeTopic(*it);
        }
    
        
        ss.str("");
        ss << THREAD_CONTROL_IPC;
    
        //create the control subscriber over the specified ipc control     address and subscribe it
        Zmqcpp::Subscriber *ctrlsubber = new     Zmqcpp::Subscriber(myparams->zmqcont,THREAD_CONTROL_IPC,     ZMQCPP_CONNECT);
        ctrlsubber->SubscribeTopic(HEADER_CTRL);
        
        sleep(1);
        while(th_continue==1)
        {
            
            //do something silly with the control messages
            ss.str("");
            ss << ctrlsubber->RecvMsg();
            msgtype.clear();
            msgtype = ss.str();
            if (!msgtype.compare(HEADER_CTRL))
            {
                ss.str("");            
                ss << "Control message: " <<     ctrlsubber->RecvMsg();
                temp.clear();
                temp.assign(ss.str());
                myparams->callback(temp.c_str());
                if (temp.compare("Control message: KILL")==0)                
                    th_continue=0;
                    
            }
        }
        //child thread garbage collection
        printf("Child thread cleaning resources.\n");
        ctrlsubber->~Subscriber();
        //msgsubber->~Subscriber();
        printf("Child thread terminating.\n");
        return(EXIT_SUCCESS);
        
    }
    
    void server_location_callback(std::string ip)
    {
        
        cout << ip.c_str() <<  std::endl;    
    }

If you literally cut&paste the msgsubscriber inside the main thread, obviously modifying the passed parameters, you can both run and debug the code.
As it is you can't.

Is this relevant to your example? (post #1)

warning: Source file is more recent than executable.

Just because gdb shows line #1 of a multiline construct does not mean that line #1 of your if block is the problem.

If you actually want to debug it, break the if's into singletons(this is logical decompostion to monads, so by a theorem by Courcelle):

 int do_this=0;
 if (pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET)
 {     
    if(pgm_error->code != PGM_ERROR_INVAL)
    {
       if(pgm_error->code != PGM_ERROR_BADF )
       {
           if(pgm_error->code != PGM_ERROR_FAULT)
             do_this=1;
       }
 }            
 if(pgm_error->domain == PGM_ERROR_DOMAIN_IF) 
 {     
    if(pgm_error->code != PGM_ERROR_INVAL)
    {
       if(pgm_error->code != PGM_ERROR_BADF )
       {
           if(pgm_error->code != PGM_ERROR_FAULT)
             do_this=1;
       }
 }            
 if(do_this)
 {
     original code from inside  if() block goes here 
 }

Not really, I had modified the phrasing of the if to see if gdb behaved any differently. It didn't.

That's not exactly the problem: the if gives way to a goto statement.
But if any of the conditions triggered the conditional to go fordward, gdb ought to show the call to the goto instruction... at least for what I know.
It instead shows the program as jumping directly to the first line after the goto label.

If then it isn't so, I'll separate the various ifs.

I tried your suggestion anyway.

        if (pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET)
        {     
           if(pgm_error->code != PGM_ERROR_INVAL)
           {
              if(pgm_error->code != PGM_ERROR_BADF )
              {
                  if(pgm_error->code != PGM_ERROR_FAULT)
                    do_this=1;
              }
           }
        }            
        if(pgm_error->domain == PGM_ERROR_DOMAIN_IF) 
        {     
           if(pgm_error->code != PGM_ERROR_INVAL)
           {
              if(pgm_error->code != PGM_ERROR_BADF )
              {
                  if(pgm_error->code != PGM_ERROR_FAULT)
                    do_this=1;
              }
           }
        }            
        if(do_this)
        {
            goto err_abort;
        }

And here is the output of gdb, i interleaved the step instructions with info locals to show the value of do_this

Breakpoint 1, zmq::pgm_socket_t::init (this=0x7ffff0000930, 
    udp_encapsulation_=true, network_=<optimized out>) at pgm_socket.cpp:311
311            if (pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET)
(gdb) info locals
port_number = 5678
sa_family = 2
pgm_error = 0x7ffff0000f40
buf = {3829176425, 4105231441}
if_req = {ir_interface = 3, ir_scope_id = 0}
do_this = 0
res = 0x7ffff0001110
addr = {sa_port = 5678, sa_addr = {gsi = {
      identifier = "\310\362\033\036\237\200"}, sport = 0}}
(gdb) step
Too many open files (signaler.cpp:230)
313               if(pgm_error->code != PGM_ERROR_INVAL)
(gdb) info locals
port_number = 5678
sa_family = 2
pgm_error = 0x7ffff0000f40
buf = {3829176425, 4105231441}
if_req = {ir_interface = 3, ir_scope_id = 0}
do_this = 0
res = 0x7ffff0001110
addr = {sa_port = 5678, sa_addr = {gsi = {
      identifier = "\310\362\033\036\237\200"}, sport = 0}}
(gdb) step
315                  if(pgm_error->code != PGM_ERROR_BADF )
(gdb) info locals
port_number = 5678
sa_family = 2
pgm_error = 0x7ffff0000f40
buf = {3829176425, 4105231441}
if_req = {ir_interface = 3, ir_scope_id = 0}
do_this = 0
res = 0x7ffff0001110
addr = {sa_port = 5678, sa_addr = {gsi = {
      identifier = "\310\362\033\036\237\200"}, sport = 0}}
(gdb) step
333            if(do_this)
(gdb) 
405        if (sock != NULL) {
(gdb) 

As you can see up to the last instruction do_this is zero, yet the jump happens anyway.

Are you sure there is NOT a logical fall through? Meaning your code hits the goto err_abort label no matter what logic happened before it.

What you showed me says there is a fall through.

I'm not familiar with the fall-through concept by its name, although I think I grasp it and there should be none, or at least there is none I can see.

The code is this and starts at line 311

        if (pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET)
        {     
           if(pgm_error->code != PGM_ERROR_INVAL)
           {
              if(pgm_error->code != PGM_ERROR_BADF )
              {
                  if(pgm_error->code != PGM_ERROR_FAULT)
                    do_this=1;
              }
           }
        }            
        if(pgm_error->domain == PGM_ERROR_DOMAIN_IF) 
        {     
           if(pgm_error->code != PGM_ERROR_INVAL)
           {
              if(pgm_error->code != PGM_ERROR_BADF )
              {
                  if(pgm_error->code != PGM_ERROR_FAULT)
                    do_this=1;
              }
           }
        }            
        if(do_this)
        {
            goto err_abort;
        }
        
        
        //  Fatal OpenPGM internal error.
        zmq_assert (false);

The last line of the snippet above is 340 and the line to which the jump points is 405, there are lots of other instructions including other conditional jumps between these points.
None of which gets executed.
I can't see no baseline to which the code could fall.

---------- Post updated at 05:39 PM ---------- Previous update was at 05:36 PM ----------

I doubt anyone wants to have a look at it, but here is the whole code of the function from which I have since posted various snippets

//  Create, bind and connect PGM socket.
int zmq::pgm_socket_t::init (bool udp_encapsulation_, const char *network_)
{
    //  Can not open transport before destroying old one.
    zmq_assert (sock == NULL);
    zmq_assert (options.rate > 0);
    int do_this=0;
    //  Zero counter used in msgrecv.
    nbytes_rec = 0;
    nbytes_processed = 0;
    pgm_msgv_processed = 0;

    uint16_t port_number;
    struct pgm_addrinfo_t *res = NULL;
    sa_family_t sa_family;

    pgm_error_t *pgm_error = NULL;

    if (init_address(network_, &res, &port_number) < 0) {
        goto err_abort;
    }

    zmq_assert (res != NULL);

    //  Pick up detected IP family.
    sa_family = res->ai_send_addrs[0].gsr_group.ss_family;

    //  Create IP/PGM or UDP/PGM socket.
    if (udp_encapsulation_) {
        if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_UDP,
              &pgm_error)) {

            //  Invalid parameters don't set pgm_error_t.
            zmq_assert (pgm_error != NULL);
            if (pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET && (
                  pgm_error->code != PGM_ERROR_BADF &&
                  pgm_error->code != PGM_ERROR_FAULT &&
                  pgm_error->code != PGM_ERROR_NOPROTOOPT &&
                  pgm_error->code != PGM_ERROR_FAILED))

                //  User, host, or network configuration or transient error.
                goto err_abort;

            //  Fatal OpenPGM internal error.
            zmq_assert (false);
        }

        //  All options are of data type int
        const int encapsulation_port = port_number;
        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_UDP_ENCAP_UCAST_PORT,
                &encapsulation_port, sizeof (encapsulation_port)))
            goto err_abort;
        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_UDP_ENCAP_MCAST_PORT,
                &encapsulation_port, sizeof (encapsulation_port)))
            goto err_abort;
    }
    else {
        if (!pgm_socket (&sock, sa_family, SOCK_SEQPACKET, IPPROTO_PGM,
              &pgm_error)) {

            //  Invalid parameters don't set pgm_error_t.
            zmq_assert (pgm_error != NULL);
            if (pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET && (
                  pgm_error->code != PGM_ERROR_BADF &&
                  pgm_error->code != PGM_ERROR_FAULT &&
                  pgm_error->code != PGM_ERROR_NOPROTOOPT &&
                  pgm_error->code != PGM_ERROR_FAILED))

                //  User, host, or network configuration or transient error.
                goto err_abort;

            //  Fatal OpenPGM internal error.
            zmq_assert (false);
        }
    }

    {
        const int rcvbuf = (int) options.rcvbuf;
        if (rcvbuf) {
            if (!pgm_setsockopt (sock, SOL_SOCKET, SO_RCVBUF, &rcvbuf,
                  sizeof (rcvbuf)))
                goto err_abort;
        }

        const int sndbuf = (int) options.sndbuf;
        if (sndbuf) {
            if (!pgm_setsockopt (sock, SOL_SOCKET, SO_SNDBUF, &sndbuf,
                  sizeof (sndbuf)))
                goto err_abort;
        }

        const int max_tpdu = (int) pgm_max_tpdu;
        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_MTU, &max_tpdu,
              sizeof (max_tpdu)))
            goto err_abort;
    }

    if (receiver) {
        const int recv_only        = 1,
                  rxw_max_tpdu     = (int) pgm_max_tpdu,
                  rxw_sqns         = compute_sqns (rxw_max_tpdu),
                  peer_expiry      = pgm_secs (300),
                  spmr_expiry      = pgm_msecs (25),
                  nak_bo_ivl       = pgm_msecs (50),
                  nak_rpt_ivl      = pgm_msecs (200),
                  nak_rdata_ivl    = pgm_msecs (200),
                  nak_data_retries = 50,
                  nak_ncf_retries  = 50;

        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_RECV_ONLY, &recv_only,
                sizeof (recv_only)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_RXW_SQNS, &rxw_sqns,
                sizeof (rxw_sqns)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_PEER_EXPIRY, &peer_expiry,
                sizeof (peer_expiry)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_SPMR_EXPIRY, &spmr_expiry,
                sizeof (spmr_expiry)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_BO_IVL, &nak_bo_ivl,
                sizeof (nak_bo_ivl)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_RPT_IVL, &nak_rpt_ivl,
                sizeof (nak_rpt_ivl)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_RDATA_IVL,
                &nak_rdata_ivl, sizeof (nak_rdata_ivl)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_DATA_RETRIES,
                &nak_data_retries, sizeof (nak_data_retries)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_NAK_NCF_RETRIES,
                &nak_ncf_retries, sizeof (nak_ncf_retries)))
            goto err_abort;
    } else {
        const int send_only        = 1,
                  max_rte      = (int) ((options.rate * 1000) / 8),
                  txw_max_tpdu     = (int) pgm_max_tpdu,
                  txw_sqns         = compute_sqns (txw_max_tpdu),
                  ambient_spm      = pgm_secs (30),
                  heartbeat_spm[]  = { pgm_msecs (100),
                                       pgm_msecs (100),
                                       pgm_msecs (100),
                                       pgm_msecs (100),
                                       pgm_msecs (1300),
                                       pgm_secs  (7),
                                       pgm_secs  (16),
                                       pgm_secs  (25),
                                       pgm_secs  (30) };

        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_SEND_ONLY,
                &send_only, sizeof (send_only)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_ODATA_MAX_RTE,
                &max_rte, sizeof (max_rte)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_TXW_SQNS,
                &txw_sqns, sizeof (txw_sqns)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_AMBIENT_SPM,
                &ambient_spm, sizeof (ambient_spm)) ||
            !pgm_setsockopt (sock, IPPROTO_PGM, PGM_HEARTBEAT_SPM,
                &heartbeat_spm, sizeof (heartbeat_spm)))
            goto err_abort;
    }

    //  PGM transport GSI.
    struct pgm_sockaddr_t addr;

    memset (&addr, 0, sizeof(addr));
    addr.sa_port = port_number;
    addr.sa_addr.sport = DEFAULT_DATA_SOURCE_PORT;

    //  Create random GSI.
    uint32_t buf [2];
    buf [0] = generate_random ();
    buf [1] = generate_random ();
    if (!pgm_gsi_create_from_data (&addr.sa_addr.gsi, (uint8_t*) buf, 8))
        goto err_abort;


    //  Bind a transport to the specified network devices.
    struct pgm_interface_req_t if_req;
    memset (&if_req, 0, sizeof(if_req));
    if_req.ir_interface = res->ai_recv_addrs[0].gsr_interface;
    if_req.ir_scope_id  = 0;
    if (AF_INET6 == sa_family) {
        struct sockaddr_in6 sa6;
        memcpy (&sa6, &res->ai_recv_addrs[0].gsr_group, sizeof (sa6));
        if_req.ir_scope_id = sa6.sin6_scope_id;
    }
    if (!pgm_bind3 (sock, &addr, sizeof (addr), &if_req, sizeof (if_req),
          &if_req, sizeof (if_req), &pgm_error)) {

        //  Invalid parameters don't set pgm_error_t.
        zmq_assert (pgm_error != NULL);
        /*if ((pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET ||
             pgm_error->domain == PGM_ERROR_DOMAIN_IF) && (
             pgm_error->code != PGM_ERROR_INVAL &&
             pgm_error->code != PGM_ERROR_BADF &&
             pgm_error->code != PGM_ERROR_FAULT))

            //  User, host, or network configuration or transient error.
            goto err_abort;*/

        
        if (pgm_error->domain == PGM_ERROR_DOMAIN_SOCKET)
        {     
           if(pgm_error->code != PGM_ERROR_INVAL)
           {
              if(pgm_error->code != PGM_ERROR_BADF )
              {
                  if(pgm_error->code != PGM_ERROR_FAULT)
                    do_this=1;
              }
           }
        }            
        if(pgm_error->domain == PGM_ERROR_DOMAIN_IF) 
        {     
           if(pgm_error->code != PGM_ERROR_INVAL)
           {
              if(pgm_error->code != PGM_ERROR_BADF )
              {
                  if(pgm_error->code != PGM_ERROR_FAULT)
                    do_this=1;
              }
           }
        }            
        if(do_this)
        {
            goto err_abort;
        }
        
        
        //  Fatal OpenPGM internal error.
        zmq_assert (false);
    }

    //  Join IP multicast groups.
    for (unsigned i = 0; i < res->ai_recv_addrs_len; i++) {
        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_JOIN_GROUP,
              &res->ai_recv_addrs , sizeof (struct group_req)))
            goto err_abort;
    }
    if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_SEND_GROUP,
          &res->ai_send_addrs [0], sizeof (struct group_req)))
        goto err_abort;

    pgm_freeaddrinfo (res);
    res = NULL;

    //  Set IP level parameters.
    {
        // Multicast loopback disabled by default
        const int multicast_loop = 0;
        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_MULTICAST_LOOP,
              &multicast_loop, sizeof (multicast_loop)))
            goto err_abort;

        const int multicast_hops = options.multicast_hops;
        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_MULTICAST_HOPS,
                &multicast_hops, sizeof (multicast_hops)))
            goto err_abort;

        //  Expedited Forwarding PHB for network elements, no ECN.
        const int dscp = 0x2e << 2;
        if (AF_INET6 != sa_family && !pgm_setsockopt (sock,
              IPPROTO_PGM, PGM_TOS, &dscp, sizeof (dscp)))
            goto err_abort;

        const int nonblocking = 1;
        if (!pgm_setsockopt (sock, IPPROTO_PGM, PGM_NOBLOCK,
              &nonblocking, sizeof (nonblocking)))
            goto err_abort;
    }

    //  Connect PGM transport to start state machine.
    if (!pgm_connect (sock, &pgm_error)) {

        //  Invalid parameters don't set pgm_error_t.
        zmq_assert (pgm_error != NULL);
        goto err_abort;
    }

    //  For receiver transport preallocate pgm_msgv array.
    if (receiver) {
        zmq_assert (in_batch_size > 0);
        size_t max_tsdu_size = get_max_tsdu_size ();
        pgm_msgv_len = (int) in_batch_size / max_tsdu_size;
        if ((int) in_batch_size % max_tsdu_size)
            pgm_msgv_len++;
        zmq_assert (pgm_msgv_len);

        pgm_msgv = (pgm_msgv_t*) malloc (sizeof (pgm_msgv_t) * pgm_msgv_len);
        alloc_assert (pgm_msgv);
    }

    return 0;

err_abort:
    if (sock != NULL) {
        pgm_close (sock, FALSE);
        sock = NULL;
    }
    if (res != NULL) {
        pgm_freeaddrinfo (res);
        res = NULL;
    }
    if (pgm_error != NULL) {
        pgm_error_free (pgm_error);
        pgm_error = NULL;
    }
    errno = EINVAL;
    return -1;
}

This is one of the problems with the goto construct. Conditional jumps are a special problem in the logic construction of a progam. I personally seldom use them, except in descent parsers (setjmp/longjmp are a kind of conditional jump, too).

Consider removing most of those jumps. There are some folks who would go on a 'Never use goto' rant. But everything in C++/C is there for good reason, including goto.

But: Absolutely do make err_abort() a separate function.

you should also instrument your code - add fprintf() statements liberally, use the __LINE__ preprocessor command to show where you are in the code. When you have jumps debugging can be extra hard.

Unfortunately none of this is mine.
This is part of the open source library ZeroMQ, I've never used jumps since I stopped using basic.
I prefer to find a more logical way of coding my programs (I'm quite akin to those "never use jumps" ranting guys ;)).

I managed to understand an important detail:

the problem arises from how I pass parameters to the child thread.

If I just pass a void pointer to the zmq context, all is fine.
If I pass a pointer to my struct (with explicit castings on both sides), the problems shows its head.

Now I don't know enough to understand this, I hope someone more knowledgeable can chime in.

Here are the two possibilities

working

void *zmq_cont_ptr = zmq_ctx_new();
pthread_create(&th_hndl_subber, NULL, th_subscriber, zmq_cont_ptr);

non working

typedef struct parameters{
    //Zmqcpp::Context * zmqcont;
    void * zmqcont;
    void (*callback) (std::string);
    std::string ip;
    int conntype;
    std::list<std::string> topics;
}parameters;

parameters myparams;

pthread_create(&th_hndl_subber, NULL, th_subscriber, (void *)&myparams);

void * th_subscriber(void * parameters)
{
    parameters *myparams = (parameters *) params;

---------- Post updated at 04:52 PM ---------- Previous update was at 01:52 PM ----------

I finally know what's the problem!!!
Thanks to chaingun from IRC channel #programming on FreeNode!

The problem is how long a temporary buffer lasts in memory.
As he pointed out when I pass something like

std::string mystring = "something";
myfunc(mystring.c_str());

A temporary buffer is allocated for the array of chars, but there are no guarantees on how much it will last.
That was the problem because when I moved the parameters into const char arrays, I was able to both run and debug the program.

Thank you to all who took the time to read this!

1 Like