<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 - core.NullDereference despite field being assumed non-null with union-based type punning"
href="https://bugs.llvm.org/show_bug.cgi?id=47054">47054</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>core.NullDereference despite field being assumed non-null with union-based type punning
</td>
</tr>
<tr>
<th>Product</th>
<td>clang
</td>
</tr>
<tr>
<th>Version</th>
<td>trunk
</td>
</tr>
<tr>
<th>Hardware</th>
<td>All
</td>
</tr>
<tr>
<th>OS</th>
<td>All
</td>
</tr>
<tr>
<th>Status</th>
<td>NEW
</td>
</tr>
<tr>
<th>Severity</th>
<td>normal
</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>aaronpuchert@alice-dsl.net
</td>
</tr>
<tr>
<th>CC</th>
<td>dcoughlin@apple.com, llvm-bugs@lists.llvm.org
</td>
</tr></table>
<p>
<div>
<pre>Created <span class=""><a href="attachment.cgi?id=23831" name="attach_23831" title="Reproducer, compile with clang --analyze.">attachment 23831</a> <a href="attachment.cgi?id=23831&action=edit" title="Reproducer, compile with clang --analyze.">[details]</a></span>
Reproducer, compile with clang --analyze.
The attached code produces what I believe is a false positive. It starts here:
struct CommonData {
uint64_t* compilationMemSize = nullptr;
Heap* temp_heap = nullptr;
};
class Postprocessor {
public:
void run();
private:
shared_ptr<CommonData> m_commonData;
};
void Postprocessor::run()
{
auto data = m_commonData;
if (data->temp_heap)
*data->compilationMemSize = data->temp_heap->get_used_size();
}
then it goes into
uint64_t get_used_size() const
{
const frame_type* p = &first_frame;
uint64_t total_size = 0;
while (p && p!=last_frame)
{
total_size += p->size;
p = p->next;
}
return total_size + last_frame_usage;
}
where the check fires on the last line:
analyzer-bug.cpp:100:9: note: Assuming field 'temp_heap' is non-null
if (data->temp_heap)
^~~~~~~~~~~~~~~
analyzer-bug.cpp:100:5: note: Taking true branch
if (data->temp_heap)
^
analyzer-bug.cpp:101:37: note: Calling 'Heap::get_used_size'
*data->compilationMemSize = data->temp_heap->get_used_size();
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
analyzer-bug.cpp:10:16: note: Assuming 'p' is null
while (p && p!=last_frame)
^
analyzer-bug.cpp:10:18: note: Left side of '&&' is false
while (p && p!=last_frame)
^
analyzer-bug.cpp:16:29: note: Access to field 'last_frame_usage' results in a
dereference of a null pointer
return total_size + last_frame_usage;
^~~~~~~~~~~~~~~~
Note that temp_heap is assumed as non-null, and p cannot be null in the first
iteration. The interesting part is the shared_ptr implementation, which uses
union-based type punning. Replacing this by reinterpret_cast or
__builtin_memcpy makes the issue disappear.
template<typename T> class mem_conv
{
template<typename U> union UCast {
U from_;
T to_;
constexpr explicit UCast(U x) noexcept : from_(x) {}
};
public:
template<typename TM_FROM> constexpr
static T cast(TM_FROM from) noexcept
{
static_assert(sizeof(TM_FROM) == sizeof(T));
UCast<TM_FROM> tmp(from);
return tmp.to_;
}
};
Now technically union-based type punning is not allowed according to the
standard, but I believe that Clang supports it.
The reproducer is still a bit large, but I wasn't able to reduce it further, it
seems that multiple things need to come together here.</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>