Firefox’s Experiment with Cross‑Translation‑Unit Static Analysis

Mozilla’s security team has long relied on Clang Tidy and the Clang Static Analyzer to surface bugs before shipping new code. In 2025, the team pushed the limits of the analyzer by attempting a whole‑project taint analysis that could follow virtual function calls across translation units (TUs). The effort, documented in an in‑house blog post on Attack & Defense (https://attackanddefense.dev/2025/12/16/attempting-cross-translation-unit-static-analysis.html), reveals both the promise and the pitfalls of extending static analysis to the scale of a modern browser.

Why Cross‑Translation‑Unit Matters

Static analyzers traditionally work on a single TU, building an abstract syntax tree (AST) and simulating execution paths within that file. This works well for many bugs, but taint flows that cross file boundaries—for example, data read from a socket in one file and used in a sink in another—are invisible to a TU‑only analysis. Clang’s CTU mode attempts to mitigate this by loading the relevant pieces of other TUs, but it still struggles with inter‑procedural control flow, especially when virtual functions are involved.

Firefox’s codebase is a sea of virtual functions. A call like p->data() may dispatch to any subclass implementation, and the set of potential callees can span multiple files or even third‑party libraries that are dynamically loaded at runtime. Without knowing the dynamic type, the analyzer must conservatively assume that the call could invoke an unknown function, which hampers precise taint tracking.

The Prototype: Devirtualizing Across the Project

The team’s prototype followed a two‑step approach:

  1. Build a global inheritance graph by parsing every TU and merging their class hierarchies. This allows the analyzer to know all classes that override a given virtual method.
  2. Split the analysis path at each virtual call, creating one branch per known overrider plus an unknown branch for potential dynamic overrides.

Once the graph was merged, the Clang Static Analyzer could inline the known overriders and propagate taint information across the entire project. The prototype succeeded in generating a list of potential overriders for a virtual function and in performing path‑sensitive analysis that respected those overrides.

"The analysis gives a list of the potential overriders of a virtual function. The Clang Static Analyzer was modified to do the path splits we discussed and remember the dynamic type constraints we learn on the way." – Mozilla blog

The Crux: The ASTImporter’s Fragility

CTU relies on Clang’s ASTImporter to bring in declarations from other files. However, the importer is incomplete and bug‑prone:

  • Infinite recursion on certain qualified names (e.g., std::unique_ptr).
  • Crashes when importing large namespaces.
  • Inability to perform minimal imports, leading to unnecessary import of entire declaration contexts.

These issues meant that, even though the prototype could theoretically devirtualize calls, the underlying CTU infrastructure could not reliably bring in the required code. The analysis would stall or crash before reaching the taint‑tracking logic.

"The patch for devirtualizing virtual function calls didn’t really help with the reliability of the ASTImporter. As the interesting taint flows cross file boundaries, the benefits of this new feature are unfortunately limited by the ASTImporter for Firefox." – Mozilla blog

What This Means for Firefox

Because the prototype could not be fully integrated into the nightly build pipeline, the immediate security impact was minimal. However, the experiment highlighted a key limitation: without a robust whole‑project analysis engine, static taint tracking in large, virtual‑function‑heavy codebases remains fragile.

The work also points to future research directions:

  • Improving the ASTImporter to support minimal, non‑recursive imports.
  • Designing a scalable whole‑project analysis framework that can handle dynamic loads and open‑set inheritance.
  • Leveraging the proposed RFC for code‑rewriting tools to adopt a similar whole‑project view.

Mozilla’s prototype, available in Balázs’s GitHub repository (steakhal/llvm-project/devirtualize-for-each-overrider), serves as a proof‑of‑concept rather than production code. It demonstrates that, with a complete and reliable CTU engine, Firefox could gain a powerful new layer of security analysis.

Takeaway

The attempt to extend Clang’s Static Analyzer to perform cross‑translation‑unit taint analysis in Firefox illustrates both the potential and the current limits of static analysis tooling. While the prototype proved that devirtualizing virtual calls can sharpen control‑flow modeling, the fragility of the underlying infrastructure—particularly the ASTImporter—remains a bottleneck. Future work that strengthens CTU support and embraces whole‑project analysis will be essential for securing ever‑more complex codebases.

Source: Mozilla’s internal blog post on Attack & Defense (2025).