Question

I am making interprocess communication between two of my processes with boost::interprocess::message_queue.

This is the first time I'm using it so this exception isn't clear to me because I cannot find any documentation on it.

I have my classes setup as following:

struct Pos{float X,Y,Z;};
struct Quat{float W,X,Y,Z;};
typedef unsigned char Byte;
struct NPCDataFoot
{
    //some Pos and Quat variables here too
    unsigned short AnimationIndex;
    void Apply(NPCDataFoot &data){AnimationIndex=data.AnimationIndex;}
    NPCDataFoot(){AnimationIndex=0;}
};
struct NPCDataVehicle
{
    //many many more
    unsigned short lrAnalog;
    void Apply(NPCDataVehicle &data){lrAnalog=data.lrAnalog;}
    NPCDataVehicle(){lrAnalog = 0;}
};
enum TransmissionDataType{
    TDT_NewNPC,//many more...
};
const unsigned short QueueMaxSize = 256;
struct ExchangeData
{
    unsigned short  CommandType;
    unsigned short  NPCPlayerID;
    Byte            State;
    NPCDataFoot     OnFootData;
    NPCDataVehicle  InCarData;
    float MoveSpeed;
    Pos MoveToPos;
    //206
    ExchangeData(unsigned short CommandType = 0, unsigned short NPCPlayerid = 0xFFFF)
        : CommandType(CommandType), NPCPlayerID(NPCPlayerid)
    {}
    ExchangeData(unsigned short CommandType, unsigned short NPCPlayerid, NPCDataFoot& foot_data, NPCDataVehicle& car_data)
        : CommandType(CommandType), NPCPlayerID(NPCPlayerid), OnFootData(foot_data), InCarData(car_data)
    {}
};

both my programs are set to compile with the /zp1 flag (Align structures/classes to 1-byte alignment).

now whenever I reach this code:

ServerMsgQueue * message_queue = NULL;
PLUGIN_EXPORT void PLUGIN_CALL
    ProcessTick()
{
    static bool init = false;
    static ExchangeData DataTransmision;
    if(!init)
    {
        try
        {
            ServerMsgQueue = new message_queue(open_or_create              
                    ,string_format("REMOTESHAREDMEMORYBTWNPRCS%04x",GetServerVarAsInt("port")).c_str()
                    ,1024 * QueueMaxSize,sizeof(ExchangeData)); 
        }
        catch(interprocess_exception &ex)
        {
            std::cout << ex.what() << ":" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << std::endl;
        }
        init = true;
    }
    static unsigned int unused;
    if(ServerMsgQueue)
    {
        try
        {
            if(ServerMsgQueue->try_receive(&DataTransmision,sizeof(ExchangeData),unused,unused))
            {
                switch(DataTransmision.CommandType)
                {//some cases
                default:{std::cout << "UNKNOWN RECEIVED DATA!!!" << std::endl;break;}
                }
            }
        }
        catch(interprocess_exception &ex)
        {
            //this happens always
            std::cout << ex.what() << ":" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << std::endl;
        }
    }
}

The application keeps issuing "boost::interprocess_exception::library_error" in the block where try_receive is being used.

What am I doing wrong in this case? I'm sure the data send is the same size because 1) i use the same header and 2) I compile with the same options.

I have confirmed that the variable sizes are the same with the following code in both programs:

MessageBox(NULL,string_format(
"Pos(%d):Quat(%d):NPCDataFoot(%d):NPCDataVehicle(‌​%d):ExchangeData(%d)",
sizeof(Pos),sizeof(Quat),sizeof(NPCDataFoot),sizeof(NPCData‌Vehicle),sizeof(ExchangeData)).c_str()
,"Reported sizes Client",0);

Edit: I seem have "solved" it.. magicly;

It seems that this code was the error:

static unsigned int unused;
if(ServerMsgQueue->try_receive(&DataTransmision,sizeof(ExchangeData),unused,unused))

changed it to

unsigned int Priority;
size_t sizexxx;
if(ServerMsgQueue->try_receive(&DataTransmision,sizeof(ExchangeData),sizexxx,Priority))

Can someone explain why this works and the other code not?

Was it helpful?

Solution

See the source code for message_queue::do_receive (called from message_queue::try_receive); do_receive first writes the message size to the "out" parameter recvd_size (a reference to unused in your code), then writes the priority to the "out" parameter priority (also a reference to unused in your code -- thus effectively overwriting recvd_size with the priority value). Immediately below, the call to memcpy uses the now incorrect recvd_size, leading to the behaviour you observed (incomplete copy or buffer overrun, depending on priority).

Arguably, the author of the library should have used the original top_msg->len (instead of the "out" parameter recvd_size) for the memcpy bytecount. However, in order to avoid these kinds of surprises, always use distinct variables for "out" parameters (call them unused1 and unused2 if you so desire).

OTHER TIPS

This is most likely caused by your use of /zp1. Your program and the libraries to which it links will think that structures have different sizes and/or member locations. Don't do that.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top