Open rupprecht opened 2 years ago
Forgot to add, here's a real piece of code that references this issue: https://github.com/llvm/llvm-project/blob/8d89dbceeb576171efd12a5657c038a2ec2e54a5/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp#L227
The loops are pretty much out of scope I'd say. The analysis collects "symbolic lock expressions", so we just note *m
as locked and basically assume that m
doesn't change while we hold the lock. (If you were to lock *m
, then point to another lock and unlock, we won't complain.) That's kind of what "no alias analysis" is saying: we don't track actual locks, only symbolic expressions. We have no mechanism to track changes to variables used in these lock expressions, nor a concept of having two lock expressions point to the same underlying object.
The bad_unroll
example looks like a bug however: apparently we're not able to distinguish the expressions mutexes[0]
and mutexes[1]
. The expression comparison might be ignoring the additional argument. In any event, if we were to distinguish these expressions, we might produce new warnings elsewhere, so we need to tread carefully. @AaronBallman, @delesley: do you remember whether having the comparison ignore the index was deliberate?
The loops are pretty much out of scope I'd say. The analysis collects "symbolic lock expressions", so we just note
*m
as locked and basically assume thatm
doesn't change while we hold the lock. (If you were to lock*m
, then point to another lock and unlock, we won't complain.) That's kind of what "no alias analysis" is saying: we don't track actual locks, only symbolic expressions. We have no mechanism to track changes to variables used in these lock expressions, nor a concept of having two lock expressions point to the same underlying object.
+1 -- adding alias analysis to this would be a pretty significant amount of effort, and in some ways, would encourage people to write less clear code because we're more relaxed about what we track (thinking about locks through aliased objects seems fraught with cognitive danger unless extreme caution is used).
The
bad_unroll
example looks like a bug however: apparently we're not able to distinguish the expressionsmutexes[0]
andmutexes[1]
. The expression comparison might be ignoring the additional argument. In any event, if we were to distinguish these expressions, we might produce new warnings elsewhere, so we need to tread carefully. @AaronBallman, @delesley: do you remember whether having the comparison ignore the index was deliberate?
I don't recall it being explicit. We added support for array extents in the attribute expression arguments (https://github.com/llvm/llvm-project/blob/891eb20104b6b77c7ff85f532bbce2a28ee9eeb0/clang/lib/Analysis/ThreadSafetyCommon.cpp#L633), but I think we simply missed it in the access check code (https://github.com/llvm/llvm-project/blob/891eb20104b6b77c7ff85f532bbce2a28ee9eeb0/clang/lib/Analysis/ThreadSafety.cpp#L1703).
I found this while making fixes for D129755, but it looks like this is an existing limitation of
-Wthread-safety-analysis
.When using mutexes as part of a collection, thread safety analysis seems to get confused and think that all mutexes in the collection are the same.
The analysis would make sense if we were locking the same mutex over and over again, but
m
is a different mutex on each loop iteration. Maybe the analysis is confused because, due to being in a loop,m
has the same name on each iteration. But it also fails if we unroll:This could be a valid warning if thread safety analysis is conservatively assuming that mutexes[0] and mutexes[1] might point to the same thing, but since alias analysis is unsupported, I don't think that's it.
This might be something that's intentionally unsupported by thread safety analysis, but I didn't see any documentation for it being a known failure.
Live demo: https://godbolt.org/z/1sn5TMj3h