vendredi 26 février 2016

C++ Union Constructor Causes Segmentation Fault

When initializing a struct that contains a union of non-POD structs, I get a segmentation fault every time I try to set the union member's value. It doesn't matter whether I initialize it ahead of time or not. In the case below, the constructor for RawEntryPayload() triggers the segmentation fault.

typedef struct RawEntry {
      RawEntryType type;
      std::uint64_t timestamp;
      std::string emd5;         // MD5 hashed lowercase email
      std::string email_domain; // eg; yahoo.com, gmail.com 
      union RawEntryPayload {
          RawUnsub unsub;
          GeoLocation location;
          RawReply reply;
          RawComplaint complaint;
          RawEntryPayload() {unsub = RawUnsub{};}
          ~RawEntryPayload() {};
      } data;
      RawEntry() { type = RawEntryType::none;};
      ~RawEntry(){};
      RawEntry(const RawEntry& e);
      bool parse(const char*, size_t); // populate from raw data

    protected:
         bool LoadRawUnsubData(Json::Value&);
         bool LoadRawReplyData(Json::Value&);
         bool LoadRawComplaintData(Json::Value&);
         bool LoadRawGeo(Json::Value&);
}

To give you an idea of what the RawUnsub struct looks like:

typedef struct Taxonomy {
      std::string network;
      std::string offer;
      std::string publisher; // optional sometimes
      std::string spec_type; // optional
  } Taxonomy;

  typedef struct RawUnsub {
      std::string client; // SendAPI client
      std::string token;  // reporting send token
      Taxonomy taxonomy;  // full taxonomy
  } RawUnsub;

Using GDB and running a backtrace, I note that it's probably due to some issue with initialization of std::string's somewhere in the union:

0x00000033f5ace858 in std::string::swap(std::string&) () from /lib64/libstdc++.so.6
#1  0x00000033f5ace879 in std::string::operator=(std::string&&) () from /lib64/libstdc++.so.6
0x000000000040d9e9 in unsubulator::RawUnsub::operator=(unsubulator::RawUnsub&&) (this=0x7fffffffddd0) at ././include/libunsubulator/types.hpp:17
...

Valgrind's memcheck notes that there's uninitialized reads of size 8 (a pointer, I'm guessing?) if I don't explicitly initialize the unsub member (but in that case, I still segfault when assigning to it).

Any thoughts? Worst I've been stumped in a long time...

Aucun commentaire:

Enregistrer un commentaire