Oh dear...
Since the restructure, all object-related structures (object_kind/artifact/ego_item/object) have slays and brands as linked lists.
These structures can be described as:
struct obj_related
{
static fields;
static pointers; (kind, name...)
dynamic pointers; (slays, brands...)
};
Everywhere in the code, these structures are copied and wiped. For all static fields/pointers, this has no impact. But for dynamic pointers, the result is catastrophic.
Case #1: WIPE()
This simply does a memset(0) on the structure, which will set to zero every bit of the structure, including dynamic pointers. Basically, the memory allocated to these pointers is lost.
To avoid these memory leaks, all dynamic pointers must be freed before calling WIPE(). See object_wipe() for a good example.
Case #2: COPY()
This will do a bit-to-bit copy of the structures, which will copy everything including dynamic pointers. Here, the danger is double: not only the memory allocated to the dynamic pointers associated with the destination is lost (pointer address is replaced), but if you free the source object (assuming the dynamic pointers are properly freed when freeing the source object), you also free the dynamic pointers associated with the destination (since they are now equal)... and you could be in trouble when freeing the destination object (potential double-free of dynamic pointers).
To avoid this problem, all dynamic pointers must be freed before calling COPY, set to NULL after the copy and then copied separately. See object_copy() for a good example.
Case #3: structure copy
This is similar to case #2, as doing struct 2 = struct 1 is the same as doing COPY(&struct 2, &struct 1, struct). Same fix must apply. See scramble_artifact() for a good example of structure copy.
Since the restructure, all object-related structures (object_kind/artifact/ego_item/object) have slays and brands as linked lists.
These structures can be described as:
struct obj_related
{
static fields;
static pointers; (kind, name...)
dynamic pointers; (slays, brands...)
};
Everywhere in the code, these structures are copied and wiped. For all static fields/pointers, this has no impact. But for dynamic pointers, the result is catastrophic.
Case #1: WIPE()
This simply does a memset(0) on the structure, which will set to zero every bit of the structure, including dynamic pointers. Basically, the memory allocated to these pointers is lost.
To avoid these memory leaks, all dynamic pointers must be freed before calling WIPE(). See object_wipe() for a good example.
Case #2: COPY()
This will do a bit-to-bit copy of the structures, which will copy everything including dynamic pointers. Here, the danger is double: not only the memory allocated to the dynamic pointers associated with the destination is lost (pointer address is replaced), but if you free the source object (assuming the dynamic pointers are properly freed when freeing the source object), you also free the dynamic pointers associated with the destination (since they are now equal)... and you could be in trouble when freeing the destination object (potential double-free of dynamic pointers).
To avoid this problem, all dynamic pointers must be freed before calling COPY, set to NULL after the copy and then copied separately. See object_copy() for a good example.
Case #3: structure copy
This is similar to case #2, as doing struct 2 = struct 1 is the same as doing COPY(&struct 2, &struct 1, struct). Same fix must apply. See scramble_artifact() for a good example of structure copy.
Comment