We all do code reviews. Who doesn't admit this – does it twice as often. C++ code reviewers look like a sapper. .. except that they can make a mistake more than once. But sometimes the consequences are painful . Brave code review world.
WSO2CON2024 - Why Should You Consider Ballerina for Your Next Integration
C++ Code as Seen by a Hypercritical Reviewer
1. C++ Code as Seen by a Hypercritical
Reviewer
Phillip Khandeliants
khandeliants@viva64.com
2. About Me
A lead C++/C# developer at PVS-
Studio.
I’ve been developing the C++
analyzer’s core for 3 years.
I educate on modern C++.
2
Текст слайда
4. What are you talking about?
4
We all do code reviews
5. What are you talking about?
5
We all do code reviews
Who doesn't admit this – does it
twice as often
6. What are you talking about?
6
We all do code reviews
Who doesn't admit this – does it
twice as often
C++ code reviewers look like a sapper
7. What are you talking about?
7
We all do code reviews
Who doesn't admit this – does it
twice as often
C++ code reviewers look like a sapper
... except that they can make a
mistake more than once
8. We all do code reviews
Who doesn't admit this – does it
twice as often
C++ code reviewers look like a sapper
... except that they can make a
mistake more than once
But sometimes the consequences
are painful
What are you talking about?
8
11. void foo(const std::vector<....> &vec)
{
....
for (auto i = 0; i < vec.size(); ++i)
{
// do some magic with vec[i]
....
}
....
}
11
12. void foo(const std::vector<....> &vec)
{
....
for (int i = 0; i < vec.size(); ++i) // 64-bit problems :)
{
// do some magic with vec[i]
....
}
....
}
12
13. void foo(const std::vector<....> &vec)
{
....
for (size_t i = 0; i < vec.size(); ++i) // ok
{
// do some magic with vec[i]
....
}
....
}
13
14. void foo(const std::vector<....> &vec)
{
....
for (std::vector<....>::size_type i = 0; i < vec.size(); ++i)
{
// do some magic with vec[i]
....
}
....
}
14
15. void foo(const std::vector<....> &vec)
{
....
for (auto i = 0uLL; i < vec.size(); ++i) // don't do that on
// 128-bit processors
{
// do some magic with vec[i]
....
}
....
}
15
16. void foo(const std::vector<....> &vec)
{
....
for (auto i = 0uLLL; i < vec.size(); ++i) // ok since C++7d
{
// do some magic with vec[i]
....
}
....
}
16
17. void foo(const std::vector<....> &vec)
{
....
for (auto i = 0uLLL; i < vec.size(); ++i) // ok since C++7d
{
// do some magic with vec[i]
....
}
....
}
17
30. void vector8_inc(std::vector<uint8_t> &v)
{
for (size_t i = 0; i < v.size(); i++)
{
v[i]++;
}
}
void vector8_inc(std::vector<uint8_t> &v)
{
auto it = v.begin();
const auto end = v.end();
for (; it != end; ++it)
{
++(*it);
}
}
30
31. 31
vector8_inc(std::vector<uint8_t> &):
mov rax, QWORD PTR [rdi] ; it = begin()
mov rdx, QWORD PTR [rdi+8] ; end = end()
cmp rax, rdx ; if (it == end)
je .L1 ; return
.L3: ; do {
add BYTE PTR [rax], 1 ; ++(*it)
add rax, 1 ; ++it
cmp rax, rdx ; } while (it != end)
.L1:
ret
32. 32
vector8_inc(std::vector<uint8_t> &):
mov rax, QWORD PTR [rdi] ; it = begin()
mov rdx, QWORD PTR [rdi+8] ; end = end()
cmp rax, rdx ; if (it == end)
je .L1 ; return
.L3: ; do {
add BYTE PTR [rax], 1 ; ++(*it)
add rax, 1 ; ++it
cmp rax, rdx ; } while (it != end)
.L1:
ret
108. static void G584_CollectExprInfo(const Ptree *p,
vector<G584_Info> &infs)
{
....
auto what = p->What();
if (what == ntParenExpr)
{
// Remember the expression in parentheses and continue
infs.emplace_back(p, true, true, false, false); // ok since C++20
p = SafeSkipParentesis(p);
}
....
}
108
111. void AddFunctionDangerousInfo(const vstring &strFunctionInfo,
const FunctionDangerousInfo &info)
{
FunctionDangerousInfoMap &infoMap = GetFunctionDangerousInfoMap();
DangerousInfoIterator it = infoMap.find(strFunctionInfo);
if (it == infoMap.end())
{
infoMap.insert(make_pair(strFunctionInfo, dangerousInfo));
}
else
{
FunctionDangerousInfo &a = it->second;
// some works with 'a'
}
}
111
112. void AddFunctionDangerousInfo(const vstring &strFunctionInfo,
const FunctionDangerousInfo &info)
{
FunctionDangerousInfoMap &infoMap = GetFunctionDangerousInfoMap();
DangerousInfoIterator it = infoMap.find(strFunctionInfo);
if (it == infoMap.end())
{
infoMap.insert(make_pair(strFunctionInfo, dangerousInfo));
}
else
{
FunctionDangerousInfo &a = it->second;
// some works with 'a'
}
}
112
113. void AddFunctionDangerousInfo(....)
{
auto &infoMap = GetFunctionDangerousInfoMap();
if (auto it = infoMap.find(strFunctionInfo); it == infoMap.end())
{
infoMap.emplace(strFunctionInfo, dangerousInfo);
}
else
{
FunctionDangerousInfo &a = it->second;
// some works with 'a'
}
}
113
114. void AddFunctionDangerousInfo(....)
{
auto &infoMap = GetFunctionDangerousInfoMap();
if (auto it = infoMap.find(strFunctionInfo); it == infoMap.end())
{
infoMap.emplace(strFunctionInfo, dangerousInfo);
}
else
{
FunctionDangerousInfo &a = it->second;
// some works with 'a'
}
}
114
115. void AddFunctionDangerousInfo(....)
{
auto &infoMap = GetFunctionDangerousInfoMap();
if (auto it = infoMap.lower_bound(strFunctionInfo);
it != infoMap.end())
{
auto &a = it->second;
// some works with 'a'
}
else
{
infoMap.emplace_hint(it,
strFunctionInfo,
dangerousInfo);
}
}
115
116. void AddFunctionDangerousInfo(....)
{
auto &infoMap = GetFunctionDangerousInfoMap();
if (auto it = infoMap.lower_bound(strFunctionInfo);
it != infoMap.end() && it->first == strFunctionInfo)
{
auto &a = it->second;
// some works with 'a'
}
else
{
infoMap.emplace_hint(it,
strFunctionInfo,
dangerousInfo);
}
}
116
119. struct Foo
{
int i;
double d;
};
Foo* bar()
{
Foo *ptr = (Foo *) malloc(sizeof(Foo));
if (ptr == NULL)
return NULL;
ptr->i = 0; // ok in C, UB in C++
ptr->d = 0.0; // ok in C, UB in C++
return ptr;
}
119
120. struct Foo
{
int i;
double d;
};
Foo* bar()
{
Foo *ptr = (Foo *) malloc(sizeof(Foo));
if (ptr == NULL)
return NULL;
new (ptr) Foo;
ptr->i = 0; // ok in C++
ptr->d = 0.0; // ok in C++
return ptr;
}
120
121. struct Foo
{
int i;
double d;
};
Foo* bar()
{
Foo *ptr = (Foo *) malloc(sizeof(Foo));
if (ptr == NULL)
return NULL;
ptr->i = 0; // ok in C, UB in C++ until C++20
ptr->d = 0.0; // ok in C, UB in C++ until C++20
return ptr;
}
121
138. Thou shalt not auto, unless thy faith is strong and pure
138
139. Thou shalt not auto, unless thy faith is strong and pure
Thou shalt not write indexed loops for they are abominations before the Code
139
140. Thou shalt not auto, unless thy faith is strong and pure
Thou shalt not write indexed loops for they are abominations before the Code
Thou shalt wash thy data thoroughly before releasing it
140
141. Thou shalt not auto, unless thy faith is strong and pure
Thou shalt not write indexed loops for they are abominations before the Code
Thou shalt wash thy data thoroughly before releasing it
Thou shalt not accept data from strangers for they might be sinful
141
142. Thou shalt not auto, unless thy faith is strong and pure
Thou shalt not write indexed loops for they are abominations before the Code
Thou shalt wash thy data thoroughly before releasing it
Thou shalt not accept data from strangers for they might be sinful
Thou shalt not copy-paste thy code blocks
142
143. Thy comparison routines shall be correct or else the Wrath of Code will get thee
143
144. Thy comparison routines shall be correct or else the Wrath of Code will get thee
Thou shalt check thy nullables for they are sinful
144
145. Thy comparison routines shall be correct or else the Wrath of Code will get thee
Thou shalt check thy nullables for they are sinful
Thou shalt not push that which can be emplaced
145
146. Thy comparison routines shall be correct or else the Wrath of Code will get thee
Thou shalt check thy nullables for they are sinful
Thou shalt not push that which can be emplaced
Thou shalt not cook signed values with overflow semantics
146
147. Thy comparison routines shall be correct or else the Wrath of Code will get thee
Thou shalt check thy nullables for they are sinful
Thou shalt not push that which can be emplaced
Thou shalt not cook signed values with overflow semantics
He who is without noexcept shall throw, and none other
147