Author: Marco Elver
Date: 2026-01-10T03:08:18+01:00
New Revision: f8629b203693048af6f71e81dc51b59321b74695

URL: 
https://github.com/llvm/llvm-project/commit/f8629b203693048af6f71e81dc51b59321b74695
DIFF: 
https://github.com/llvm/llvm-project/commit/f8629b203693048af6f71e81dc51b59321b74695.diff

LOG: Thread Safety Analysis: Add test for guarded member initialization pattern 
in C (#175267)

A common problem in C code with guarded members is object construction,
where it should be allowed to initialize guarded members without holding
a capability (which itself requires initialization).

One potential pattern to solve this is "init with reentrant assert"
followed by member initialization. The pattern assumes that capability
objects themselves have an init function, which then asserts the
capability as held. To permit immediate use of the capability, we have
to cast to any reentrant capability.

The current implementation of reentrant capability supports this pattern
as-is: Casting to ReentrantMutex works because the analysis determines
if a held lock is reentrant based on the type used when the lock was
added to the fact set. Since the assertion uses the reentrant type, the
analysis records that the lock is reentrant. When the subsequent
mutex_exclusive_lock() occurs, the analyzer checks the properties of the
already held lock; finding it marked as reentrant, it allows the
"re-acquisition" instead of flagging a double-lock error.

Despite the potential for false negatives (real double-lock), the
pattern requires explicit casting to an auxiliary reentrant capability,
so this is not something that can easily happen by accident, but rather
requires developer intent and deliberate use. This is a valid solution
to this problem encountered by the Linux kernel:
https://lore.kernel.org/all/[email protected]/

NFC.

Added: 
    

Modified: 
    clang/test/Sema/warn-thread-safety-analysis.c

Removed: 
    


################################################################################
diff  --git a/clang/test/Sema/warn-thread-safety-analysis.c 
b/clang/test/Sema/warn-thread-safety-analysis.c
index 9ca4b580e2b13..53594609e902d 100644
--- a/clang/test/Sema/warn-thread-safety-analysis.c
+++ b/clang/test/Sema/warn-thread-safety-analysis.c
@@ -248,6 +248,34 @@ void test_reentrant(void) {
   r_ = 1; // expected-warning{{writing variable 'r_' requires holding mutex 
'rmu' exclusively}}
 }
 
+// In C code, object construction may want to initialize guarded members
+// alongside a capability (initialization implies exclusive access); to do so,
+// we can assert a capability as part of its initialization. To permit 
immediate
+// use of the capability, it is necessarily to "promote" the type to a 
reentrant
+// capability for the rest of the scope. While this avoids the false positive
+// warning on member initialization and immediate use, it does pose the danger
+// of false negatives (no warning on actual double-lock in the same function).
+void mutex_init(struct Mutex *mu) ASSERT_EXCLUSIVE_LOCK((struct ReentrantMutex 
*)mu);
+
+struct TestInit {
+  struct Mutex mu;
+  int a GUARDED_BY(&mu);
+};
+
+struct TestInit test_init(void) {
+  struct TestInit foo;
+
+  mutex_init(&foo.mu); // initialize capability before guarded members
+  foo.a = 0;           // initialize guarded members normally
+
+  // It should be allowed to immediately use the capability in the same
+  // function, such as after spawning a thread.
+  mutex_exclusive_lock(&foo.mu);
+  mutex_exclusive_unlock(&foo.mu);
+
+  return foo;
+}
+
 // We had a problem where we'd skip all attributes that follow a late-parsed
 // attribute in a single __attribute__.
 void run(void) __attribute__((guarded_by(mu1), guarded_by(mu1))); // 
expected-warning 2{{only applies to non-static data members and global 
variables}}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to