Introduction to Static Code Analysis and Common Scanning Rules with Practical Examples
This article introduces static code analysis, outlines its advantages and disadvantages, presents eight typical scanning rule categories, and demonstrates common pitfalls such as null‑pointer dereferences, logic errors, uninitialized variables, and potential overflow issues with concrete code examples.
Static code analysis, also known as static program analysis, examines source or binary code without executing it, allowing early detection of defects. It mainly targets specific source versions but can also analyze compiled artifacts.
Advantages include the ability to scan code without compilation, rapid issue discovery, automated rule‑based detection of common bugs (null pointers, memory leaks, etc.), broad coverage, and reduced manual review effort.
Disadvantages are limited to naive logical errors, inability to catch business‑logic flaws, and potential noise from overly fine‑grained rules, which can be mitigated by prioritization or filtering.
The typical static scanning rule set comprises eight categories:
Null Pointer checks
Buffer Over‑run checks
Memory Leak detection
Logic errors
Suspicious code
Compute errors
Unsafe function usage
Uninitialized variables
Example 1 – Null Pointer Check : A function checks whether VarA is non‑null before use, but later accesses VarA outside the guarded scope, leading to a potential null‑pointer dereference.
int FuncA::Init(const Config& config, std::class<B> ParamA, ...)
if (VarA) {
VarA->Init(ObjectA);
VarA->FuncB(params);
}
Later code may call VarA->FuncC(params); without a null check, illustrating the flaw.
Example 2 – Logic Error (Invalid Condition) : An if statement combines two conditions with || ( VarB >= 0 || VarB <= 255 ), which is always true, rendering the check ineffective.
void FuncA(params) {
if (VarB >= 0 || VarB <= 255) {
funcB(VarB);
}
}
Example 3 – Uninitialized Variables : Constructor members mVarA and mVarB are assigned without prior initialization, a subtle bug in large codebases.
ClassC(ClassA VarA, ClassB VarB) : VarC(C) {
mVarA = VarA;
mVarB = VarB;
}
Example 4 – Potential Overflow : Different compiler architectures define int and unsigned long sizes variably (16‑bit, 32‑bit, 64‑bit). Multiplying two int values and storing the result in an unsigned long can overflow on some platforms.
Compiler bits int unsigned long 16‑bit 2 bytes 4 bytes 32‑bit 4 bytes 4 bytes 64‑bit 4 bytes 8 bytes
Code illustrating the risk:
void FuncA(int w, int h) {
int varA1 = X.width();
int varB1 = X.height();
int varA2 = Y.width();
int varB2 = Y.height();
const unsigned long varC = varA1 * varA2;
const unsigned long varD = varB1 * varB2;
}
The article concludes by summarizing the importance of understanding static code analysis and hints at future topics covering tool selection and practical application in real projects.
Byte Quality Assurance Team
World-leading audio and video quality assurance team, safeguarding the AV experience of hundreds of millions of users.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.