Reputation: 2210
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(NPCDataVehicle),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?
Upvotes: 1
Views: 2579
Reputation: 66661
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).
Upvotes: 1
Reputation: 42544
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.
Upvotes: 1