Skip to content

C++ extractor crashes with coordinates_of_template_param_symbol assertion on a dependent default non-type template parameter used through a libc++ alias over a pack #22658

Description

@jaf0rk

2.27.1 version has not resolved this issue; the problem still persists:
#22506 (comment).
For the main branch of Chromium, the current CodeQL still loses many things, such as the most basic OnceCallback
and RepeatingCallback classes implemented under the [src/base/functional/](https://source.chromium.org/chromium/
chromium/src/+/main:base/functional/) directory.

CodeQL C++ extractor aborts in coordinates_of_template_param_symbol on Chromium code

Summary

The CodeQL 2.27.1 C++ extractor (extractor version 1.22.1) aborts with an
internal assertion while extracting Chromium translation units:

Warning[extractor-c++]: In construct_text_message: "<file>", line N:
internal error: assertion failed at: "templates.c", line 3973
in coordinates_of_template_param_symbol

Warning[extractor-c++]: In main: Extractor exiting with code 4

The extractor exits with code 4 and the affected translation unit contributes
almost nothing to the database, while codeql database create still exits with
status 0 and reports Successfully created database, so the failure is silent
unless the extractor log is inspected.

The crash reproduces without any Chromium code: a seven-line file that uses
libc++ is enough (Reproduction A). It also reproduces on real Chromium code, both
on a one-line #include and on a real Chromium translation unit compiled with
its own GN build command (Reproduction B).

Environment

  • CodeQL CLI 2.27.1, C++ extractor 1.22.1
  • Linux x64
  • clang 24 (third_party/llvm-build/Release+Asserts/bin/clang++,
    llvmorg-24-init-7747-g62397f8b-29)
  • libc++ from Chromium's third_party/libc++ and third_party/libc++abi
  • Chromium commit 89c312d38e954 (2026-09-22), build directory out/release
  • Language mode -std=c++23

Reproduction A - standalone, no Chromium code

repro_standalone.cc:

#include <type_traits>

template <typename...> struct Pack;

template <typename... Args>
struct Outer {
  template <typename T, bool v = (sizeof(T) > 0)>
  struct Check {};

  using Result = Pack<Check<std::decay_t<Args>>...>;
};

The file is compiled against libc++ only; the Linux sysroot is used for the C
library headers. Compile command (also in repro_standalone_compile.sh):

clang++ -std=c++23 -nostdinc++ \
  -isystem <chromium>/src/third_party/libc++/src/include \
  -isystem <chromium>/src/third_party/libc++abi/src/include \
  -isystem <chromium>/src/buildtools/third_party/libc++ \
  --sysroot=<chromium>/src/build/linux/debian_bullseye_amd64-sysroot \
  -fno-exceptions -fno-rtti \
  -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE \
  -c repro_standalone.cc -o repro_standalone.o

Database creation:

codeql database create repro-standalone-db --language=cpp --source-root=. \
  --command="sh repro_standalone_compile.sh"

Observed output:

Warning[extractor-c++]: In construct_text_message: "repro_standalone.cc", line 5:
internal error: assertion failed at: "templates.c", line 3973
in coordinates_of_template_param_symbol

    template <typename T, bool v = (sizeof(T) > 0)>
                                           ^

Warning[extractor-c++]: In main: Extractor exiting with code 4

Expected: database creation succeeds.

Actual: the extractor aborts with exit code 4. The full log is attached as
logs/standalone_extractor.log.

libc++ is required for this reproduction - the same file compiled against
libstdc++ does not crash.

Reproduction B - real Chromium code

repro_chromium_compile.sh contains the compile command that GN uses for
obj/base/base/concurrent_closures.o in out/release, with the Clang module
flags removed (-DUSE_LIBCXX_MODULES, -fmodules,
-fno-implicit-module-maps, -fno-implicit-modules,
-fmodules-local-submodule-visibility, -fmodules-disable-diagnostic-validation,
-fmodule-file-home-is-cwd, -fmodules-cache-path=...,
-fmodule-map-file=..., -fmodule-file=..., -fmodule-name=...), i.e. the
configuration that results from use_clang_modules = false. All other flags are
unchanged and the object file is written to /tmp.

B1 - real Chromium translation unit

base/functional/concurrent_closures.cc is an ordinary Chromium source file of
the //base:base target. Compiling it with the command above aborts the
extractor:

Warning[extractor-c++]: In construct_text_message:
"../../base/functional/bind_internal.h", line 1227:
internal error: assertion failed at: "templates.c", line 3973
in coordinates_of_template_param_symbol

                  (IsRawRef<T> && IsRefCountedType<base::RemoveRawRefT<T>>) ||
                            ^

