msacm32: Avoid attempts to convert data when available output is negative in acmStreamConvert
Bruno Jesus
00cpxxx at gmail.com
Sun Nov 22 09:46:33 CST 2015
Signed-off-by: Bruno Jesus <00cpxxx at gmail.com>
The game Lost Horizon passes a negative value in cbDstLength while
calling acmStreamConvert, this means we can't do the conversion
because there is no output buffer available. Cast required since the
value is DWORD.
Fixes https://bugs.winehq.org/show_bug.cgi?id=24723
-------------- next part --------------
diff --git a/dlls/msacm32/stream.c b/dlls/msacm32/stream.c
index bdfc3cc..67c5ce9 100644
--- a/dlls/msacm32/stream.c
+++ b/dlls/msacm32/stream.c
@@ -88,20 +88,25 @@ MMRESULT WINAPI acmStreamConvert(HACMSTREAM has, PACMSTREAMHEADER pash,
if ((was = ACM_GetStream(has)) == NULL) {
WARN("invalid handle\n");
- return MMSYSERR_INVALHANDLE;
+ return MMSYSERR_INVALHANDLE;
}
if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER)) {
WARN("invalid parameter\n");
- return MMSYSERR_INVALPARAM;
+ return MMSYSERR_INVALPARAM;
}
if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED)) {
WARN("unprepared header\n");
- return ACMERR_UNPREPARED;
+ return ACMERR_UNPREPARED;
}
pash->cbSrcLengthUsed = 0;
pash->cbDstLengthUsed = 0;
+ if ((LONG) pash->cbDstLength < 0) {
+ WARN("invalid output length\n");
+ return MMSYSERR_INVALPARAM;
+ }
+
/* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
* size. some fields are private to msacm internals, and are exposed
* in ACMSTREAMHEADER in the dwReservedDriver array
diff --git a/dlls/msacm32/tests/msacm.c b/dlls/msacm32/tests/msacm.c
index 4c9dca0..3b5a446 100644
--- a/dlls/msacm32/tests/msacm.c
+++ b/dlls/msacm32/tests/msacm.c
@@ -527,7 +527,7 @@ static void test_prepareheader(void)
WAVEFORMATEX dst;
MMRESULT mr;
ACMSTREAMHEADER hdr;
- BYTE buf[sizeof(WAVEFORMATEX) + 32], pcm[512], input[512];
+ BYTE buf[sizeof(WAVEFORMATEX) + 32], pcm[2048], input[512];
ADPCMCOEFSET *coef;
src = (ADPCMWAVEFORMAT*)buf;
@@ -567,6 +567,7 @@ static void test_prepareheader(void)
mr = acmStreamOpen(&has, NULL, (WAVEFORMATEX*)src, &dst, NULL, 0, 0, 0);
ok(mr == MMSYSERR_NOERROR, "open failed: 0x%x\n", mr);
+ memset(input, 0, sizeof(input));
memset(&hdr, 0, sizeof(hdr));
hdr.cbStruct = sizeof(hdr);
hdr.pbSrc = input;
@@ -594,10 +595,37 @@ static void test_prepareheader(void)
ok(mr == MMSYSERR_NOERROR, "prepare failed: 0x%x\n", mr);
ok(hdr.fdwStatus == (ACMSTREAMHEADER_STATUSF_PREPARED | ACMSTREAMHEADER_STATUSF_DONE), "header wasn't prepared: 0x%x\n", hdr.fdwStatus);
+ hdr.fdwStatus &= ~ACMSTREAMHEADER_STATUSF_DONE;
+ mr = acmStreamConvert(has, &hdr, ACM_STREAMCONVERTF_BLOCKALIGN);
+ ok(mr == MMSYSERR_NOERROR, "convert failed: 0x%x\n", mr);
+ ok(hdr.fdwStatus & ACMSTREAMHEADER_STATUSF_DONE, "conversion was not done: 0x%x\n", hdr.fdwStatus);
+
mr = acmStreamUnprepareHeader(has, &hdr, 0);
ok(mr == MMSYSERR_NOERROR, "unprepare failed: 0x%x\n", mr);
ok(hdr.fdwStatus == ACMSTREAMHEADER_STATUSF_DONE, "header wasn't unprepared: 0x%x\n", hdr.fdwStatus);
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.cbStruct = sizeof(hdr);
+ hdr.pbSrc = input;
+ hdr.cbSrcLength = sizeof(input);
+ hdr.pbDst = pcm;
+ hdr.cbDstLength = sizeof(pcm);
+
+ mr = acmStreamPrepareHeader(has, &hdr, 0);
+ ok(mr == MMSYSERR_NOERROR, "prepare failed: 0x%x\n", mr);
+ ok(hdr.fdwStatus == ACMSTREAMHEADER_STATUSF_PREPARED, "header wasn't prepared: 0x%x\n", hdr.fdwStatus);
+
+ hdr.cbDstLength = -4; /* Test for Lost Horizon (bug 24723) */
+ hdr.cbDstLengthUsed = 12345;
+ mr = acmStreamConvert(has, &hdr, ACM_STREAMCONVERTF_BLOCKALIGN);
+ ok(mr == MMSYSERR_INVALPARAM, "expected 11, got %d!\n", mr);
+ ok(hdr.cbDstLengthUsed == 0, "expected 0, got %d\n", hdr.cbDstLengthUsed);
+
+ hdr.cbDstLength = sizeof(pcm);
+ mr = acmStreamUnprepareHeader(has, &hdr, 0);
+ ok(mr == MMSYSERR_NOERROR, "unprepare failed: 0x%x\n", mr);
+ ok(hdr.fdwStatus == 0, "header wasn't unprepared: 0x%x\n", hdr.fdwStatus);
+
mr = acmStreamClose(has, 0);
ok(mr == MMSYSERR_NOERROR, "close failed: 0x%x\n", mr);
}
More information about the wine-patches
mailing list