fix(netpacket): Fix undefined behavior with NetPacket buffer writes#2304
fix(netpacket): Fix undefined behavior with NetPacket buffer writes#2304xezon wants to merge 1 commit intoTheSuperHackers:mainfrom
Conversation
Greptile Overview
|
| Filename | Overview |
|---|---|
| Core/GameEngine/Source/GameNetwork/NetPacket.cpp | Replaces placement-new into raw byte buffers with stack construction + memcpy across all 20 FillBufferWith* functions, eliminating alignment and strict aliasing undefined behavior. All changes are mechanical and consistent. |
Flowchart
flowchart TD
A["FillBufferWithCommand(buffer, ref)"] --> B{Switch on\nNetCommandType}
B --> C["FillBufferWithGameCommand"]
B --> D["FillBufferWithAckCommand"]
B --> E["FillBufferWithFrameCommand"]
B --> F["...18 other FillBufferWith* functions"]
subgraph old["Old Pattern (Undefined Behavior)"]
G["placement-new: NetPacketXxx* p = new (buffer) NetPacketXxx"] --> H["Write fields via p->field = value"]
end
subgraph new["New Pattern (Well-Defined)"]
I["Stack construct: NetPacketXxx packet"] --> J["Write fields via packet.field = value"]
J --> K["memcpy(buffer, &packet, sizeof(packet))"]
end
C --> new
D --> new
E --> new
F --> new
K --> L["Append variable data via memcpy at offset sizeof(NetPacketXxx)"]
Last reviewed commit: 55e69ea
| packet->relay.relay = msg->getRelay(); | ||
| packet->playerId.playerId = cmdMsg->getPlayerID(); | ||
| packet->commandId.commandId = cmdMsg->getID(); | ||
| NetPacketGameCommand packet; |
There was a problem hiding this comment.
Considering how frequently these are used, maybe we make these static so we aren't always initialising the structs?
The variable parts are always updated with each use so it shouldn't be an issue.
There was a problem hiding this comment.
Unclear to me if that would give anything for performance. Making it static means it goes into the DATA segment. So CPU would need to write and read from DATA segment to heap buffer, which of course is fast, but maybe write and read from code segment to stack to heap buffer is just fine? Code instructions and Stack are hot. DATA segment maybe not as hot?
There was a problem hiding this comment.
It's fair, there's probably nothing to it in the grand scheme of things since we don't need to persist any values between calls.
There was a problem hiding this comment.
We can revisit this when it indeed shows up in profiler. I doubt it will.
| memcpy(buffer + offset, unitext.str(), packet->textLength * sizeof(UnsignedShort)); | ||
| offset += packet->textLength * sizeof(UnsignedShort); | ||
| memcpy(buffer + offset, unitext.str(), packet.textLength * sizeof(UnsignedShort)); | ||
| offset += packet.textLength * sizeof(UnsignedShort); |
There was a problem hiding this comment.
Since this is a local variable, this offset adjustment seems redundant here.
I think fill buffer with chat command does the same thing.
seems like this was a copypasta in this situation from the other function
There was a problem hiding this comment.
seems like the file transfer command does the same thing
There was a problem hiding this comment.
Yes. I already have a follow up refactor for afterwards that cleans this up. Outside the scope of this change.
This change fixes the undefined behavior with NetPacket buffer writes in
NetPacket::FillBufferfunctions.TODO