Skip to content

Commit de4659a

Browse files
committed
Some string APIs operating on UTF-8 buffers do not property compute the length of the UTF-8 buffer in bytes
Many of our string APIs which take LPCUTF8 buffers do not know how many bytes are in those buffers. Typically, these APIs need to walk over the characters in the decoded string so they take in parameters for the number of decoded characters. But the number of decoded characters is not necessarily the same as the number of bytes. This is the case when there are Unicode sequences encoded into the UTF-8 string. As a consequence of this missing info, APIs such as utf8::CharsAreEqual made the assumption that the UTF-8 buffer always contains at least 4 bytes - the maximum number of bytes in a Unicode sequence - without knowing if that was actually true or not. It turned out that this was not always true. This change computes the correct byte length for the APIs which previously made assumptions about the number of bytes in the buffer. Fixes: https://microsoft.visualstudio.com/OS/_workitems?id=10440534&_a=edit
1 parent f4a7690 commit de4659a

20 files changed

Lines changed: 107 additions & 75 deletions

bin/NativeTests/FileLoadHelpers.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ HRESULT FileLoadHelpers::LoadScriptFromFile(LPCSTR filename, LPCWSTR& contents,
119119
IfFailGo(E_OUTOFMEMORY);
120120
}
121121

122-
utf8::DecodeIntoAndNullTerminate((char16*) contents, pRawBytes, cUtf16Chars, decodeOptions);
122+
utf8::DecodeIntoAndNullTerminate((char16*) contents, pRawBytes, pRawBytes + lengthBytes, cUtf16Chars, decodeOptions);
123123
}
124124

125125
Error:

lib/Common/Codex/Utf8Codex.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ namespace utf8
377377
return ptr;
378378
}
379379

380-
void DecodeInto(__out_ecount_full(cch) char16 *buffer, LPCUTF8 ptr, size_t cch, DecodeOptions options)
380+
void DecodeInto(__out_ecount_full(cch) char16 *buffer, LPCUTF8 ptr, LPCUTF8 end, size_t cch, DecodeOptions options)
381381
{
382382
DecodeOptions localOptions = options;
383383

@@ -397,16 +397,14 @@ namespace utf8
397397
LSlowPath:
398398
while (cch-- > 0)
399399
{
400-
LPCUTF8 end = ptr + cch + 1; // WARNING: Assume cch correct, suppress end-of-buffer checking
401-
402400
*buffer++ = Decode(ptr, end, localOptions);
403401
if (ShouldFastPath(ptr, buffer)) goto LFastPath;
404402
}
405403
}
406404

407-
void DecodeIntoAndNullTerminate(__out_ecount(cch+1) __nullterminated char16 *buffer, LPCUTF8 ptr, size_t cch, DecodeOptions options)
405+
void DecodeIntoAndNullTerminate(__out_ecount(cch+1) __nullterminated char16 *buffer, LPCUTF8 ptr, LPCUTF8 end, size_t cch, DecodeOptions options)
408406
{
409-
DecodeInto(buffer, ptr, cch, options);
407+
DecodeInto(buffer, ptr, end, cch, options);
410408
buffer[cch] = 0;
411409
}
412410

@@ -463,13 +461,11 @@ namespace utf8
463461
return result;
464462
}
465463

