diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 72a567081..747a5847e 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -1481,6 +1481,39 @@ void CheckBufferOverrun::bufferOverrun() { // singlepass checking using ast, symboldatabase and valueflow for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { + if (_settings->isEnabled(Settings::PORTABILITY) && tok->str() == "+" && tok->valueType() && tok->valueType()->pointer > 0) { + if (!tok->astOperand1() || !tok->astOperand1()->valueType()) + continue; + if (!tok->astOperand2() || !tok->astOperand2()->valueType()) + continue; + + // pointer arithmetic.. + const Token *pointerToken, *indexToken; + + if (tok->astOperand1()->valueType()->pointer == 0) { + indexToken = tok->astOperand1(); + pointerToken = tok->astOperand2(); + } else if (tok->astOperand2()->valueType()->pointer == 0) { + indexToken = tok->astOperand2(); + pointerToken = tok->astOperand1(); + } + + while (pointerToken && pointerToken->str() == ".") + pointerToken = pointerToken->astOperand2(); + + if (!pointerToken || !pointerToken->isName()) + continue; + + const Variable *var = pointerToken->variable(); + if (!var || !var->isArray()) + continue; + + const ValueFlow::Value *value = indexToken->getValueGE(var->dimension(0)+1, _settings); + if (value) { + pointerOutOfBoundsError(tok, indexToken, value->intvalue); + } + } + // Array index if (!Token::Match(tok, "%name% [")) continue; @@ -1876,7 +1909,7 @@ MathLib::bigint CheckBufferOverrun::ArrayInfo::totalIndex(const std::vectorisEnabled(Settings::STYLE)) + if (!_settings->isEnabled(Settings::PORTABILITY)) return; const std::size_t functions = symbolDatabase->functionScopes.size(); diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 8886ec97b..5fec58a88 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -185,6 +185,7 @@ private: // char *p2 = a + 11 // UB TEST_CASE(pointer_out_of_bounds_1); TEST_CASE(pointer_out_of_bounds_2); + TEST_CASE(pointer_out_of_bounds_3); TEST_CASE(pointer_out_of_bounds_sub); TEST_CASE(strncat1); @@ -2795,6 +2796,14 @@ private: ASSERT_EQUALS("", errout.str()); } + void pointer_out_of_bounds_3() { + check("struct S { int a[10]; };\n" + "void f(struct S *s) {\n" + " char *p = s->a + 100;\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (portability) Undefined behaviour, pointer arithmetic 's->a+100' is out of bounds.\n", errout.str()); + } + void pointer_out_of_bounds_sub() { check("void f() {\n" " char x[10];\n"