<html>
<head>
<base href="https://bugs.llvm.org/">
</head>
<body><table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Bug ID</th>
<td><a class="bz_bug_link
bz_status_NEW "
title="NEW - False positive due to truncation of constant when comparing against non-default AS pointer"
href="https://bugs.llvm.org/show_bug.cgi?id=40814">40814</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>False positive due to truncation of constant when comparing against non-default AS pointer
</td>
</tr>
<tr>
<th>Product</th>
<td>clang
</td>
</tr>
<tr>
<th>Version</th>
<td>trunk
</td>
</tr>
<tr>
<th>Hardware</th>
<td>PC
</td>
</tr>
<tr>
<th>OS</th>
<td>Linux
</td>
</tr>
<tr>
<th>Status</th>
<td>NEW
</td>
</tr>
<tr>
<th>Severity</th>
<td>enhancement
</td>
</tr>
<tr>
<th>Priority</th>
<td>P
</td>
</tr>
<tr>
<th>Component</th>
<td>Static Analyzer
</td>
</tr>
<tr>
<th>Assignee</th>
<td>dcoughlin@apple.com
</td>
</tr>
<tr>
<th>Reporter</th>
<td>david.stenberg@ericsson.com
</td>
</tr>
<tr>
<th>CC</th>
<td>dcoughlin@apple.com, llvm-bugs@lists.llvm.org
</td>
</tr></table>
<p>
<div>
<pre>Seen on r354452.
When running:
$ clang --target=amdgcn --analyze ptr-cmp.cl
on the following test case:
#include <stdint.h>
void bar(__global int *p) __attribute__((nonnull(1)));
void foo(__global int *p) {
if ((uint64_t)p <= 1UL << 32)
bar(p);
}
you get a warning for the call to bar():
ptr-cmp.cl:7:5: warning: Null pointer passed as an argument to a 'nonnull'
parameter
bar(p);
^~~~~~
which I think is a false positive. If you change the constant so that any of
its lower 32 bits are set, you don't get a warning. Same goes if you change the
comparison to a less-than operation.
I'm not very well-versed with the analyzer codebase, but as far as I can tell
the issue here seems to be that in SimpleSValBuilder::evalBinOpNN() the
right-hand side is converted to a void pointer for the default address space,
rather than the left-hand side's address space:
case nonloc::ConcreteIntKind: {
// FIXME: at the moment the implementation
// of modeling "pointers as integers" is not complete.
if (!BinaryOperator::isComparisonOp(op))
return UnknownVal();
// Transform the integer into a location and compare.
// FIXME: This only makes sense for comparisons. If we want to, say,
// add 1 to a LocAsInteger, we'd better unpack the Loc and add to it,
// then pack it back into a LocAsInteger.
llvm::APSInt i = rhs.castAs<nonloc::ConcreteInt>().getValue();
BasicVals.getAPSIntType(Context.VoidPtrTy).apply(i);
<---------------------
return evalBinOpLL(state, op, lhsL, makeLoc(i), resultTy);
which in this case means that the constant is truncated from 8 to 4 bytes, so
we get ((uint64_t)p <= 0U) instead.
This can be seen by dumping the state afterwards in
ExprEngine::VisitBinaryOperator():
Store (direct and default bindings), 0x0 :
Expressions by stack frame:
#0 Calling foo
(LC1, S1356) p : &p
(LC1, S1370) p : &SymRegion{reg_$0<__global int * p>}
(LC1, S1373) (uint64_t)p : &SymRegion{reg_$0<__global int * p>} [as 128 bit
integer]
(LC1, S1386) 1UL << 32 : 4294967296 U64b
(LC1, S1390) 1UL << 32 : 4294967296 U128b
(LC1, S1393) (uint64_t)p <= 1UL << 32 : (reg_$0<__global int * p>) <= 0U
<--------------------------
Ranges are empty.</pre>
</div>
</p>
<hr>
<span>You are receiving this mail because:</span>
<ul>
<li>You are on the CC list for the bug.</li>
</ul>
</body>
</html>