Fundamentals 7 min read

Memory Leak Bugs in a 6000‑Line C Module: Lessons from Unit Testing

This article shares practical experiences from unit testing a 6000‑line C module, detailing static code review and dynamic gtest testing, uncovering common defects such as memory leaks, and presenting two memory‑leak case studies with root‑cause analysis and cleanup recommendations.

360 Tech Engineering
360 Tech Engineering
360 Tech Engineering
Memory Leak Bugs in a 6000‑Line C Module: Lessons from Unit Testing

Preface: The author performed unit testing on a critical low‑level C module (~6000 lines) and plans a series of articles to share practical testing experiences, with future white‑box testing theory.

Test object and method: The module was tested using white‑box techniques, starting with static code review (which uncovered about 80% of bugs) and followed by dynamic testing with the open‑source gtest framework, resulting in over 10,000 lines of test code (ratio ~1:1.8 to source, ~1:9 functions to test cases).

Typical defects discovered include memory leaks, boundary‑value errors, illegal memory accesses, incorrect return codes, unreachable branches, division‑by‑zero, redundant parameters, weak logic, logging mistakes, and general robustness issues.

Memory‑leak case study – Bug 1: A function allocates heap memory, throws an exception, and returns before the free statement at the end, causing a leak.

Solution: add appropriate free calls before every early return.

Memory‑leak case study – Bug 2: A complex structure allocates memory in multiple steps; if allocation fails at step N or an exception occurs, previously allocated blocks (1…N‑1) are not released.

Solution: invoke a helper free_String_vector(nodes, j, 0) to clean up all partially allocated memory before exiting.

Root cause analysis: Memory‑release statements are skipped in many scenarios, such as early returns, exceptions, multiple return paths, loops with break/continue, code extensions that add new return paths, and multi‑layer allocations where only the caller frees memory.

Allocate and free within the same function but miss the free due to control‑flow jumps.

Exceptions interrupt execution before freeing.

Multiple return branches without consistent cleanup.

Loop‑based allocations where break/continue bypass free.

Code extensions that forget to add new cleanup paths.

Cross‑function allocations requiring caller‑side cleanup, which need tool‑assisted dynamic testing.

Partial allocation failures in complex structures.

C++ destructors or smart pointers (mentioned as future mitigation).

Tip: The same principles apply to any resource cleanup, such as database connections, file descriptors, mutexes, or sockets.

The author promises future articles on boundary‑value testing and invites readers to follow the public account for more testing techniques.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

software qualityunit testingMemory LeakC programmingstatic analysisDynamic Testing
360 Tech Engineering
Written by

360 Tech Engineering

Official tech channel of 360, building the most professional technology aggregation platform for the brand.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.