diff --git a/scapy/fields.py b/scapy/fields.py index 62f81e742f6..a071f0bc408 100644 --- a/scapy/fields.py +++ b/scapy/fields.py @@ -336,6 +336,9 @@ def _find_fld(self): except KeyError: pass else: + if not pkt.default_fields: + # Packet not initialized + return self.dflt if isinstance(pkt, tuple(self.dflt.owners)): return self._find_fld_pkt(pkt) frame = frame.f_back diff --git a/scapy/packet.py b/scapy/packet.py index 97b47f025a2..790f63a297c 100644 --- a/scapy/packet.py +++ b/scapy/packet.py @@ -187,11 +187,14 @@ def do_init_fields(self, flist): """ Initialize each fields of the fields_desc dict """ + default_fields = {} for f in flist: - self.default_fields[f.name] = copy.deepcopy(f.default) + default_fields[f.name] = copy.deepcopy(f.default) self.fieldtype[f.name] = f if f.holds_packets: self.packetfields.append(f) + # We set default_fields last to avoid race issues + self.default_fields = default_fields def do_init_cached_fields(self): """ @@ -206,8 +209,9 @@ def do_init_cached_fields(self): self.prepare_cached_fields(self.fields_desc) # Use fields information from cache - if not Packet.class_default_fields.get(cls_name, None) is None: - self.default_fields = Packet.class_default_fields[cls_name] + default_fields = Packet.class_default_fields.get(cls_name, None) + if default_fields: + self.default_fields = default_fields self.fieldtype = Packet.class_fieldtype[cls_name] self.packetfields = Packet.class_packetfields[cls_name] @@ -228,32 +232,38 @@ def prepare_cached_fields(self, flist): cls_name = self.__class__ # Fields cache initialization - if flist: - Packet.class_default_fields[cls_name] = dict() - Packet.class_default_fields_ref[cls_name] = list() - Packet.class_fieldtype[cls_name] = dict() - Packet.class_packetfields[cls_name] = list() + if not flist: + return + + class_default_fields = dict() + class_default_fields_ref = list() + class_fieldtype = dict() + class_packetfields = list() # Fields initialization for f in flist: if isinstance(f, MultipleTypeField): - del Packet.class_default_fields[cls_name] - del Packet.class_default_fields_ref[cls_name] - del Packet.class_fieldtype[cls_name] - del Packet.class_packetfields[cls_name] + # Abort self.class_dont_cache[cls_name] = True self.do_init_fields(self.fields_desc) - break + return tmp_copy = copy.deepcopy(f.default) - Packet.class_default_fields[cls_name][f.name] = tmp_copy - Packet.class_fieldtype[cls_name][f.name] = f + class_default_fields[f.name] = tmp_copy + class_fieldtype[f.name] = f if f.holds_packets: - Packet.class_packetfields[cls_name].append(f) + class_packetfields.append(f) # Remember references if isinstance(f.default, (list, dict, set, RandField, Packet)): - Packet.class_default_fields_ref[cls_name].append(f.name) + class_default_fields_ref.append(f.name) + + # Apply + Packet.class_default_fields_ref[cls_name] = class_default_fields_ref + Packet.class_fieldtype[cls_name] = class_fieldtype + Packet.class_packetfields[cls_name] = class_packetfields + # Last to avoid racing issues + Packet.class_default_fields[cls_name] = class_default_fields def dissection_done(self, pkt): """DEV: will be called after a dissection is completed""" diff --git a/test/fields.uts b/test/fields.uts index 87e0d630b3f..d68d68e70ba 100644 --- a/test/fields.uts +++ b/test/fields.uts @@ -1252,6 +1252,7 @@ assert Dot11().FCfield.to_DS is False ######## ######## + MultipleTypeField +~ mtf = Test initialization order