466-
bool CharsAreEqual(__in_ecount(cch) LPCOLESTR pch, LPCUTF8 bch, size_t cch, DecodeOptions options)
464+
bool CharsAreEqual(__in_ecount(cch) LPCOLESTR pch, LPCUTF8 bch, LPCUTF8 end, size_t cch, DecodeOptions options)
467465
{
468466
DecodeOptions localOptions = options;
469467
while (cch-- > 0)
470468
{
471-
LPCUTF8 end = bch + cch + 1; // WARNING: Assume cch correct, suppress end-of-buffer checking
472-
473469
if (*pch++ != utf8::Decode(bch, end, localOptions))
474470
return false;
475471
}

lib/Common/Codex/Utf8Codex.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ typedef char16_t char16;
2626

2727
typedef char16 wchar;
2828

29+
#ifndef Unused
30+
#define Unused(var) var
31+
#endif
2932

3033
#ifndef _WIN32
3134
// Templates are defined here in order to avoid a dependency on C++
@@ -273,16 +276,17 @@ namespace utf8
273276
// Decode a UTF-8 sequence of cch UTF-16 characters into buffer. ptr could advance up to 3 times
274277
// longer than cch so DecodeInto should only be used when it is already known that
275278
// ptr refers to at least cch number of UTF-8 sequences.
276-
void DecodeInto(__out_ecount_full(cch) char16 *buffer, LPCUTF8 ptr, size_t cch, DecodeOptions options = doDefault);
279+
void DecodeInto(__out_ecount_full(cch) char16 *buffer, LPCUTF8 ptr, LPCUTF8 end, size_t cch, DecodeOptions options = doDefault);
277280

278281
// Provided for dual-mode templates
279-
inline void DecodeInto(__out_ecount_full(cch) char16 *buffer, const char16 *ptr, size_t cch, DecodeOptions /* options */ = doDefault)
282+
inline void DecodeInto(__out_ecount_full(cch) char16 *buffer, const char16 *ptr, const char16 *end, size_t cch, DecodeOptions /* options */ = doDefault)
280283
{
284+
Unused(end);
281285
memcpy_s(buffer, cch * sizeof(char16), ptr, cch * sizeof(char16));
282286
}
283287

284288
// Like DecodeInto but ensures buffer ends with a NULL at buffer[cch].
285-
void DecodeIntoAndNullTerminate(__out_ecount(cch+1) __nullterminated char16 *buffer, LPCUTF8 ptr, size_t cch, DecodeOptions options = doDefault);
289+
void DecodeIntoAndNullTerminate(__out_ecount(cch+1) __nullterminated char16 *buffer, LPCUTF8 ptr, LPCUTF8 end, size_t cch, DecodeOptions options = doDefault);
286290

287291
// Decode cb bytes from ptr to into buffer returning the number of characters converted and written to buffer
288292
_Ret_range_(0, pbEnd - _Old_(pbUtf8))
@@ -316,7 +320,7 @@ namespace utf8
316320
size_t EncodeTrueUtf8IntoAndNullTerminate(__out_ecount(cch * 3 + 1) utf8char_t *buffer, __in_ecount(cch) const char16 *source, charcount_t cch);
317321

318322
// Returns true if the pch refers to a UTF-16LE encoding of the given UTF-8 encoding bch.
319-
bool CharsAreEqual(__in_ecount(cch) LPCOLESTR pch, LPCUTF8 bch, size_t cch, DecodeOptions options = doDefault);
323+
bool CharsAreEqual(__in_ecount(cch) LPCOLESTR pch, LPCUTF8 bch, LPCUTF8 end, size_t cch, DecodeOptions options = doDefault);
320324

321325
// Convert the character index into a byte index.
322326
size_t CharacterIndexToByteIndex(__in_ecount(cbLength) LPCUTF8 pch, size_t cbLength, const charcount_t cchIndex, size_t cbStartIndex, charcount_t cchStartIndex, DecodeOptions options = doDefault);

lib/Common/Codex/Utf8Helper.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,7 @@ namespace utf8
7373
// Some node tests depend on the utf8 decoder not swallowing invalid unicode characters
7474
// instead of replacing them with the "replacement" chracter. Pass a flag to our
7575
// decoder to require such behavior
76-
utf8::DecodeIntoAndNullTerminate(destString, (LPCUTF8) sourceString, cchDestString,
77-
DecodeOptions::doAllowInvalidWCHARs);
76+
utf8::DecodeIntoAndNullTerminate(destString, (LPCUTF8) sourceString, (LPCUTF8) sourceString + cbSourceString, cchDestString, DecodeOptions::doAllowInvalidWCHARs);
7877
Assert(destString[cchDestString] == 0);
7978
static_assert(sizeof(utf8char_t) == sizeof(char), "Needs to be valid for cast");
8079
*destStringPtr = destString;

lib/Jsrt/JsrtDebugUtils.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ void JsrtDebugUtils::AddSourceLengthAndTextToObject(Js::DynamicObject* object, J
5959
Assert(statementMap != nullptr);
6060

6161
LPCUTF8 source = functionBody->GetStartOfDocument(_u("Source for debugging"));
62-
size_t startByte = utf8::CharacterIndexToByteIndex(source, functionBody->GetUtf8SourceInfo()->GetCbLength(), (const charcount_t)statementMap->sourceSpan.begin);
62+
size_t cbLength = functionBody->GetUtf8SourceInfo()->GetCbLength();
63+
size_t startByte = utf8::CharacterIndexToByteIndex(source, cbLength, (const charcount_t)statementMap->sourceSpan.begin);
6364

6465
int byteLength = statementMap->sourceSpan.end - statementMap->sourceSpan.begin;
6566

@@ -69,7 +70,7 @@ void JsrtDebugUtils::AddSourceLengthAndTextToObject(Js::DynamicObject* object, J
6970
if (sourceContent != nullptr)
7071
{
7172
utf8::DecodeOptions options = functionBody->GetUtf8SourceInfo()->IsCesu8() ? utf8::doAllowThreeByteSurrogates : utf8::doDefault;
72-
utf8::DecodeIntoAndNullTerminate(sourceContent, source + startByte, byteLength, options);
73+
utf8::DecodeIntoAndNullTerminate(sourceContent, source + startByte, source + startByte + cbLength, byteLength, options);
7374
JsrtDebugUtils::AddPropertyToObject(object, JsrtDebugPropertyId::sourceText, sourceContent, byteLength, functionBody->GetScriptContext());
7475
}
7576
else
@@ -92,8 +93,10 @@ void JsrtDebugUtils::AddSouceToObject(Js::DynamicObject * object, Js::Utf8Source
9293
AutoArrayPtr<char16> sourceContent(HeapNewNoThrowArray(char16, cchLength + 1), cchLength + 1);
9394
if (sourceContent != nullptr)
9495
{
96+
LPCUTF8 source = utf8SourceInfo->GetSource();
97+
size_t cbLength = utf8SourceInfo->GetCbLength();
9598
utf8::DecodeOptions options = utf8SourceInfo->IsCesu8() ? utf8::doAllowThreeByteSurrogates : utf8::doDefault;
96-
utf8::DecodeIntoAndNullTerminate(sourceContent, utf8SourceInfo->GetSource(), cchLength, options);
99+
utf8::DecodeIntoAndNullTerminate(sourceContent, source, source + cbLength, cchLength, options);
97100
JsrtDebugUtils::AddPropertyToObject(object, JsrtDebugPropertyId::source, sourceContent, cchLength, utf8SourceInfo->GetScriptContext());
98101
}
99102
else

lib/Parser/Hash.cpp

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -209,31 +209,39 @@ IdentPtr HashTbl::PidFromTk(tokens token)
209209
{
210210
StaticSym const * sym = s_reservedWordInfo[token].sym;
211211
Assert(sym != nullptr);
212-
rpid = this->PidHashNameLenWithHash(sym->sz, sym->cch, sym->luHash);
212+
rpid = this->PidHashNameLenWithHash(sym->sz, sym->sz + sym->cch, sym->cch, sym->luHash);
213213
rpid->SetTk(token, s_reservedWordInfo[token].grfid);
214214
m_rpid[token] = rpid;
215215
}
216216
return rpid;
217217
}
218218

219219
template <typename CharType>
220-
IdentPtr HashTbl::PidHashNameLen(CharType const * prgch, uint32 cch)
220+
IdentPtr HashTbl::PidHashNameLen(CharType const * prgch, CharType const * end, uint32 cch)
221221
{
222222
// NOTE: We use case sensitive hash during compilation, but the runtime
223223
// uses case insensitive hashing so it can do case insensitive lookups.
224-
uint32 luHash = CaseSensitiveComputeHashCch(prgch, cch);
225-
return PidHashNameLenWithHash(prgch, cch, luHash);
224+
225+
uint32 luHash = CaseSensitiveComputeHashCch(prgch, end, cch);
226+
return PidHashNameLenWithHash(prgch, end, cch, luHash);
227+
}
228+
229+
template <typename CharType>
230+
IdentPtr HashTbl::PidHashNameLen(CharType const * prgch, uint32 cch)
231+
{
232+
Assert(sizeof(CharType) == 2);
233+
return PidHashNameLen(prgch, prgch + cch, cch);
226234
};
227235
template IdentPtr HashTbl::PidHashNameLen<utf8char_t>(utf8char_t const * prgch, uint32 cch);
228236
template IdentPtr HashTbl::PidHashNameLen<char>(char const * prgch, uint32 cch);
229237
template IdentPtr HashTbl::PidHashNameLen<char16>(char16 const * prgch, uint32 cch);
230238

231239
template <typename CharType>
232-
IdentPtr HashTbl::PidHashNameLenWithHash(_In_reads_(cch) CharType const * prgch, int32 cch, uint32 luHash)
240+
IdentPtr HashTbl::PidHashNameLenWithHash(_In_reads_(cch) CharType const * prgch, CharType const * end, int32 cch, uint32 luHash)
233241
{
234242
Assert(cch >= 0);
235243
AssertArrMemR(prgch, cch);
236-
Assert(luHash == CaseSensitiveComputeHashCch(prgch, cch));
244+
Assert(luHash == CaseSensitiveComputeHashCch(prgch, end, cch));
237245

238246
IdentPtr * ppid;
239247
IdentPtr pid;
@@ -245,7 +253,7 @@ IdentPtr HashTbl::PidHashNameLenWithHash(_In_reads_(cch) CharType const * prgch,
245253
int depth = 0;
246254
#endif
247255

248-
pid = this->FindExistingPid(prgch, cch, luHash, &ppid, &bucketCount
256+
pid = this->FindExistingPid(prgch, end, cch, luHash, &ppid, &bucketCount
249257
#if PROFILE_DICTIONARY
250258
, depth
251259
#endif
@@ -313,14 +321,15 @@ IdentPtr HashTbl::PidHashNameLenWithHash(_In_reads_(cch) CharType const * prgch,
313321
pid->m_propertyId = Js::Constants::NoProperty;
314322
pid->assignmentState = NotAssigned;
315323

316-
HashTbl::CopyString(pid->m_sz, prgch, cch);
324+
HashTbl::CopyString(pid->m_sz, prgch, end, cch);
317325

318326
return pid;
319327
}
320328

321329
template <typename CharType>
322330
IdentPtr HashTbl::FindExistingPid(
323331
CharType const * prgch,
332+
CharType const * end,
324333
int32 cch,
325334
uint32 luHash,
326335
IdentPtr **pppInsert,
@@ -340,7 +349,7 @@ IdentPtr HashTbl::FindExistingPid(
340349
for (bucketCount = 0; nullptr != (pid = *ppid); ppid = &pid->m_pidNext, bucketCount++)
341350
{
342351
if (pid->m_luHash == luHash && (int)pid->m_cch == cch &&
343-
HashTbl::CharsAreEqual(pid->m_sz, prgch, cch))
352+
HashTbl::CharsAreEqual(pid->m_sz, prgch, end, cch))
344353
{
345354
return pid;
346355
}
@@ -362,32 +371,32 @@ IdentPtr HashTbl::FindExistingPid(
362371
}
363372

364373
template IdentPtr HashTbl::FindExistingPid<utf8char_t>(
365-
utf8char_t const * prgch, int32 cch, uint32 luHash, IdentPtr **pppInsert, int32 *pBucketCount
374+
utf8char_t const * prgch, utf8char_t const * end, int32 cch, uint32 luHash, IdentPtr **pppInsert, int32 *pBucketCount
366375
#if PROFILE_DICTIONARY
367376
, int& depth
368377
#endif
369378
);
370379
template IdentPtr HashTbl::FindExistingPid<char>(
371-
char const * prgch, int32 cch, uint32 luHash, IdentPtr **pppInsert, int32 *pBucketCount
380+
char const * prgch, char const * end, int32 cch, uint32 luHash, IdentPtr **pppInsert, int32 *pBucketCount
372381
#if PROFILE_DICTIONARY
373382
, int& depth
374383
#endif
375384
);
376385
template IdentPtr HashTbl::FindExistingPid<char16>(
377-
char16 const * prgch, int32 cch, uint32 luHash, IdentPtr **pppInsert, int32 *pBucketCount
386+
char16 const * prgch, char16 const * end, int32 cch, uint32 luHash, IdentPtr **pppInsert, int32 *pBucketCount
378387
#if PROFILE_DICTIONARY
379388
, int& depth
380389
#endif
381390
);
382391

383392
bool HashTbl::Contains(_In_reads_(cch) LPCOLESTR prgch, int32 cch)
384393
{
385-
uint32 luHash = CaseSensitiveComputeHashCch(prgch, cch);
394+
uint32 luHash = CaseSensitiveComputeHashCch(prgch, prgch + cch, cch);
386395

387396
for (auto pid = m_prgpidName[luHash & m_luMask]; pid; pid = pid->m_pidNext)
388397
{
389398
if (pid->m_luHash == luHash && (int)pid->m_cch == cch &&
390-
HashTbl::CharsAreEqual(pid->m_sz, prgch, cch))
399+
HashTbl::CharsAreEqual(pid->m_sz, prgch + cch, prgch, cch))
391400
{
392401
return true;
393402
}
@@ -407,7 +416,7 @@ bool HashTbl::Contains(_In_reads_(cch) LPCOLESTR prgch, int32 cch)
407416
// This method is used during colorizing when scanner isn't interested in storing the actual id and does not care about conversion of escape sequences
408417
tokens HashTbl::TkFromNameLenColor(_In_reads_(cch) LPCOLESTR prgch, uint32 cch)
409418
{
410-
uint32 luHash = CaseSensitiveComputeHashCch(prgch, cch);
419+
uint32 luHash = CaseSensitiveComputeHashCch(prgch, prgch + cch, cch);
411420

412421
// look for a keyword
413422
#include "kwds_sw.h"
@@ -434,7 +443,7 @@ tokens HashTbl::TkFromNameLenColor(_In_reads_(cch) LPCOLESTR prgch, uint32 cch)
434443
// This method is used during colorizing when scanner isn't interested in storing the actual id and does not care about conversion of escape sequences
435444
tokens HashTbl::TkFromNameLen(_In_reads_(cch) LPCOLESTR prgch, uint32 cch, bool isStrictMode)
436445
{
437-
uint32 luHash = CaseSensitiveComputeHashCch(prgch, cch);
446+
uint32 luHash = CaseSensitiveComputeHashCch(prgch, prgch + cch, cch);
438447

439448
// look for a keyword
440449
#include "kwds_sw.h"

lib/Parser/Hash.h

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ typedef StaticSymLen<0> StaticSym;
2121
/***************************************************************************
2222
Hashing functions. Definitions in core\hashfunc.cpp.
2323
***************************************************************************/
24-
ULONG CaseSensitiveComputeHashCch(LPCOLESTR prgch, int32 cch);
25-
ULONG CaseSensitiveComputeHashCch(LPCUTF8 prgch, int32 cch);
24+
ULONG CaseSensitiveComputeHashCch(LPCOLESTR prgch, LPCOLESTR end, int32 cch);
25+
ULONG CaseSensitiveComputeHashCch(LPCUTF8 prgch, LPCUTF8 end, int32 cch);
2626
ULONG CaseInsensitiveComputeHash(LPCOLESTR posz);
2727

2828
enum
@@ -350,15 +350,18 @@ class HashTbl
350350
return PidHashNameLen(psz, static_cast<uint32>(csz));
351351
}
352352

353+
template <typename CharType>
354+
IdentPtr PidHashNameLen(CharType const * psz, CharType const * end, uint32 cch);
353355
template <typename CharType>
354356
IdentPtr PidHashNameLen(CharType const * psz, uint32 cch);
355357
template <typename CharType>
356-
IdentPtr PidHashNameLenWithHash(_In_reads_(cch) CharType const * psz, int32 cch, uint32 luHash);
358+
IdentPtr PidHashNameLenWithHash(_In_reads_(cch) CharType const * psz, CharType const * end, int32 cch, uint32 luHash);
357359

358360

359361
template <typename CharType>
360362
inline IdentPtr FindExistingPid(
361363
CharType const * prgch,
364+
CharType const * end,
362365
int32 cch,
363366
uint32 luHash,
364367
IdentPtr **pppInsert,
@@ -404,34 +407,38 @@ class HashTbl
404407
uint CountAndVerifyItems(IdentPtr *buckets, uint bucketCount, uint mask);
405408
#endif
406409

407-
static bool CharsAreEqual(__in_z LPCOLESTR psz1, __in_ecount(cch2) LPCOLESTR psz2, int32 cch2)
410+
static bool CharsAreEqual(__in_z LPCOLESTR psz1, __in_ecount(cch2) LPCOLESTR psz2, LPCOLESTR psz2end, int32 cch2)
408411
{
412+
Unused(psz2end);
409413
return memcmp(psz1, psz2, cch2 * sizeof(OLECHAR)) == 0;
410414
}
411-
static bool CharsAreEqual(__in_z LPCOLESTR psz1, LPCUTF8 psz2, int32 cch2)
415+
static bool CharsAreEqual(__in_z LPCOLESTR psz1, LPCUTF8 psz2, LPCUTF8 psz2end, int32 cch2)
412416
{
413-
return utf8::CharsAreEqual(psz1, psz2, cch2, utf8::doAllowThreeByteSurrogates);
417+
return utf8::CharsAreEqual(psz1, psz2, psz2end, cch2, utf8::doAllowThreeByteSurrogates);
414418
}
415-
static bool CharsAreEqual(__in_z LPCOLESTR psz1, __in_ecount(cch2) char const * psz2, int32 cch2)
419+
static bool CharsAreEqual(__in_z LPCOLESTR psz1, __in_ecount(cch2) char const * psz2, char const * psz2end, int32 cch2)
416420
{
421+
Unused(psz2end);
417422
while (cch2-- > 0)
418423
{
419424
if (*psz1++ != *psz2++)
420425
return false;
421426
}
422427
return true;
423428
}
424-
static void CopyString(__in_ecount(cch + 1) LPOLESTR psz1, __in_ecount(cch) LPCOLESTR psz2, int32 cch)
429+
static void CopyString(__in_ecount(cch + 1) LPOLESTR psz1, __in_ecount(cch) LPCOLESTR psz2, LPCOLESTR psz2end, int32 cch)
425430
{
431+
Unused(psz2end);
426432
js_memcpy_s(psz1, cch * sizeof(OLECHAR), psz2, cch * sizeof(OLECHAR));
427433
psz1[cch] = 0;
428434
}
429-
static void CopyString(__in_ecount(cch + 1) LPOLESTR psz1, LPCUTF8 psz2, int32 cch)
435+
static void CopyString(__in_ecount(cch + 1) LPOLESTR psz1, LPCUTF8 psz2, LPCUTF8 psz2end, int32 cch)
430436
{
431-
utf8::DecodeIntoAndNullTerminate(psz1, psz2, cch);
437+
utf8::DecodeIntoAndNullTerminate(psz1, psz2, psz2end, cch);
432438
}
433-
static void CopyString(__in_ecount(cch + 1) LPOLESTR psz1, __in_ecount(cch) char const * psz2, int32 cch)
439+
static void CopyString(__in_ecount(cch + 1) LPOLESTR psz1, __in_ecount(cch) char const * psz2, char const * psz2end, int32 cch)
434440
{
441+
Unused(psz2end);
435442
while (cch-- > 0)
436443
*(psz1++) = *psz2++;
437444
*psz1 = 0;

lib/Parser/HashFunc.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,31 @@
1616
* of the hash function so things don't go out of sync.
1717
*/
1818

19-
ULONG CaseSensitiveComputeHashCch(LPCOLESTR prgch, int32 cch)
19+
ULONG CaseSensitiveComputeHashCch(LPCOLESTR prgch, LPCOLESTR end, int32 cch)
2020
{
21+
Unused(end);
2122
ULONG luHash = 0;
2223

2324
while (cch-- > 0)
2425
luHash = 17 * luHash + *(char16 *)prgch++;
2526
return luHash;
2627
}
2728

28-
ULONG CaseSensitiveComputeHashCch(LPCUTF8 prgch, int32 cch)
29+
ULONG CaseSensitiveComputeHashCch(LPCUTF8 prgch, LPCUTF8 end, int32 cch)
2930
{
3031
utf8::DecodeOptions options = utf8::doAllowThreeByteSurrogates;
3132
ULONG luHash = 0;
3233

3334
while (cch-- > 0)
3435
{
35-
LPCUTF8 end = prgch + cch + 1; // WARNING: Assume cch correct, suppress end-of-buffer checking
36-
3736
luHash = 17 * luHash + utf8::Decode(prgch, end, options);
3837
}
3938
return luHash;
4039
}
4140

42-
ULONG CaseSensitiveComputeHashCch(char const * prgch, int32 cch)
41+
ULONG CaseSensitiveComputeHashCch(char const * prgch, char const * end, int32 cch)
4342
{
43+
Unused(end);
4444
ULONG luHash = 0;
4545

4646
while (cch-- > 0)

0 commit comments

Comments
 (0)