Skip to content

Commit cc85761

Browse files
committed
Partial fix for #14960
1 parent d9b785a commit cc85761

2 files changed

Lines changed: 34 additions & 16 deletions

File tree

lib/checkbufferoverrun.cpp

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -620,19 +620,19 @@ ValueFlow::Value CheckBufferOverrunImpl::getBufferSize(const Token *bufTok, cons
620620
}
621621
//---------------------------------------------------------------------------
622622

623-
static bool checkBufferSize(const Token *ftok, const Library::ArgumentChecks::MinSize &minsize, const std::vector<const Token *> &args, const MathLib::bigint bufferSize, const Settings &settings, const Tokenizer* tokenizer)
623+
static bool checkBufferSize(const Token *ftok, const Library::ArgumentChecks::MinSize &minsize, const std::vector<const Token *> &args, ValueFlow::Value& bufferSize, const Settings &settings, const Tokenizer* tokenizer)
624624
{
625625
const Token * const arg = (minsize.arg > 0 && minsize.arg - 1 < args.size()) ? args[minsize.arg - 1] : nullptr;
626626
const Token * const arg2 = (minsize.arg2 > 0 && minsize.arg2 - 1 < args.size()) ? args[minsize.arg2 - 1] : nullptr;
627627

628628
switch (minsize.type) {
629629
case Library::ArgumentChecks::MinSize::Type::STRLEN:
630630
if (settings.library.isargformatstr(ftok, minsize.arg)) {
631-
return getMinFormatStringOutputLength(args, minsize.arg, settings) < bufferSize;
631+
return getMinFormatStringOutputLength(args, minsize.arg, settings) < bufferSize.intvalue;
632632
} else if (arg) {
633633
const Token *strtoken = arg->getValueTokenMaxStrLength();
634634
if (strtoken)
635-
return Token::getStrLength(strtoken) < bufferSize;
635+
return Token::getStrLength(strtoken) < bufferSize.intvalue;
636636
}
637637
break;
638638
case Library::ArgumentChecks::MinSize::Type::ARGVALUE: {
@@ -641,7 +641,14 @@ static bool checkBufferSize(const Token *ftok, const Library::ArgumentChecks::Mi
641641
const int baseSize = tokenizer->sizeOfType(minsize.baseType);
642642
if (baseSize != 0)
643643
myMinsize *= baseSize;
644-
return myMinsize <= bufferSize;
644+
const bool ok = myMinsize <= bufferSize.intvalue;
645+
if (!ok) {
646+
if (bufferSize.errorPath.empty())
647+
bufferSize.errorPath = arg->values().front().errorPath;
648+
if (!bufferSize.condition)
649+
bufferSize.condition = arg->values().front().condition;
650+
}
651+
return ok;
645652
}
646653
break;
647654
}
@@ -650,14 +657,14 @@ static bool checkBufferSize(const Token *ftok, const Library::ArgumentChecks::Mi
650657
break;
651658
case Library::ArgumentChecks::MinSize::Type::MUL:
652659
if (arg && arg2 && arg->hasKnownIntValue() && arg2->hasKnownIntValue())
653-
return (arg->getKnownIntValue() * arg2->getKnownIntValue()) <= bufferSize;
660+
return (arg->getKnownIntValue() * arg2->getKnownIntValue()) <= bufferSize.intvalue;
654661
break;
655662
case Library::ArgumentChecks::MinSize::Type::VALUE: {
656663
MathLib::bigint myMinsize = minsize.value;
657664
const int baseSize = tokenizer->sizeOfType(minsize.baseType);
658665
if (baseSize != 0)
659666
myMinsize *= baseSize;
660-
return myMinsize <= bufferSize;
667+
return myMinsize <= bufferSize.intvalue;
661668
}
662669
case Library::ArgumentChecks::MinSize::Type::NONE:
663670
break;
@@ -695,7 +702,7 @@ void CheckBufferOverrunImpl::bufferOverflow()
695702
if (argtok->valueType() && argtok->valueType()->pointer == 0)
696703
continue;
697704
// TODO: strcpy(buf+10, "hello");
698-
const ValueFlow::Value bufferSize = getBufferSize(argtok, mSettings);
705+
ValueFlow::Value bufferSize = getBufferSize(argtok, mSettings);
699706
if (bufferSize.intvalue <= 0)
700707
continue;
701708
// buffer size == 1 => do not warn for dynamic memory
@@ -714,7 +721,7 @@ void CheckBufferOverrunImpl::bufferOverflow()
714721
}
715722
}
716723
const bool error = std::none_of(minsizes->begin(), minsizes->end(), [&](const Library::ArgumentChecks::MinSize &minsize) {
717-
return checkBufferSize(tok, minsize, args, bufferSize.intvalue, mSettings, mTokenizer);
724+
return checkBufferSize(tok, minsize, args, bufferSize, mSettings, mTokenizer);
718725
});
719726
if (error)
720727
bufferOverflowError(args[argnr], &bufferSize, Certainty::normal);
@@ -726,7 +733,7 @@ void CheckBufferOverrunImpl::bufferOverflow()
726733
void CheckBufferOverrunImpl::bufferOverflowError(const Token *tok, const ValueFlow::Value *value, Certainty certainty)
727734
{
728735
const auto errorPath = getErrorPath(tok, value, "Buffer overrun");
729-
const auto severity = !value || value->isKnown() ? Severity::error : Severity::warning;
736+
const auto severity = !value || (value->isKnown() && !value->condition) ? Severity::error : Severity::warning;
730737
const std::string msg = "Buffer is accessed out of bounds: " + (tok ? getRealBufferTok(tok)->expressionString() : "buf");
731738
reportError(errorPath, severity, "bufferAccessOutOfBounds", msg, CWE_BUFFER_OVERRUN, certainty);
732739
}

test/testbufferoverrun.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3572,13 +3572,6 @@ class TestBufferOverrun : public TestFixture {
35723572
" std::memcpy(&u, &s[0], sizeof(u));\n"
35733573
"}\n");
35743574
ASSERT_EQUALS("", errout_str());
3575-
3576-
check("void f(const std::vector<uint8_t>& s) {\n"
3577-
" if (s.size() == 2) {}\n"
3578-
" uint32_t u = 0;\n"
3579-
" std::memcpy(&u, &s[0], sizeof(u));\n"
3580-
"}\n");
3581-
ASSERT_EQUALS("[test.cpp:4:21]: (warning) Buffer is accessed out of bounds: &s[0] [bufferAccessOutOfBounds]\n", errout_str());
35823575
}
35833576