Warning[extractor-c++]: In main: Extractor exiting with code 4

Log: logs/chromium_real_tu_extractor.log.

The database creation still reports success, but the translation unit is lost:
this run imports 1.40 KiB of relations, whereas a control run of the same
pipeline on a small standalone file that does not trigger the assertion
(variant 4 below) imports 410.64 KiB. In other words, the affected
translation unit contributes essentially no entities.

B2 - include-only minimisation

repro_chromium.cc is a single line:

#include "base/functional/bind.h"

Compiled with the same command (only the -c argument is changed:
sh repro_chromium_compile.sh repro_chromium.cc), it produces the same
assertion at the same location. Log:
logs/chromium_include_only_extractor.log.

Chromium code involved

base/functional/bind_internal.h:1227:

template <typename... BoundArgs>
struct ValidateBindStateTypeCommonChecks {
 private:
  template <typename T,
            bool v =
                (IsRawRef<T> && IsRefCountedType<base::RemoveRawRefT<T>>) ||
                (IsPointerOrRawPtr<T> && IsRefCountedType<base::RemovePointerT<T>>)>
  struct RefCountedTypeNotPassedByRawPointer { ... };

 public:
  using CommonCheckResult = std::conjunction<
      RefCountedTypeNotPassedByRawPointer<std::decay_t<BoundArgs>>...,
      ValidateStorageTraits<BoundArgs>...>;
};

Minimization

The standalone reproduction was minimized by changing one thing at a time and
re-running codeql database create. Each variant below was extracted on its
own:

  1. Reproducer as shown above (control) - extractor crashes, exit code 4.
  2. std::remove_cv_t<Args> in place of std::decay_t<Args> - extractor
    crashes, exit code 4.
  3. typename std::decay<Args>::type in place of the std::decay_t<Args>
    alias - no crash.
  4. Single type parameter (template <typename Arg>) in place of the pack
    Args... - no crash.
  5. Pack-expansion use of the member template removed
    (using Result = Pack<>;) - no crash.
  6. Non-type parameter and its default argument removed
    (template <typename T> struct Check {};) - no crash.
  7. libstdc++ in place of libc++ - no crash.

Variants 1 and 2 together show that the failure is not specific to decay_t:
any libc++ alias template applied to the pack triggers it, while the non-alias
form (variant 3) does not.

The final reproducer contains no concepts, no std::conjunction, no
static_assert, no lambda and no Chromium header, so none of these is required
for the crash.

Trigger description:

A class template with a parameter pack Args... contains a member class
template template <typename T, bool v = <expression depending on T>>, and the
member template is used as Pack<Check<std::decay_t<Args>>...> - i.e. a libc++
_t alias template applied to the pack feeds the member template whose default
non-type argument references its own template parameter. The extractor aborts
while resolving the coordinates of the template parameter symbol
(templates.c:3973, coordinates_of_template_param_symbol).

Additional observation

In a database created from a full Chromium build with the default modularized
configuration, entities from module-imported headers never reach the database:
base::OnceCallback, base::RepeatingCallback and base::BindOnce have no
results, and practically no classes from base/ are present. This is the symptom
that led us to the crash above. We can supply a separate minimal reproduction for
it if it is useful.

Attachments and how to use them

  • README.md - the same instructions in one file, inside the attached package.
  • repro_standalone.cc, repro_standalone_compile.sh - standalone
    reproduction (Reproduction A). Compile with
    SRC=<chromium>/src sh repro_standalone_compile.sh, or let CodeQL drive it
    with codeql database create repro-standalone-db --language=cpp --source-root=. --command="sh repro_standalone_compile.sh". The script only
    needs a libc++ and a Linux sysroot, no Chromium code.
  • repro_chromium.cc, repro_chromium_compile.sh - Chromium reproduction
    (Reproduction B). The script must run with <chromium>/src/out/release as the
    working directory and the absolute paths inside it adapted to the checkout.
    • sh repro_chromium_compile.sh compiles the real translation unit
      base/functional/concurrent_closures.cc (B1).
    • sh repro_chromium_compile.sh repro_chromium.cc compiles the include-only
      file instead (B2).
    • Under CodeQL:
      codeql database create repro-chromium-db --language=cpp --source-root=<chromium>/src --command="sh repro_chromium_compile.sh".
  • logs/standalone_extractor.log - extractor log for A, showing the assertion.
  • logs/chromium_real_tu_extractor.log - extractor log for the real translation
    unit (B1).
  • logs/chromium_include_only_extractor.log - extractor log for the include-only
    file (B2).

codeql-repro-coordinates_of_template_param_symbol.zip

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions