Skip to content
JavaScript

Enhancing JavaScript Analysis: Leveraging Control Flow Graphs

PVS-Studio introduces control flow graph support to JavaScript analysis, enhancing bug detection and code quality insights.

Topic
JavaScript
Reading time
5 min
Length
1,058 words
Published
Oct 9, 2026
06:39 pm IST
In this article
  1. Understanding Control Flow Graphs
  2. Implementing CFG in PVS-Studio
  3. Example Test Case
  4. Practical Applications
  5. Rolling Out CFG in Existing Codebases
  6. Limitations and Considerations
  7. Future Prospects

We recently added JavaScript/TypeScript support to PVS-Studio analyzer. From its first release, the analyzer can detect control-flow bugs in code. This move lets the static analyzer get a better grip on identifying control-flow bugs in the code. The Control Flow Graph (CFG) exists to address issues with the abstract syntax tree (AST) method; it maps out all possible execution paths in a program.

Understanding Control Flow Graphs

The CFG lays out all the possible execution paths in a program. It's made up of nodes and edges, where:

  • Nodes stand for entry and exit points, along with basic blocks of code. Basic blocks are sequences of instructions with just one way in and one way out.
  • Edges show possible transitions between these nodes, representing the control flow within the program.

Every basic block wraps up with a terminator, which dictates how execution behaves, like branching or continuing a loop. Terminators are special instructions that steer the execution flow: they can represent branching conditions or signal the end of a function. The CFG is useful for spotting unreachable code and other control-flow issues.

Implementing CFG in PVS-Studio

Getting CFG into PVS-Studio's JavaScript/TypeScript analyzer meant building a Common Abstract Tree (CAT) that could handle multilingual analysis. For now, it's just for JavaScript/TypeScript, but it’s set up to add more languages down the road. The CFG construction taps into language-specific details, like untyped exceptions in try blocks and jumps to labels in loops, to model control flow accurately. The analyzer, for instance, knows that labels can only be jumped to within the context of the statement they label, ensuring precise flow representation.

Testing the CFG's correctness wasn't a walk in the park. The idea of serializing the graph for visual inspection came up, but it wasn't reliable because of constant development changes. Instead, a mini-interpreter driven by the CFG was implemented. This interpreter checks the CFG's accuracy by comparing its execution results with those from an actual JavaScript interpreter, using a simple assertion API for validation. This method makes sure the CFG truly mirrors the program's execution semantics.

Example Test Case

@Test
void branching() {
    EvaluationAssert.evaluate("branching")
                    .withParam("param", true)
                    .expect("a", 2);
    EvaluationAssert.evaluate("branching")
                    .withParam("param", false)
                    .expect("a", 0);
}

function branching(param: boolean) {
    let a = 1;
    if (param) {
        a++;
    } else {
        a--;
    }
}

This bare-bones approach not only makes sure the CFG is spot-on but also sets the stage for future data-flow analysis, like taint tracking and conditional constant propagation. Being able to peek at the state of variables at different points without erasing them when they leave scope gives valuable insights for debugging and analysis.

Practical Applications

The CFG boosts PVS-Studio's knack for flagging several kinds of control-flow issues:

  • Unreachable Code: It catches code that never gets executed, like a break statement after a return in a block. This is super useful for spotting redundant code that might stick around unintentionally or by mistake.
  • Loop Analysis: It finds loops that might go on forever or run just once because of unreachable increments or exits. For example, nested loops where the inner loop's increment never gets reached due to a return statement can be flagged.
  • Exception Handling: It digs into complex try-catch-finally structures to make sure all control flow interruptions are covered. This includes finally blocks that might change the flow unexpectedly.

Take the Three.js library, for instance, where the analyzer found an unreachable break statement after a return, showing off its skill in highlighting redundant code paths. These insights are key for keeping code clean and efficient.

Rolling Out CFG in Existing Codebases

If you’re managing a JavaScript or TypeScript codebase, bringing in PVS-Studio's CFG analysis can make a real difference in your code quality. Here's what you might want to do:

  1. Set Up PVS-Studio: Make sure PVS-Studio is part of your development environment. Set it up to regularly go through your codebase. This involves installing the necessary plugins or command-line tools based on how you develop.
  2. Review CFG Warnings: Pay attention to warnings like unreachable code or infinite loops. Dig into these alerts to see what logic errors might be lurking. This review step helps spotlight parts of the code that need closer examination or refactoring.
  3. Refactor Accordingly: Use what you learn from CFG analysis to refactor your code, getting rid of redundant paths and optimizing control flow. This might mean restructuring conditional statements or loops to boost readability and performance.
  4. Leverage for Code Reviews: Bring CFG analysis results into your code review process to catch potential issues early. Sharing these insights with your team encourages writing sturdier code and developing a shared understanding of best practices.

Limitations and Considerations

While CFG gives a lot of insight, it's not the ultimate fix. Here's what to keep in mind:

  • Language Limitations: Right now, CFG support is only for JavaScript and TypeScript. So, teams working with other languages won't see benefits until more implementations come along.
  • Complexity of CFG Construction: Building and keeping up with CFGs can be tough, especially for big codebases with complex control flows. Developers need to watch out for the overhead in terms of processing time and resource use.
  • False Positives: Like any static analysis tool, you might get false positives. It's crucial to look at warnings with a critical eye. Not every warning means there's a real problem, so understanding the context is key for accurate interpretation.

Despite these limitations, the CFG implementation in PVS-Studio is a big leap forward in static analysis capabilities for JavaScript and TypeScript. It lets developers tackle control-flow issues more effectively, leading to cleaner, more maintainable code.

Future Prospects

Adding CFG is just getting started. PVS-Studio plans to extend its CFG capabilities to handle short-circuit expression analysis and other data-flow analysis techniques. These changes will ramp up the tool's ability to catch dead code and other issues, boosting overall code quality. From my experience, it's worth keeping an eye on future updates, as these enhancements can unlock new chances for optimization and error detection.

The integration of CFG into PVS-Studio for JavaScript and TypeScript marks a meaningful development that takes static analysis up a notch. By grasping control flow better, developers can spot and fix potential issues more effectively, making for cleaner and more reliable codebases.

For more insights on JavaScript development and static analysis, check out our article on form engines or explore the SQL formatting tips for JavaScript developers.

Sources

How we made JavaScript analyzer understand control flow

Every claim above was checked against this source before publishing. The analysis, the code and the opinions are mine.

Frequently asked

What is a control flow graph (CFG)?

A CFG is a representation of all possible execution paths in a program, consisting of nodes and edges that map out control flow transitions.

How does CFG improve JavaScript analysis?

CFG allows for more reliable detection of control-flow bugs, such as unreachable code, by mapping execution paths more accurately than AST.

Can CFG be used for languages other than JavaScript and TypeScript?

Currently, CFG support in PVS-Studio is limited to JavaScript and TypeScript, but the framework is designed to be extensible for future language support.

What are the limitations of CFG analysis?

CFG analysis may produce false positives and is currently limited to JavaScript/TypeScript, requiring careful review of warnings and complex CFG construction for large codebases.

Deepak Kumar

Written by

Deepak Kumar

Sr Software Engineer at India Today Group | Aaj Tak · MERN Stack · Generative AI

I have worked in JavaScript daily for nine years, across browser code that has to stay fast and server code that has to stay up. I write here about what those systems actually do once real traffic hits them. Hiring a JavaScript developer in India? Here is how I work.

Message me