[PATCH 0/1] MR10278: d3dxof: Return isolated buffers from IDirectXFileData_GetData().
The original d3dxof.dll does it. Space Empires V writes into the returned buffers for some reason and overwrites adjacent data. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49722 -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10278
From: Joerg Rueppel <joru.ossdev@gmail.com> The original d3dxof.dll does it. Space Empires V writes into the returned buffers for some reason and overwrites adjacent data. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49722 --- dlls/d3dxof/d3dxof.c | 13 ++++++-- dlls/d3dxof/d3dxof_private.h | 1 + dlls/d3dxof/tests/d3dxof.c | 58 ++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/dlls/d3dxof/d3dxof.c b/dlls/d3dxof/d3dxof.c index 250af38c895..3ca07cfb094 100644 --- a/dlls/d3dxof/d3dxof.c +++ b/dlls/d3dxof/d3dxof.c @@ -551,6 +551,7 @@ static ULONG WINAPI IDirectXFileDataImpl_Release(IDirectXFileData *iface) if (!data->level && !data->from_ref) { HeapFree(GetProcessHeap(), 0, data->pstrings); + HeapFree(GetProcessHeap(), 0, data->pdata_user_copy); if (data->pobj) { HeapFree(GetProcessHeap(), 0, data->pobj->pdata); @@ -615,6 +616,14 @@ static HRESULT WINAPI IDirectXFileDataImpl_GetData(IDirectXFileData* iface, LPCS if (!pcbSize || !ppvData) return DXFILEERR_BADVALUE; + if (!This->pdata_user_copy && This->pobj->root->pdata && This->pobj->size > 0) + { + This->pdata_user_copy = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pobj->size); + if (!This->pdata_user_copy) + return DXFILEERR_BADALLOC; + memcpy(This->pdata_user_copy, This->pobj->root->pdata + This->pobj->pos_data, This->pobj->size); + } + if (szMember) { ULONG i; @@ -627,12 +636,12 @@ static HRESULT WINAPI IDirectXFileDataImpl_GetData(IDirectXFileData* iface, LPCS return DXFILEERR_BADDATAREFERENCE; } *pcbSize = This->pobj->members[i].size; - *ppvData = This->pobj->root->pdata + This->pobj->members[i].start; + *ppvData = This->pdata_user_copy + (This->pobj->members[i].start - This->pobj->pos_data); } else { *pcbSize = This->pobj->size; - *ppvData = This->pobj->root->pdata + This->pobj->pos_data; + *ppvData = This->pdata_user_copy; } return DXFILE_OK; diff --git a/dlls/d3dxof/d3dxof_private.h b/dlls/d3dxof/d3dxof_private.h index 9f208dfc9cb..d48a4a5d665 100644 --- a/dlls/d3dxof/d3dxof_private.h +++ b/dlls/d3dxof/d3dxof_private.h @@ -104,6 +104,7 @@ typedef struct { BOOL from_ref; ULONG level; LPBYTE pstrings; + LPBYTE pdata_user_copy; } IDirectXFileDataImpl; typedef struct { diff --git a/dlls/d3dxof/tests/d3dxof.c b/dlls/d3dxof/tests/d3dxof.c index b7b1b1cc502..089ed17188f 100644 --- a/dlls/d3dxof/tests/d3dxof.c +++ b/dlls/d3dxof/tests/d3dxof.c @@ -366,6 +366,8 @@ static char object_complex[] = "3;;;, 0;;;, 1;;;, 2;;;,\n" "3;;;, 1;;;, 2;;;, 3;;;,\n" "3;;;, 3;;;, 1;;;, 2;;;,\n" +/* for heap alloc test */ +"Vector{0.0;;;, 0.0;;;, 0.0;;;}\n" "}\n"; static char template_using_index_color_lower[] = @@ -1005,6 +1007,61 @@ static void test_complex_object(void) IDirectXFile_Release(dxfile); } +static void test_getdata_isolated_heap_alloc(void) +{ + IDirectXFile *dxfile = NULL; + IDirectXFileEnumObject *enum_object; + IDirectXFileData *root_data, *child_data; + IDirectXFileObject *child_obj; + DXFILELOADMEMORY load_info; + HRESULT hr; + size_t distance; + + DWORD root_size, child_size; + void *root_ptr, *child_ptr; + + if (!pDirectXFileCreate) + { + win_skip("DirectXFileCreate is not available\n"); + return; + } + + hr = pDirectXFileCreate(&dxfile); + ok(hr == DXFILE_OK, "Unexpected hr %#lx.\n", hr); + + hr = IDirectXFile_RegisterTemplates(dxfile, templates_complex_object, sizeof(templates_complex_object) - 1); + ok(hr == DXFILE_OK, "Unexpected hr %#lx.\n", hr); + + load_info.lpMemory = object_complex; + load_info.dSize = sizeof(object_complex) - 1; + hr = IDirectXFile_CreateEnumObject(dxfile, &load_info, DXFILELOAD_FROMMEMORY, &enum_object); + ok(hr == DXFILE_OK, "Unexpected hr %#lx.\n", hr); + + hr = IDirectXFileEnumObject_GetNextDataObject(enum_object, &root_data); + ok(hr == DXFILE_OK, "Unexpected hr %#lx.\n", hr); + hr = IDirectXFileData_GetData(root_data, NULL, &root_size, &root_ptr); + ok(hr == DXFILE_OK, "Unexpected hr %#lx.\n", hr); + + hr = IDirectXFileData_GetNextObject(root_data, &child_obj); + ok(hr == DXFILE_OK, "Unexpected hr %#lx.\n", hr); + + hr = IDirectXFileObject_QueryInterface(child_obj, &IID_IDirectXFileData, (void** )&child_data); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IDirectXFileData_GetData(child_data, NULL, &child_size, &child_ptr); + ok(hr == DXFILE_OK, "Unexpected hr %#lx.\n", hr); + + distance = (root_ptr > child_ptr) ? (BYTE*) root_ptr - (BYTE*) child_ptr : (BYTE*) child_ptr - (BYTE*) root_ptr; + ok(distance > root_size + child_size, "GetData returned adjacent pointers into (likely) shared buffer, must be an isolated allocation\n"); + + IDirectXFileData_Release(child_data); + IDirectXFileObject_Release(child_obj); + + IDirectXFileData_Release(root_data); + IDirectXFileEnumObject_Release(enum_object); + IDirectXFile_Release(dxfile); +} + static void test_standard_templates(void) { IDirectXFile *dxfile = NULL; @@ -1061,6 +1118,7 @@ START_TEST(d3dxof) test_syntax(); test_syntax_semicolon_comma(); test_complex_object(); + test_getdata_isolated_heap_alloc(); test_standard_templates(); test_type_index_color(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10278
Does it ignore data size value, or is returned size incorrect? Does it still write past valid buffer size, corrupting heap instead potentially? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10278#note_131625
The returned sizes are correct as far as I can tell. The game seems to have a bounds bug or is doing something "smart" and gets away with it on windows. At some point it writes into the memory adress in the shared buffer where the pointer to the texture file name is stored and increases it by 1 (in some cases, not all). And when that happens, it's looking for the wrong files on disk (missing the first letter - ing instead of ring, p01 instead of rp01). -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10278#note_131626
participants (3)
-
Joerg Rueppel -
Joerg Rueppel (@jrueppel) -
Nikolay Sivov (@nsivov)