35843577
void buffer_overrun_errorpath() {
@@ -3593,6 +3586,24 @@ class TestBufferOverrun : public TestFixture {
35933586
ASSERT_EQUALS("[test.cpp:3:12]: error: Buffer is accessed out of bounds: p [bufferAccessOutOfBounds]\n"
35943587
"[test.cpp:2:13]: note: Assign p, buffer with size 10\n"
35953588
"[test.cpp:3:12]: note: Buffer overrun\n", errout_str());
3589+
3590+
check("void f(const std::vector<uint8_t>& s) {\n"
3591+
" if (s.size() == 2) {}\n"
3592+
" uint32_t u = 0;\n"
3593+
" std::memcpy(&u, &s[0], sizeof(u));\n"
3594+
"}\n", s);
3595+
ASSERT_EQUALS("[test.cpp:4:21]: warning: Buffer is accessed out of bounds: &s[0] [bufferAccessOutOfBounds]\n"
3596+
"[test.cpp:2:18]: note: Assuming that condition 's.size()==2' is not redundant\n"
3597+
"[test.cpp:4:21]: note: Buffer overrun\n", errout_str());
3598+
3599+
check("void f(int i) {\n" // #14960
3600+
" int a[1];\n"
3601+
" if (i != 2) return;\n"
3602+
" memset(a, 0, i * sizeof(int));\n"
3603+
"}", s);
3604+
ASSERT_EQUALS("[test.cpp:4:12]: warning: Buffer is accessed out of bounds: a [bufferAccessOutOfBounds]\n"
3605+
"[test.cpp:3:11]: note: Assuming that condition 'i!=2' is not redundant\n"
3606+
"[test.cpp:4:12]: note: Buffer overrun\n", errout_str());
35963607
}
35973608

35983609
void buffer_overrun_bailoutIfSwitch() {

0 commit comments

Comments
 (0)