From: Brendan McGrath brendan@redmandi.com
Unravel Two adds a reference to the IMediaSample during its callback.
This patch adds a test that checks if an application does do this, that it can free it later and the reference count will finish at zero.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51616 Signed-off-by: Brendan McGrath brendan@redmandi.com Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- v3: Some stylistic fixups; make commit messages a bit more specific.
dlls/qedit/tests/mediadet.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/dlls/qedit/tests/mediadet.c b/dlls/qedit/tests/mediadet.c index 3202baca924..6e7017f865c 100644 --- a/dlls/qedit/tests/mediadet.c +++ b/dlls/qedit/tests/mediadet.c @@ -866,6 +866,17 @@ static void test_put_filter(void) ok(!ref, "Got outstanding refcount %ld.\n", ref); }
+struct test_sample +{ + IMediaSample sample; + LONG refcount; +}; + +static struct test_sample *impl_from_IMediaSample(IMediaSample *iface) +{ + return CONTAINING_RECORD(iface, struct test_sample, sample); +} + static HRESULT WINAPI ms_QueryInterface(IMediaSample *iface, REFIID riid, void **ppvObject) { @@ -874,12 +885,14 @@ static HRESULT WINAPI ms_QueryInterface(IMediaSample *iface, REFIID riid,
static ULONG WINAPI ms_AddRef(IMediaSample *iface) { - return 2; + struct test_sample *sample = impl_from_IMediaSample(iface); + return InterlockedIncrement(&sample->refcount); }
static ULONG WINAPI ms_Release(IMediaSample *iface) { - return 1; + struct test_sample *sample = impl_from_IMediaSample(iface); + return InterlockedDecrement(&sample->refcount); }
static HRESULT WINAPI ms_GetPointer(IMediaSample *iface, BYTE **ppBuffer) @@ -989,7 +1002,7 @@ static const IMediaSampleVtbl my_sample_vt = { ms_SetMediaTime };
-static IMediaSample my_sample = { &my_sample_vt }; +static struct test_sample my_sample = { {&my_sample_vt}, 0 };
static BOOL samplecb_called = FALSE;
@@ -1012,8 +1025,9 @@ static ULONG WINAPI sgcb_Release(ISampleGrabberCB *iface) static HRESULT WINAPI sgcb_SampleCB(ISampleGrabberCB *iface, double SampleTime, IMediaSample *pSample) { - ok(pSample == &my_sample, "Got wrong IMediaSample: %p, expected %p\n", pSample, &my_sample); + ok(pSample == &my_sample.sample, "Got wrong IMediaSample: %p, expected %p\n", pSample, &my_sample); samplecb_called = TRUE; + IMediaSample_AddRef(pSample); return E_NOTIMPL; }
@@ -1043,6 +1057,7 @@ static void test_samplegrabber(void) IEnumPins *pins; HRESULT hr; FILTER_STATE fstate; + ULONG refcount;
/* Invalid RIID */ hr = CoCreateInstance(&CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, &IID_IClassFactory, @@ -1074,10 +1089,13 @@ static void test_samplegrabber(void) hr = IPin_QueryInterface(pin, &IID_IMemInputPin, (void**)&inpin); ok(hr == S_OK, "Got hr %#lx.\n", hr);
- hr = IMemInputPin_Receive(inpin, &my_sample); + hr = IMemInputPin_Receive(inpin, &my_sample.sample); ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(samplecb_called == TRUE, "SampleCB should have been called\n");
+ refcount = IUnknown_Release(&my_sample.sample); + todo_wine ok(!refcount, "Got unexpected refcount %ld.\n", refcount); + IMemInputPin_Release(inpin); IPin_Release(pin);
From: Brendan McGrath brendan@redmandi.com
This patch removes a work around that causes a crash in Unravel Two.
There is a callback in Unravel Two that appears to add a reference to a IMediaSample, which this workaround treats as a leak and releases. However, the application also later releases the reference itself, causing a use-after-free.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51616 Signed-off-by: Brendan McGrath brendan@redmandi.com Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/qedit/samplegrabber.c | 3 --- 1 file changed, 3 deletions(-)
diff --git a/dlls/qedit/samplegrabber.c b/dlls/qedit/samplegrabber.c index 9b9780e564a..cefb2f37078 100644 --- a/dlls/qedit/samplegrabber.c +++ b/dlls/qedit/samplegrabber.c @@ -164,9 +164,6 @@ static void SampleGrabber_callback(struct sample_grabber *This, IMediaSample *sa if (ref) { ERR("(%p) Callback referenced sample %p by %lu\n", This, sample, ref); - /* ugly as hell but some apps are sooo buggy */ - while (ref--) - IMediaSample_Release(sample); } } break;
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=119042
Your paranoid android.
=== debian11 (32 bit report) ===
qedit: mediadet.c:1097: Test succeeded inside todo block: Got unexpected refcount 0.
=== debian11 (32 bit Chinese:China report) ===
qedit: mediadet.c:1097: Test succeeded inside todo block: Got unexpected refcount 0.
=== debian11 (32 bit WoW report) ===
qedit: mediadet.c:1097: Test succeeded inside todo block: Got unexpected refcount 0.
=== debian11 (64 bit WoW report) ===
qedit: mediadet.c:1097: Test succeeded inside todo block: Got unexpected refcount 0.
Unravel Two adds a reference to the IMediaSample during its callback.
This patch adds a test that checks if an application does do this, that it can free it later and the reference count will finish at zero.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51616 Signed-off-by: Brendan McGrath brendan@redmandi.com Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/qedit/tests/mediadet.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/dlls/qedit/tests/mediadet.c b/dlls/qedit/tests/mediadet.c index 3202baca9244..6e7017f865ce 100644 --- a/dlls/qedit/tests/mediadet.c +++ b/dlls/qedit/tests/mediadet.c @@ -866,6 +866,17 @@ static void test_put_filter(void) ok(!ref, "Got outstanding refcount %ld.\n", ref); }
+struct test_sample +{ + IMediaSample sample; + LONG refcount; +}; + +static struct test_sample *impl_from_IMediaSample(IMediaSample *iface) +{ + return CONTAINING_RECORD(iface, struct test_sample, sample); +} + static HRESULT WINAPI ms_QueryInterface(IMediaSample *iface, REFIID riid, void **ppvObject) { @@ -874,12 +885,14 @@ static HRESULT WINAPI ms_QueryInterface(IMediaSample *iface, REFIID riid,
static ULONG WINAPI ms_AddRef(IMediaSample *iface) { - return 2; + struct test_sample *sample = impl_from_IMediaSample(iface); + return InterlockedIncrement(&sample->refcount); }
static ULONG WINAPI ms_Release(IMediaSample *iface) { - return 1; + struct test_sample *sample = impl_from_IMediaSample(iface); + return InterlockedDecrement(&sample->refcount); }
static HRESULT WINAPI ms_GetPointer(IMediaSample *iface, BYTE **ppBuffer) @@ -989,7 +1002,7 @@ static const IMediaSampleVtbl my_sample_vt = { ms_SetMediaTime };
-static IMediaSample my_sample = { &my_sample_vt }; +static struct test_sample my_sample = { {&my_sample_vt}, 0 };
static BOOL samplecb_called = FALSE;
@@ -1012,8 +1025,9 @@ static ULONG WINAPI sgcb_Release(ISampleGrabberCB *iface) static HRESULT WINAPI sgcb_SampleCB(ISampleGrabberCB *iface, double SampleTime, IMediaSample *pSample) { - ok(pSample == &my_sample, "Got wrong IMediaSample: %p, expected %p\n", pSample, &my_sample); + ok(pSample == &my_sample.sample, "Got wrong IMediaSample: %p, expected %p\n", pSample, &my_sample); samplecb_called = TRUE; + IMediaSample_AddRef(pSample); return E_NOTIMPL; }
@@ -1043,6 +1057,7 @@ static void test_samplegrabber(void) IEnumPins *pins; HRESULT hr; FILTER_STATE fstate; + ULONG refcount;
/* Invalid RIID */ hr = CoCreateInstance(&CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, &IID_IClassFactory, @@ -1074,10 +1089,13 @@ static void test_samplegrabber(void) hr = IPin_QueryInterface(pin, &IID_IMemInputPin, (void**)&inpin); ok(hr == S_OK, "Got hr %#lx.\n", hr);
- hr = IMemInputPin_Receive(inpin, &my_sample); + hr = IMemInputPin_Receive(inpin, &my_sample.sample); ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(samplecb_called == TRUE, "SampleCB should have been called\n");
+ refcount = IUnknown_Release(&my_sample.sample); + todo_wine ok(!refcount, "Got unexpected refcount %ld.\n", refcount); + IMemInputPin_Release(inpin); IPin_Release(pin);
This patch removes a work around that causes a crash in Unravel Two.
There is a callback in Unravel Two that appears to add a reference to a IMediaSample, which this workaround treats as a leak and releases. However, the application also later releases the reference itself, causing a use-after-free.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51616 Signed-off-by: Brendan McGrath brendan@redmandi.com Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- v4: Remove todo_wine from test added in patch 1
Thanks again for your time and assistance on this Zeb.
dlls/qedit/samplegrabber.c | 3 --- dlls/qedit/tests/mediadet.c | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/dlls/qedit/samplegrabber.c b/dlls/qedit/samplegrabber.c index 9b9780e564a8..cefb2f370785 100644 --- a/dlls/qedit/samplegrabber.c +++ b/dlls/qedit/samplegrabber.c @@ -164,9 +164,6 @@ static void SampleGrabber_callback(struct sample_grabber *This, IMediaSample *sa if (ref) { ERR("(%p) Callback referenced sample %p by %lu\n", This, sample, ref); - /* ugly as hell but some apps are sooo buggy */ - while (ref--) - IMediaSample_Release(sample); } } break; diff --git a/dlls/qedit/tests/mediadet.c b/dlls/qedit/tests/mediadet.c index 6e7017f865ce..05805c56eb58 100644 --- a/dlls/qedit/tests/mediadet.c +++ b/dlls/qedit/tests/mediadet.c @@ -1094,7 +1094,7 @@ static void test_samplegrabber(void) ok(samplecb_called == TRUE, "SampleCB should have been called\n");
refcount = IUnknown_Release(&my_sample.sample); - todo_wine ok(!refcount, "Got unexpected refcount %ld.\n", refcount); + ok(!refcount, "Got unexpected refcount %ld.\n", refcount);
IMemInputPin_Release(inpin); IPin_Release(pin);