Skip to content

initialize some uninitialized things#37

Open
briaguya0 wants to merge 4 commits into
HarbourMasters:developfrom
briaguya0:fix-skin-vtx-count-ub
Open

initialize some uninitialized things#37
briaguya0 wants to merge 4 commits into
HarbourMasters:developfrom
briaguya0:fix-skin-vtx-count-ub

Conversation

@briaguya0
Copy link
Copy Markdown
Contributor

@briaguya0 briaguya0 commented Mar 27, 2026

Initialize SkinAnimatedLimbData::totalVtxCount to 0 and dlist to SEGMENTED_NULL

totalVtxCount and dlist had no default values, so limbs that don't go through ParseRawData (non-SkinType_Animated limbs) would export uninitialized data into the OTR file.

the only flow where we get intentional data for these is

segmentStruct.ExtractFromFile(skinSegmentOffset);

in

ZAPDTR/ZAPD/ZLimb.cpp

Lines 105 to 117 in 74a8e9d

case ZLimbType::Skin:
skinSegmentType =
static_cast<ZLimbSkinType>(BitConverter::ToInt32BE(rawData, rawDataIndex + 8));
skinSegment = BitConverter::ToUInt32BE(rawData, rawDataIndex + 12);
if (skinSegmentType == ZLimbSkinType::SkinType_Animated)
{
if (skinSegment != 0 && GETSEGNUM(skinSegment) == parent->segment)
{
uint32_t skinSegmentOffset = Seg2Filespace(skinSegment, parent->baseAddress);
segmentStruct.ExtractFromFile(skinSegmentOffset);
}
}
break;

the rest of

void ZLimb::ParseRawData()

leaves them uninitialized.

totalVtxCount is written unconditionally and read back as skinVtxCnt.

this means we read garbage in OTRExporter_SkeletonLimb::Save

void OTRExporter_SkeletonLimb::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer)
{
	[...]
	writer->Write((uint16_t)limb->segmentStruct.totalVtxCount);

dlist (also in OTRExporter_SkeletonLimb::Save) is checked against SEGMENTED_NULL and passed through GETSEGOFFSET into GetDeclaration.

	if (limb->segmentStruct.dlist != SEGMENTED_NULL)
	{
		auto skinGfxDecl = limb->parent->GetDeclaration(GETSEGOFFSET(limb->segmentStruct.dlist));

If the garbage value's offset happened to match a key in the declarations map, it would write that declaration's path as skinDList2 into the OTR file.

Others

they weren't getting initialized so they had garbage

Initialize SetMesh::data to 0

Initialize RoomShapeImageMultiBgEntry::unk_00 and id to 0

briaguya0 and others added 2 commits March 26, 2026 22:44
totalVtxCount had no default value, so limbs that don't go through
ParseRawData (non-SkinType_Animated limbs) would export uninitialized
data as skinVtxCnt into the OTR file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
dlist is only set in ParseRawData, which is only called for
SkinType_Animated limbs. For all other limb types it is uninitialized.

OTRExporter unconditionally checks segmentStruct.dlist != SEGMENTED_NULL
and passes it through GETSEGOFFSET into GetDeclaration. If the garbage
value's offset happened to match a key in the declarations map, it would
write that declaration's path as skinDList2 into the OTR file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@briaguya0 briaguya0 changed the title Initialize SkinAnimatedLimbData::totalVtxCount to 0 Initialize SkinAnimatedLimbData::totalVtxCount to 0 and dlist to SEGMENTED_NULL Mar 27, 2026
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@briaguya0 briaguya0 changed the title Initialize SkinAnimatedLimbData::totalVtxCount to 0 and dlist to SEGMENTED_NULL initialize some uninitialized things Mar 28, 2026
These fields are only assigned in ParseRawData when isSubStruct is
false (multi-bg entries). For single-bg rooms (isSubStruct=true), they
are left uninitialized but still written by the OTRExporter.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant