mirror of
https://github.com/github/codeql.git
synced 2026-04-28 10:15:14 +02:00
Merge pull request #9089 from ihsinme/ihsinme-patch-87
CPP: Add query for CWE-125 Out-of-bounds Read with different interpretation of the string when use mbtowc
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
|
||||
...
|
||||
mbtowc(&wc, ptr, 4)); // BAD:we can get unpredictable results
|
||||
...
|
||||
mbtowc(&wc, ptr, MB_LEN_MAX); // GOOD
|
||||
...
|
||||
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p> Using a function to convert multibyte or wide characters with an invalid length argument may result in an out-of-range access error or unexpected results.</p>
|
||||
|
||||
</overview>
|
||||
|
||||
<example>
|
||||
<p>The following example shows the erroneous and corrected method of using function mbtowc.</p>
|
||||
<sample src="DangerousWorksWithMultibyteOrWideCharacters.cpp" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
CERT Coding Standard:
|
||||
<a href="https://wiki.sei.cmu.edu/confluence/display/c/ARR30-C.+Do+not+form+or+use+out-of-bounds+pointers+or+array+subscripts">ARR30-C. Do not form or use out-of-bounds pointers or array subscripts - SEI CERT C Coding Standard - Confluence</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,236 @@
|
||||
/**
|
||||
* @name Dangerous use convert function.
|
||||
* @description Using convert function with an invalid length argument can result in an out-of-bounds access error or unexpected result.
|
||||
* @kind problem
|
||||
* @id cpp/dangerous-use-convert-function
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @tags correctness
|
||||
* security
|
||||
* external/cwe/cwe-125
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
|
||||
/** Holds if there are indications that the variable is treated as a string. */
|
||||
predicate exprMayBeString(Expr exp) {
|
||||
(
|
||||
exists(StringLiteral sl | globalValueNumber(exp) = globalValueNumber(sl))
|
||||
or
|
||||
exists(FunctionCall fctmp |
|
||||
(
|
||||
fctmp.getAnArgument().(VariableAccess).getTarget() = exp.(VariableAccess).getTarget() or
|
||||
globalValueNumber(fctmp.getAnArgument()) = globalValueNumber(exp)
|
||||
) and
|
||||
fctmp.getTarget().hasName(["strlen", "strcat", "strncat", "strcpy", "sptintf", "printf"])
|
||||
)
|
||||
or
|
||||
exists(AssignExpr astmp |
|
||||
astmp.getRValue().getValue() = "0" and
|
||||
astmp.getLValue().(ArrayExpr).getArrayBase().(VariableAccess).getTarget() =
|
||||
exp.(VariableAccess).getTarget()
|
||||
)
|
||||
or
|
||||
exists(ComparisonOperation cotmp, Expr exptmp1, Expr exptmp2 |
|
||||
exptmp1.getValue() = "0" and
|
||||
(
|
||||
exptmp2.(PointerDereferenceExpr).getOperand().(VariableAccess).getTarget() =
|
||||
exp.(VariableAccess).getTarget() or
|
||||
exptmp2.(ArrayExpr).getArrayBase().(VariableAccess).getTarget() =
|
||||
exp.getAChild().(VariableAccess).getTarget()
|
||||
) and
|
||||
cotmp.hasOperands(exptmp1, exptmp2)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if expression is constant or operator call `sizeof`. */
|
||||
predicate argConstOrSizeof(Expr exp) {
|
||||
exp.getValue().toInt() > 1 or
|
||||
exp.(SizeofTypeOperator).getTypeOperand().getSize() > 1
|
||||
}
|
||||
|
||||
/** Holds if expression is macro. */
|
||||
predicate argMacro(Expr exp) {
|
||||
exists(MacroInvocation matmp |
|
||||
exp = matmp.getExpr() and
|
||||
(
|
||||
matmp.getMacroName() = "MB_LEN_MAX" or
|
||||
matmp.getMacroName() = "MB_CUR_MAX"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if erroneous situations of using functions `mbtowc` and `mbrtowc` are detected. */
|
||||
predicate findUseCharacterConversion(Expr exp, string msg) {
|
||||
exists(FunctionCall fc |
|
||||
fc = exp and
|
||||
(
|
||||
exists(Loop lptmp | lptmp = fc.getEnclosingStmt().getParentStmt*()) and
|
||||
fc.getTarget().hasName(["mbtowc", "mbrtowc", "_mbtowc_l"]) and
|
||||
not fc.getArgument(0).isConstant() and
|
||||
not fc.getArgument(1).isConstant() and
|
||||
(
|
||||
exprMayBeString(fc.getArgument(1)) and
|
||||
argConstOrSizeof(fc.getArgument(2)) and
|
||||
fc.getArgument(2).getValue().toInt() < 5 and
|
||||
not argMacro(fc.getArgument(2)) and
|
||||
msg = "Size can be less than maximum character length, use macro MB_CUR_MAX."
|
||||
or
|
||||
not exprMayBeString(fc.getArgument(1)) and
|
||||
(
|
||||
argConstOrSizeof(fc.getArgument(2))
|
||||
or
|
||||
argMacro(fc.getArgument(2))
|
||||
or
|
||||
exists(DecrementOperation dotmp |
|
||||
globalValueNumber(dotmp.getAnOperand()) = globalValueNumber(fc.getArgument(2)) and
|
||||
not exists(AssignSubExpr aetmp |
|
||||
(
|
||||
aetmp.getLValue().(VariableAccess).getTarget() =
|
||||
fc.getArgument(2).(VariableAccess).getTarget() or
|
||||
globalValueNumber(aetmp.getLValue()) = globalValueNumber(fc.getArgument(2))
|
||||
) and
|
||||
globalValueNumber(aetmp.getRValue()) = globalValueNumber(fc)
|
||||
)
|
||||
)
|
||||
) and
|
||||
msg =
|
||||
"Access beyond the allocated memory is possible, the length can change without changing the pointer."
|
||||
or
|
||||
exists(AssignPointerAddExpr aetmp |
|
||||
(
|
||||
aetmp.getLValue().(VariableAccess).getTarget() =
|
||||
fc.getArgument(0).(VariableAccess).getTarget() or
|
||||
globalValueNumber(aetmp.getLValue()) = globalValueNumber(fc.getArgument(0))
|
||||
) and
|
||||
globalValueNumber(aetmp.getRValue()) = globalValueNumber(fc)
|
||||
) and
|
||||
msg = "Maybe you're using the function's return value incorrectly."
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if detecting erroneous situations of working with multibyte characters. */
|
||||
predicate findUseMultibyteCharacter(Expr exp, string msg) {
|
||||
exists(ArrayType arrayType, ArrayExpr arrayExpr |
|
||||
arrayExpr = exp and
|
||||
arrayExpr.getArrayBase().getType() = arrayType and
|
||||
(
|
||||
exists(AssignExpr assZero, SizeofExprOperator sizeofArray, Expr oneValue |
|
||||
oneValue.getValue() = "1" and
|
||||
sizeofArray.getExprOperand().getType() = arrayType and
|
||||
assZero.getLValue() = arrayExpr and
|
||||
arrayExpr.getArrayOffset().(SubExpr).hasOperands(sizeofArray, oneValue) and
|
||||
assZero.getRValue().getValue() = "0"
|
||||
) and
|
||||
arrayType.getArraySize() != arrayType.getByteSize() and
|
||||
msg =
|
||||
"The size of the array element is greater than one byte, so the offset will point outside the array."
|
||||
or
|
||||
exists(FunctionCall mbFunction |
|
||||
(
|
||||
mbFunction.getTarget().getName().matches("_mbs%") or
|
||||
mbFunction.getTarget().getName().matches("mbs%") or
|
||||
mbFunction.getTarget().getName().matches("_mbc%") or
|
||||
mbFunction.getTarget().getName().matches("mbc%")
|
||||
) and
|
||||
mbFunction.getAnArgument().(VariableAccess).getTarget().getADeclarationEntry().getType() =
|
||||
arrayType
|
||||
) and
|
||||
exists(Loop loop, SizeofExprOperator sizeofArray, AssignExpr assignExpr |
|
||||
arrayExpr.getEnclosingStmt().getParentStmt*() = loop and
|
||||
sizeofArray.getExprOperand().getType() = arrayType and
|
||||
assignExpr.getLValue() = arrayExpr and
|
||||
loop.getCondition().(LTExpr).getLeftOperand().(VariableAccess).getTarget() =
|
||||
arrayExpr.getArrayOffset().getAChild*().(VariableAccess).getTarget() and
|
||||
loop.getCondition().(LTExpr).getRightOperand() = sizeofArray
|
||||
) and
|
||||
msg =
|
||||
"This buffer may contain multibyte characters, so attempting to copy may result in part of the last character being lost."
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(FunctionCall mbccpy, Loop loop, SizeofExprOperator sizeofOp |
|
||||
mbccpy.getTarget().hasName("_mbccpy") and
|
||||
mbccpy.getArgument(0) = exp and
|
||||
exp.getEnclosingStmt().getParentStmt*() = loop and
|
||||
sizeofOp.getExprOperand().getType() =
|
||||
exp.getAChild*().(VariableAccess).getTarget().getADeclarationEntry().getType() and
|
||||
loop.getCondition().(LTExpr).getLeftOperand().(VariableAccess).getTarget() =
|
||||
exp.getAChild*().(VariableAccess).getTarget() and
|
||||
loop.getCondition().(LTExpr).getRightOperand() = sizeofOp and
|
||||
msg =
|
||||
"This buffer may contain multibyte characters, so an attempt to copy may result in an overflow."
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if erroneous situations of using functions `MultiByteToWideChar` and `WideCharToMultiByte` or `mbstowcs` and `_mbstowcs_l` and `mbsrtowcs` are detected. */
|
||||
predicate findUseStringConversion(
|
||||
Expr exp, string msg, int posBufSrc, int posBufDst, int posSizeDst, string nameCalls
|
||||
) {
|
||||
exists(FunctionCall fc |
|
||||
fc = exp and
|
||||
posBufSrc in [0 .. fc.getNumberOfArguments() - 1] and
|
||||
posSizeDst in [0 .. fc.getNumberOfArguments() - 1] and
|
||||
(
|
||||
fc.getTarget().hasName(nameCalls) and
|
||||
(
|
||||
globalValueNumber(fc.getArgument(posBufDst)) = globalValueNumber(fc.getArgument(posBufSrc)) and
|
||||
msg =
|
||||
"According to the definition of the functions, if the source buffer and the destination buffer are the same, undefined behavior is possible."
|
||||
or
|
||||
exists(ArrayType arrayDst |
|
||||
fc.getArgument(posBufDst).(VariableAccess).getTarget().getADeclarationEntry().getType() =
|
||||
arrayDst and
|
||||
fc.getArgument(posSizeDst).getValue().toInt() >= arrayDst.getArraySize() and
|
||||
not exists(AssignExpr assZero |
|
||||
assZero.getLValue().(ArrayExpr).getArrayBase().(VariableAccess).getTarget() =
|
||||
fc.getArgument(posBufDst).(VariableAccess).getTarget() and
|
||||
assZero.getRValue().getValue() = "0"
|
||||
) and
|
||||
not exists(Expr someExp, FunctionCall checkSize |
|
||||
checkSize.getASuccessor*() = fc and
|
||||
checkSize.getTarget().hasName(nameCalls) and
|
||||
checkSize.getArgument(posSizeDst).getValue() = "0" and
|
||||
globalValueNumber(checkSize) = globalValueNumber(someExp) and
|
||||
someExp.getEnclosingStmt().getParentStmt*() instanceof IfStmt
|
||||
) and
|
||||
exprMayBeString(fc.getArgument(posBufDst)) and
|
||||
msg =
|
||||
"According to the definition of the functions, it is not guaranteed to write a null character at the end of the string, so access beyond the bounds of the destination buffer is possible."
|
||||
)
|
||||
or
|
||||
exists(FunctionCall allocMem |
|
||||
allocMem.getTarget().hasName(["calloc", "malloc"]) and
|
||||
globalValueNumber(fc.getArgument(posBufDst)) = globalValueNumber(allocMem) and
|
||||
(
|
||||
allocMem.getArgument(allocMem.getNumberOfArguments() - 1).getValue() = "1" or
|
||||
not exists(SizeofOperator sizeofOperator |
|
||||
globalValueNumber(allocMem
|
||||
.getArgument(allocMem.getNumberOfArguments() - 1)
|
||||
.getAChild*()) = globalValueNumber(sizeofOperator)
|
||||
)
|
||||
) and
|
||||
msg =
|
||||
"The buffer destination has a type other than char, you need to take this into account when allocating memory."
|
||||
)
|
||||
or
|
||||
fc.getArgument(posBufDst).getValue() = "0" and
|
||||
fc.getArgument(posSizeDst).getValue() != "0" and
|
||||
msg =
|
||||
"If the destination buffer is NULL and its size is not 0, then undefined behavior is possible."
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
from Expr exp, string msg
|
||||
where
|
||||
findUseCharacterConversion(exp, msg) or
|
||||
findUseMultibyteCharacter(exp, msg) or
|
||||
findUseStringConversion(exp, msg, 1, 0, 2, ["mbstowcs", "_mbstowcs_l", "mbsrtowcs"]) or
|
||||
findUseStringConversion(exp, msg, 2, 4, 5, ["MultiByteToWideChar", "WideCharToMultiByte"])
|
||||
select exp, msg
|
||||
@@ -0,0 +1,26 @@
|
||||
| test1.cpp:28:5:28:23 | call to WideCharToMultiByte | According to the definition of the functions, if the source buffer and the destination buffer are the same, undefined behavior is possible. |
|
||||
| test1.cpp:29:5:29:23 | call to MultiByteToWideChar | According to the definition of the functions, if the source buffer and the destination buffer are the same, undefined behavior is possible. |
|
||||
| test1.cpp:45:3:45:21 | call to WideCharToMultiByte | According to the definition of the functions, it is not guaranteed to write a null character at the end of the string, so access beyond the bounds of the destination buffer is possible. |
|
||||
| test1.cpp:58:3:58:21 | call to MultiByteToWideChar | The buffer destination has a type other than char, you need to take this into account when allocating memory. |
|
||||
| test1.cpp:70:3:70:21 | call to MultiByteToWideChar | The buffer destination has a type other than char, you need to take this into account when allocating memory. |
|
||||
| test1.cpp:76:10:76:28 | call to WideCharToMultiByte | If the destination buffer is NULL and its size is not 0, then undefined behavior is possible. |
|
||||
| test1.cpp:93:5:93:23 | call to WideCharToMultiByte | According to the definition of the functions, it is not guaranteed to write a null character at the end of the string, so access beyond the bounds of the destination buffer is possible. |
|
||||
| test2.cpp:15:5:15:12 | call to mbstowcs | According to the definition of the functions, if the source buffer and the destination buffer are the same, undefined behavior is possible. |
|
||||
| test2.cpp:17:5:17:15 | call to _mbstowcs_l | According to the definition of the functions, if the source buffer and the destination buffer are the same, undefined behavior is possible. |
|
||||
| test2.cpp:19:5:19:13 | call to mbsrtowcs | According to the definition of the functions, if the source buffer and the destination buffer are the same, undefined behavior is possible. |
|
||||
| test2.cpp:35:3:35:10 | call to mbstowcs | According to the definition of the functions, it is not guaranteed to write a null character at the end of the string, so access beyond the bounds of the destination buffer is possible. |
|
||||
| test2.cpp:48:3:48:10 | call to mbstowcs | The buffer destination has a type other than char, you need to take this into account when allocating memory. |
|
||||
| test2.cpp:60:3:60:10 | call to mbstowcs | The buffer destination has a type other than char, you need to take this into account when allocating memory. |
|
||||
| test2.cpp:66:10:66:17 | call to mbstowcs | If the destination buffer is NULL and its size is not 0, then undefined behavior is possible. |
|
||||
| test2.cpp:80:3:80:10 | call to mbstowcs | According to the definition of the functions, it is not guaranteed to write a null character at the end of the string, so access beyond the bounds of the destination buffer is possible. |
|
||||
| test3.cpp:16:5:16:13 | access to array | This buffer may contain multibyte characters, so attempting to copy may result in part of the last character being lost. |
|
||||
| test3.cpp:36:13:36:18 | ... + ... | This buffer may contain multibyte characters, so an attempt to copy may result in an overflow. |
|
||||
| test3.cpp:47:3:47:24 | access to array | The size of the array element is greater than one byte, so the offset will point outside the array. |
|
||||
| test.cpp:66:27:66:32 | call to mbtowc | Size can be less than maximum character length, use macro MB_CUR_MAX. |
|
||||
| test.cpp:76:27:76:32 | call to mbtowc | Size can be less than maximum character length, use macro MB_CUR_MAX. |
|
||||
| test.cpp:106:11:106:16 | call to mbtowc | Access beyond the allocated memory is possible, the length can change without changing the pointer. |
|
||||
| test.cpp:123:11:123:16 | call to mbtowc | Access beyond the allocated memory is possible, the length can change without changing the pointer. |
|
||||
| test.cpp:140:11:140:16 | call to mbtowc | Access beyond the allocated memory is possible, the length can change without changing the pointer. |
|
||||
| test.cpp:158:11:158:16 | call to mbtowc | Access beyond the allocated memory is possible, the length can change without changing the pointer. |
|
||||
| test.cpp:181:11:181:16 | call to mbtowc | Access beyond the allocated memory is possible, the length can change without changing the pointer. |
|
||||
| test.cpp:197:11:197:16 | call to mbtowc | Maybe you're using the function's return value incorrectly. |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE/CWE-125/DangerousWorksWithMultibyteOrWideCharacters.ql
|
||||
@@ -0,0 +1,206 @@
|
||||
typedef unsigned long size_t;
|
||||
#define MB_CUR_MAX 6
|
||||
#define MB_LEN_MAX 16
|
||||
int mbtowc(wchar_t *out, const char *in, size_t size);
|
||||
int wprintf (const wchar_t* format, ...);
|
||||
int strlen( const char * string );
|
||||
int checkErrors();
|
||||
|
||||
void goodTest0()
|
||||
{
|
||||
char * ptr = "123456789";
|
||||
int ret;
|
||||
int len;
|
||||
len = 9;
|
||||
for (wchar_t wc; (ret = mbtowc(&wc, ptr, len)) > 0; len-=ret) { // GOOD
|
||||
wprintf(L"%lc", wc);
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
void goodTest1(const char* ptr)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
len = strlen(ptr);
|
||||
for (wchar_t wc; (ret = mbtowc(&wc, ptr, len)) > 0; len-=ret) { // GOOD
|
||||
wprintf(L"%lc", wc);
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
void goodTest2(char* ptr)
|
||||
{
|
||||
int ret;
|
||||
ptr[10]=0;
|
||||
int len = 9;
|
||||
for (wchar_t wc; (ret = mbtowc(&wc, ptr, 16)) > 0; len-=ret) { // GOOD
|
||||
wprintf(L"%lc", wc);
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
|
||||
void goodTest3(const char* ptr)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
len = strlen(ptr);
|
||||
for (wchar_t wc; (ret = mbtowc(&wc, ptr, MB_CUR_MAX)) > 0; len-=ret) { // GOOD
|
||||
wprintf(L"%lc", wc);
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
void goodTest4(const char* ptr)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
len = strlen(ptr);
|
||||
for (wchar_t wc; (ret = mbtowc(&wc, ptr, MB_LEN_MAX)) > 0; len-=ret) { // GOOD
|
||||
wprintf(L"%lc", wc);
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
void badTest1(const char* ptr)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
len = strlen(ptr);
|
||||
for (wchar_t wc; (ret = mbtowc(&wc, ptr, 4)) > 0; len-=ret) { // BAD:we can get unpredictable results
|
||||
wprintf(L"%lc", wc);
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
void badTest2(const char* ptr)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
len = strlen(ptr);
|
||||
for (wchar_t wc; (ret = mbtowc(&wc, ptr, sizeof(wchar_t))) > 0; len-=ret) { // BAD:we can get unpredictable results
|
||||
wprintf(L"%lc", wc);
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
|
||||
void goodTest5(const char* ptr,wchar_t *wc,int wc_len)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
len = wc_len;
|
||||
while (*ptr && len > 0) {
|
||||
ret = mbtowc(wc, ptr, len); // GOOD
|
||||
if (ret <0)
|
||||
break;
|
||||
if (ret == 0 || ret > len)
|
||||
break;
|
||||
len-=ret;
|
||||
ptr+=ret;
|
||||
wc++;
|
||||
}
|
||||
}
|
||||
|
||||
void badTest3(const char* ptr,int wc_len)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
len = wc_len;
|
||||
wchar_t *wc = new wchar_t[wc_len];
|
||||
while (*ptr && len > 0) {
|
||||
ret = mbtowc(wc, ptr, MB_CUR_MAX); // BAD
|
||||
if (ret <0)
|
||||
break;
|
||||
if (ret == 0 || ret > len)
|
||||
break;
|
||||
len-=ret;
|
||||
ptr+=ret;
|
||||
wc++;
|
||||
}
|
||||
}
|
||||
void badTest4(const char* ptr,int wc_len)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
len = wc_len;
|
||||
wchar_t *wc = new wchar_t[wc_len];
|
||||
while (*ptr && len > 0) {
|
||||
ret = mbtowc(wc, ptr, 16); // BAD
|
||||
if (ret <0)
|
||||
break;
|
||||
if (ret == 0 || ret > len)
|
||||
break;
|
||||
len-=ret;
|
||||
ptr+=ret;
|
||||
wc++;
|
||||
}
|
||||
}
|
||||
void badTest5(const char* ptr,int wc_len)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
len = wc_len;
|
||||
wchar_t *wc = new wchar_t[wc_len];
|
||||
while (*ptr && len > 0) {
|
||||
ret = mbtowc(wc, ptr, sizeof(wchar_t)); // BAD
|
||||
if (ret <0)
|
||||
break;
|
||||
if (ret == 0 || ret > len)
|
||||
break;
|
||||
len-=ret;
|
||||
ptr+=ret;
|
||||
wc++;
|
||||
}
|
||||
}
|
||||
|
||||
void badTest6(const char* ptr,int wc_len)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
len = wc_len;
|
||||
wchar_t *wc = new wchar_t[wc_len];
|
||||
while (*ptr && wc_len > 0) {
|
||||
ret = mbtowc(wc, ptr, wc_len); // BAD
|
||||
if (ret <0)
|
||||
if (checkErrors()) {
|
||||
++ptr;
|
||||
--len;
|
||||
continue;
|
||||
} else
|
||||
break;
|
||||
if (ret == 0 || ret > len)
|
||||
break;
|
||||
wc_len--;
|
||||
len-=ret;
|
||||
wc++;
|
||||
ptr+=ret;
|
||||
}
|
||||
}
|
||||
void badTest7(const char* ptr,int wc_len)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
len = wc_len;
|
||||
wchar_t *wc = new wchar_t[wc_len];
|
||||
while (*ptr && wc_len > 0) {
|
||||
ret = mbtowc(wc, ptr, len); // BAD
|
||||
if (ret <0)
|
||||
break;
|
||||
if (ret == 0 || ret > len)
|
||||
break;
|
||||
len--;
|
||||
wc++;
|
||||
ptr+=ret;
|
||||
}
|
||||
}
|
||||
void badTest8(const char* ptr,wchar_t *wc)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
len = strlen(ptr);
|
||||
while (*ptr && len > 0) {
|
||||
ret = mbtowc(wc, ptr, len); // BAD
|
||||
if (ret <0)
|
||||
break;
|
||||
if (ret == 0 || ret > len)
|
||||
break;
|
||||
len-=ret;
|
||||
ptr++;
|
||||
wc+=ret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
#define CP_ACP 1
|
||||
#define CP_UTF8 1
|
||||
#define WC_COMPOSITECHECK 1
|
||||
#define NULL 0
|
||||
typedef unsigned int UINT;
|
||||
typedef unsigned long DWORD, *PDWORD, *LPDWORD;
|
||||
typedef char CHAR;
|
||||
#define CONST const
|
||||
typedef wchar_t WCHAR;
|
||||
|
||||
typedef CHAR *LPSTR;
|
||||
typedef CONST CHAR *LPCSTR;
|
||||
typedef CONST WCHAR *LPCWSTR;
|
||||
|
||||
typedef int BOOL;
|
||||
typedef BOOL *LPBOOL;
|
||||
|
||||
|
||||
int WideCharToMultiByte(UINT CodePage,DWORD dwFlags,LPCWSTR lpWideCharStr,int cchWideChar,LPSTR lpMultiByteStr,int cbMultiByte,LPCWSTR lpDefaultChar,LPBOOL lpUsedDefaultChar);
|
||||
int MultiByteToWideChar(UINT CodePage,DWORD dwFlags,LPCSTR lpMultiByteStr,int cbMultiByte,LPCWSTR lpWideCharStr,int cchWideChar);
|
||||
|
||||
int printf ( const char * format, ... );
|
||||
typedef unsigned int size_t;
|
||||
void* calloc (size_t num, size_t size);
|
||||
void* malloc (size_t size);
|
||||
|
||||
void badTest1(void *src, int size) {
|
||||
WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, (LPSTR)src, size, 0, 0); // BAD
|
||||
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, (LPCWSTR)src, 30); // BAD
|
||||
}
|
||||
void goodTest2(){
|
||||
wchar_t src[] = L"0123456789ABCDEF";
|
||||
char dst[16];
|
||||
int res = WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, 16, NULL, NULL); // GOOD
|
||||
if (res == sizeof(dst)) {
|
||||
dst[res-1] = NULL;
|
||||
} else {
|
||||
dst[res] = NULL;
|
||||
}
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
void badTest2(){
|
||||
wchar_t src[] = L"0123456789ABCDEF";
|
||||
char dst[16];
|
||||
WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, 16, NULL, NULL); // BAD
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
void goodTest3(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, src,sizeof(src),NULL,0);
|
||||
wchar_t * dst = (wchar_t*)calloc(size + 1, sizeof(wchar_t));
|
||||
MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size+1); // GOOD
|
||||
}
|
||||
void badTest3(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, src,sizeof(src),NULL,0);
|
||||
wchar_t * dst = (wchar_t*)calloc(size + 1, 1);
|
||||
MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size+1); // BAD
|
||||
}
|
||||
void goodTest4(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, src,sizeof(src),NULL,0);
|
||||
wchar_t * dst = (wchar_t*)malloc((size + 1)*sizeof(wchar_t));
|
||||
MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size+1); // GOOD
|
||||
}
|
||||
void badTest4(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, src,sizeof(src),NULL,0);
|
||||
wchar_t * dst = (wchar_t*)malloc(size + 1);
|
||||
MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size+1); // BAD
|
||||
}
|
||||
int goodTest5(void *src){
|
||||
return WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, 0, 0, 0, 0); // GOOD
|
||||
}
|
||||
int badTest5 (void *src) {
|
||||
return WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, 0, 3, 0, 0); // BAD
|
||||
}
|
||||
void goodTest6(WCHAR *src)
|
||||
{
|
||||
int size;
|
||||
char dst[5] ="";
|
||||
size = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, src, -1, dst, 0, 0, 0);
|
||||
if(size>=sizeof(dst)){
|
||||
printf("buffer size error\n");
|
||||
return;
|
||||
}
|
||||
WideCharToMultiByte(CP_ACP, 0, src, -1, dst, sizeof(dst), 0, 0); // GOOD
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
void badTest6(WCHAR *src)
|
||||
{
|
||||
char dst[5] ="";
|
||||
WideCharToMultiByte(CP_ACP, 0, src, -1, dst, 260, 0, 0); // BAD
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#define NULL 0
|
||||
typedef unsigned int size_t;
|
||||
struct mbstate_t{};
|
||||
struct _locale_t{};
|
||||
int printf ( const char * format, ... );
|
||||
void* calloc (size_t num, size_t size);
|
||||
void* malloc (size_t size);
|
||||
|
||||
size_t mbstowcs(wchar_t *wcstr,const char *mbstr,size_t count);
|
||||
size_t _mbstowcs_l(wchar_t *wcstr,const char *mbstr,size_t count, _locale_t locale);
|
||||
size_t mbsrtowcs(wchar_t *wcstr,const char *mbstr,size_t count, mbstate_t *mbstate);
|
||||
|
||||
|
||||
void badTest1(void *src, int size) {
|
||||
mbstowcs((wchar_t*)src,(char*)src,size); // BAD
|
||||
_locale_t locale;
|
||||
_mbstowcs_l((wchar_t*)src,(char*)src,size,locale); // BAD
|
||||
mbstate_t *mbstate;
|
||||
mbsrtowcs((wchar_t*)src,(char*)src,size,mbstate); // BAD
|
||||
}
|
||||
void goodTest2(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
wchar_t dst[16];
|
||||
int res = mbstowcs(dst, src,16); // GOOD
|
||||
if (res == sizeof(dst)) {
|
||||
dst[res-1] = NULL;
|
||||
} else {
|
||||
dst[res] = NULL;
|
||||
}
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
void badTest2(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
wchar_t dst[16];
|
||||
mbstowcs(dst, src,16); // BAD
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
void goodTest3(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = mbstowcs(NULL, src,NULL);
|
||||
wchar_t * dst = (wchar_t*)calloc(size + 1, sizeof(wchar_t));
|
||||
mbstowcs(dst, src,size+1); // GOOD
|
||||
}
|
||||
void badTest3(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = mbstowcs(NULL, src,NULL);
|
||||
wchar_t * dst = (wchar_t*)calloc(size + 1, 1);
|
||||
mbstowcs(dst, src,size+1); // BAD
|
||||
}
|
||||
void goodTest4(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = mbstowcs(NULL, src,NULL);
|
||||
wchar_t * dst = (wchar_t*)malloc((size + 1)*sizeof(wchar_t));
|
||||
mbstowcs(dst, src,size+1); // GOOD
|
||||
}
|
||||
void badTest4(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = mbstowcs(NULL, src,NULL);
|
||||
wchar_t * dst = (wchar_t*)malloc(size + 1);
|
||||
mbstowcs(dst, src,size+1); // BAD
|
||||
}
|
||||
int goodTest5(void *src){
|
||||
return mbstowcs(NULL, (char*)src,NULL); // GOOD
|
||||
}
|
||||
int badTest5 (void *src) {
|
||||
return mbstowcs(NULL, (char*)src,3); // BAD
|
||||
}
|
||||
void goodTest6(void *src){
|
||||
wchar_t dst[5];
|
||||
int size = mbstowcs(NULL, (char*)src,NULL);
|
||||
if(size>=sizeof(dst)){
|
||||
printf("buffer size error\n");
|
||||
return;
|
||||
}
|
||||
mbstowcs(dst, (char*)src,sizeof(dst)); // GOOD
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
void badTest6(void *src){
|
||||
wchar_t dst[5];
|
||||
mbstowcs(dst, (char*)src,260); // BAD
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#define NULL 0
|
||||
typedef unsigned int size_t;
|
||||
|
||||
unsigned char * _mbsnbcpy(unsigned char * strDest,const unsigned char * strSource,size_t count);
|
||||
size_t _mbclen(const unsigned char *c);
|
||||
void _mbccpy(unsigned char *dest,const unsigned char *src);
|
||||
unsigned char *_mbsinc(const unsigned char *current);
|
||||
void goodTest1(unsigned char *src){
|
||||
unsigned char dst[50];
|
||||
_mbsnbcpy(dst,src,sizeof(dst)); // GOOD
|
||||
}
|
||||
size_t badTest1(unsigned char *src){
|
||||
int cb = 0;
|
||||
unsigned char dst[50];
|
||||
while( cb < sizeof(dst) )
|
||||
dst[cb++]=*src++; // BAD
|
||||
return _mbclen(dst);
|
||||
}
|
||||
void goodTest2(unsigned char *src){
|
||||
|
||||
int cb = 0;
|
||||
unsigned char dst[50];
|
||||
while( (cb + _mbclen(src)) <= sizeof(dst) )
|
||||
{
|
||||
_mbccpy(dst+cb,src); // GOOD
|
||||
cb+=_mbclen(src);
|
||||
src=_mbsinc(src);
|
||||
}
|
||||
}
|
||||
void badTest2(unsigned char *src){
|
||||
|
||||
int cb = 0;
|
||||
unsigned char dst[50];
|
||||
while( cb < sizeof(dst) )
|
||||
{
|
||||
_mbccpy(dst+cb,src); // BAD
|
||||
cb+=_mbclen(src);
|
||||
src=_mbsinc(src);
|
||||
}
|
||||
}
|
||||
void goodTest3(){
|
||||
wchar_t name[50];
|
||||
name[sizeof(name) / sizeof(*name) - 1] = L'\0'; // GOOD
|
||||
}
|
||||
void badTest3(){
|
||||
wchar_t name[50];
|
||||
name[sizeof(name) - 1] = L'\0'; // BAD
|
||||
}
|
||||
Reference in New Issue
Block a user