Skip to content

Commit d15ea45

Browse files
committed
Pickle - support extra slots
1 parent b9f54f2 commit d15ea45

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

scapy/packet.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ def _rebuild_pkt(
8484
fields, # type: Dict[str, Any]
8585
payload, # type: Optional[Packet]
8686
metadata, # type: Dict[str, Any]
87+
extra_slots=None, # type: Optional[Dict[str, Any]]
8788
):
8889
# type: (...) -> Packet
8990
"""Helper for unpickling Packet instances via field values."""
@@ -98,6 +99,9 @@ def _rebuild_pkt(
9899
pkt.sniffed_on = metadata['sniffed_on']
99100
pkt.wirelen = metadata['wirelen']
100101
pkt.comments = metadata['comments']
102+
# Restore any extra __slots__ defined by subclasses
103+
for attr, value in extra_slots.items():
104+
setattr(pkt, attr, value)
101105
return pkt
102106

103107

@@ -279,9 +283,14 @@ def __reduce__(self):
279283
'wirelen': self.wirelen,
280284
'comments': self.comments,
281285
}
286+
# Collect any extra __slots__ defined by subclasses
287+
extra_slots = {}
288+
for attr in type(self).__all_slots__ - set(Packet.__slots__):
289+
if hasattr(self, attr):
290+
extra_slots[attr] = getattr(self, attr)
282291
return (
283292
_rebuild_pkt,
284-
(self.__class__, fields, payload, metadata),
293+
(self.__class__, fields, payload, metadata, extra_slots),
285294
)
286295

287296
def __deepcopy__(self,

test/regression.uts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,30 @@ p2 = pickle.loads(pickle.dumps(p))
653653
assert p2.src == '10.0.0.1'
654654
assert raw(p2) == raw(p)
655655

656+
= Pickle preserves custom __slots__ from subclasses
657+
658+
import pickle
659+
660+
class MyPacket(Packet):
661+
__slots__ = ["custom_id", "custom_tag"]
662+
name = "MyPacket"
663+
fields_desc = [ByteField("val", 0)]
664+
665+
p = MyPacket(val=42)
666+
p.custom_id = 0x123
667+
p.custom_tag = "hello"
668+
p2 = pickle.loads(pickle.dumps(p))
669+
assert p2.val == 42
670+
assert p2.custom_id == 0x123
671+
assert p2.custom_tag == "hello"
672+
673+
# Unset custom slots should not cause errors
674+
p3 = MyPacket(val=7)
675+
assert p3.custom_id is None
676+
p4 = pickle.loads(pickle.dumps(p3))
677+
assert p4.val == 7
678+
assert p4.custom_id is None
679+
656680
= Usage test
657681

658682
from scapy.main import _usage

0 commit comments

Comments
 (0)