================
@@ -380,37 +309,41 @@ void BlockInCriticalSectionChecker::checkPostCall(const 
CallEvent &Call,
     return;
   }
 
-  if (std::optional<MutexDescriptor> LockDesc =
-          checkDescriptorMatch(Call, C, /*IsLock=*/true)) {
-    if (!std::holds_alternative<RAIIMutexDescriptor>(*LockDesc))
-      handleLock(*LockDesc, Call, C, C.getState());
+  const ThreadingCallDescription *Desc = lookupThreadingCall(Call);
+  if (!Desc)
     return;
-  }
-  if (std::optional<MutexDescriptor> UnlockDesc =
-          checkDescriptorMatch(Call, C, /*IsLock=*/false)) {
-    handleUnlock(*UnlockDesc, Call, C);
+
+  // RAII constructors are modeled in evalCall so they are not inlined.
+  if (isa<CXXConstructorCall>(Call))
+    return;
+
+  switch (Desc->Role) {
+  case Role::Lock:
+    handleLock(*Desc, Call, C, C.getState());
+    break;
+  case Role::Unlock:
+    handleUnlock(*Desc, Call, C);
+    break;
   }
 }
 
 bool BlockInCriticalSectionChecker::evalCall(const CallEvent &Call,
                                              CheckerContext &C) const {
-  if (std::optional<MutexDescriptor> LockDesc =
-          checkDescriptorMatch(Call, C, /*IsLock=*/true)) {
-    if (std::holds_alternative<RAIIMutexDescriptor>(*LockDesc)) {
-      ProgramStateRef State = C.getState();
-      // Escape the object under construction to model the side-effects of the
-      // constructor.
-      if (const auto *Ctor = dyn_cast<AnyCXXConstructorCall>(&Call)) {
-        const MemRegion *ObjRegion = Ctor->getCXXThisVal().getAsRegion();
-        State = State->invalidateRegions(ObjRegion, C.getCFGElementRef(),
-                                         C.blockCount(), C.getStackFrame(),
-                                         /*CausesPointerEscape=*/false);
-      }
-      handleLock(*LockDesc, Call, C, State);
-      return true;
-    }
+  const ThreadingCallDescription *Desc = lookupThreadingCall(Call);
+  if (!Desc || !isa<CXXConstructorCall>(Call))
+    return false;
----------------
steakhal wrote:

Also here, claude thinks that:

    Previously the gate was 
std::holds_alternative<RAIIMutexDescriptor>(*LockDesc); now any matched entry 
that happens to
    be a constructor gets evaluated as a lock, suppresses inlining, and 
invalidates the object — including the
    Role::Unlock entries. Structurally the function claims to model "RAII lock 
guard constructors" (per the new comment at
    :222) but the condition it actually tests is "some threading call that is a 
constructor".

    Today the only entries a constructor can name-match are {"std","lock"} / 
{"std","unlock"} (a class std::lock /
    std::unlock), so this is latent rather than exploitable — but it is a 
foot-gun for the next entry added to the map,
    and it makes Role dead in evalCall. Consider keying off Desc->GetRegion == 
getObjectUnderConstruction, or adding an
    explicit IsRAIICtor flag / asserting Desc->Role == Role::Lock.

    Evidence: not verified as a behavior change — I could not build a 
non-contrived program that reaches it without also
    tripping the pre-existing cast<CXXMemberCall> assertion in getCXXThisRegion 
(which base hits too, from checkPostCall;
    see below). Reported as a robustness concern, not a regression.

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

Reply via email to