0

I'm toying with ZeroMQ and Cereal to pass data structures (mostly std::vector of numeric types) between different processes. I've managed to successfully achieve what I wanted, but I'm getting a Segmentation Fault at the end of execution, and after further inspection with valgrind I've noticed that memory is being leaked/not freed.

server.cpp (receiving side):

#include <zmq.hpp>
#include <string>
#include <unistd.h>
#include <sstream>
#include <cereal/archives/binary.hpp> // serializer
#include <cereal/types/vector.hpp>    // to allow vector serialization
///////////////////////
int receiveMSG(zmq::socket_t& _ss, std::string& _dd){ 
    _dd.clear(); // empty string
    zmq::message_t msg; 
    int n = _ss.recv(&msg); 
    char * tmp;
    memcpy(tmp,msg.data(),msg.size()); 
    _dd = std::string (tmp,msg.size());
    return n;
};
///////////////////////
template <typename _t> 
void vectorDeserializer(std::vector<_t>& _output, std::string& _serializedVector){
    std::stringstream ss; 
    ss << _serializedVector;
    cereal::BinaryInputArchive iarchive(ss);
    iarchive(_output);
    ss.clear();
};
/////////////////////////////////////////////////////
int main () {
    zmq::context_t context (1);
    zmq::socket_t socket (context, ZMQ_REP);
    socket.bind ("tcp://*:4455");

    std::string ts = "dummy";
    std::vector<float> vec (10,5.5);

    receiveMSG(socket,ts);
    vectorDeserializer(vec,ts);

    for (int i = 0; i < vec.size(); ++i) printf("%f\t",vec[i]);
    printf("\n");

    return 0;
}

client.cpp (sending side):

#include <zmq.hpp>
#include <string>
#include <vector>
#include <cereal/archives/binary.hpp> // serializer
#include <cereal/types/vector.hpp>    // to allow vector serialization
#include <sstream>
///////////////////////
int sendMSG(zmq::socket_t& _ss, std::string& _dd){
    zmq::message_t msg (_dd.size());
    return _ss.send(msg);
};
///////////////////////
template <typename _t> 
void vectorSerializer(std::vector<_t>& _input, std::string& _serializedVector){
    std::stringstream ss; // any stream can be used
    cereal::BinaryOutputArchive oarchive(ss); // Create an output archive
    oarchive(_input);
    _serializedVector = ss.str();
};
///////////////////////
int main ()  {
    zmq::context_t context (1);
    zmq::socket_t  socket (context, ZMQ_REQ);

    std::cout << "Connecting to server…" << std::endl;
    socket.connect ("tcp://localhost:4455");

    std::vector<float> tt (5,1.5);
    std::string ssss="dummy";
    vectorSerializer(tt,ssss);
    sendMSG(socket,ssss);
    return 0;
}

The output from valgrind is on this Pastebin link. Apparently the destructor of zmq::socket_t trhoughs a segfault due to an Invalid read of size 4 when closing the socket. Additionally, there is a lot of Conditional jump or move depends on uninitialised value(s) reported by valgrind when calling memcpy.

What exactly am I missing in my code? Or is the issue on the libraries inner code?

joaocandre
  • 1,621
  • 4
  • 25
  • 42
  • `char * tmp; memcpy(tmp,msg.data(),msg.size());` -- You are copying data to a pointer that was not initialized. Also, why even have `tmp` to create a `std::string`? You could have simply directly used `msg.data()` to create the string. – PaulMcKenzie Apr 07 '18 at 17:39
  • @PaulMcKenzie You are right, looking closely it does make more sense. `_dd = std::string ((const char *) msg.data(),msg.size());` is enough to create a string. I was initially following ZeroMQ own examples. If you write an answer I'll flag it as accepted. – joaocandre Apr 07 '18 at 18:16

0 Answers0