Skip to content

Conversation

@localspook
Copy link
Contributor

This code:

void f() {
  std::lock_guard<std::mutex> dont_crash {some_nonexistant_variable};
}

Generates an AST like this:

TranslationUnitDecl
`-FunctionDecl <line:3:1, line:5:1> line:3:6 f 'void ()'
  `-CompoundStmt <col:10, line:5:1>
    `-DeclStmt <line:4:3, col:69>
      `-VarDecl <col:3, col:31> col:31 dont_crash 'std::lock_guard<std::mutex>' destroyed

Where the VarDecl has no initializer. The check doesn't expect this and crashes.

@llvmbot
Copy link
Member

llvmbot commented Oct 26, 2025

@llvm/pr-subscribers-clang-tools-extra

@llvm/pr-subscribers-clang-tidy

Author: Victor Chernyakin (localspook)

Changes

This code:

void f() {
  std::lock_guard&lt;std::mutex&gt; dont_crash {some_nonexistant_variable};
}

Generates an AST like this:

TranslationUnitDecl
`-FunctionDecl &lt;line:3:1, line:5:1&gt; line:3:6 f 'void ()'
  `-CompoundStmt &lt;col:10, line:5:1&gt;
    `-DeclStmt &lt;line:4:3, col:69&gt;
      `-VarDecl &lt;col:3, col:31&gt; col:31 dont_crash 'std::lock_guard&lt;std::mutex&gt;' destroyed

Where the VarDecl has no initializer. The check doesn't expect this and crashes.


Full diff: https://github.com/llvm/llvm-project/pull/165127.diff

3 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp (+2-1)
  • (modified) clang-tools-extra/docs/ReleaseNotes.rst (+5)
  • (added) clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-no-crash.cpp (+9)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
index aa1ee6db8917a..5c03c1a3aae9e 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
@@ -217,7 +217,8 @@ void UseScopedLockCheck::diagOnSingleLock(
 
   // Create Fix-its only if we can find the constructor call to properly handle
   // 'std::lock_guard l(m, std::adopt_lock)' case.
-  const auto *CtorCall = dyn_cast<CXXConstructExpr>(LockGuard->getInit());
+  const auto *CtorCall =
+      dyn_cast_if_present<CXXConstructExpr>(LockGuard->getInit());
   if (!CtorCall)
     return;
 
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 33cc401bcb78f..d3e70f11ffaf1 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -364,6 +364,11 @@ Changes in existing checks
   on Windows when the check was enabled with a 32-bit :program:`clang-tidy`
   binary.
 
+- Improved :doc:`modernize-use-scoped-lock
+  <clang-tidy/checks/modernize/use-scoped-lock>` check by fixing a crash
+  on malformed code (common when using :program:`clang-tidy` through
+  :program:`clangd``).
+
 - Improved :doc:`modernize-use-std-format
   <clang-tidy/checks/modernize/use-std-format>` check to correctly match
   when the format string is converted to a different type by an implicit
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-no-crash.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-no-crash.cpp
new file mode 100644
index 0000000000000..587dbe2707873
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-no-crash.cpp
@@ -0,0 +1,9 @@
+// RUN: %check_clang_tidy -std=c++17-or-later -expect-clang-tidy-error %s modernize-use-scoped-lock %t -- -- -isystem %clang_tidy_headers
+
+#include <mutex>
+
+void f() {
+  std::lock_guard<std::mutex> dont_crash {some_nonexistant_variable};
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'std::scoped_lock' instead of 'std::lock_guard' [modernize-use-scoped-lock]
+  // CHECK-MESSAGES: :[[@LINE-2]]:43: error: use of undeclared identifier 'some_nonexistant_variable' [clang-diagnostic-error]
+}

@localspook localspook force-pushed the use-scoped-lock-crash branch from da1c47e to 25c6938 Compare October 26, 2025 03:21
Copy link
Contributor

@vbvictor vbvictor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you!

Copy link
Contributor

@HerrCai0907 HerrCai0907 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@localspook localspook merged commit 7de1a17 into llvm:main Oct 28, 2025
12 checks passed
@localspook localspook deleted the use-scoped-lock-crash branch October 28, 2025 03:04
Lukacma pushed a commit to Lukacma/llvm-project that referenced this pull request Oct 29, 2025
…lvm#165127)

This code:

```cpp
void f() {
  std::lock_guard<std::mutex> dont_crash {some_nonexistant_variable};
}
```

Generates an AST like this:

```txt
TranslationUnitDecl
`-FunctionDecl <line:3:1, line:5:1> line:3:6 f 'void ()'
  `-CompoundStmt <col:10, line:5:1>
    `-DeclStmt <line:4:3, col:69>
      `-VarDecl <col:3, col:31> col:31 dont_crash 'std::lock_guard<std::mutex>' destroyed
```

Where the `VarDecl` has no initializer. The check doesn't expect this
and crashes.
aokblast pushed a commit to aokblast/llvm-project that referenced this pull request Oct 30, 2025
…lvm#165127)

This code:

```cpp
void f() {
  std::lock_guard<std::mutex> dont_crash {some_nonexistant_variable};
}
```

Generates an AST like this:

```txt
TranslationUnitDecl
`-FunctionDecl <line:3:1, line:5:1> line:3:6 f 'void ()'
  `-CompoundStmt <col:10, line:5:1>
    `-DeclStmt <line:4:3, col:69>
      `-VarDecl <col:3, col:31> col:31 dont_crash 'std::lock_guard<std::mutex>' destroyed
```

Where the `VarDecl` has no initializer. The check doesn't expect this
and crashes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants