[llvm-bugs] [Bug 47054] New: core.NullDereference despite field being assumed non-null with union-based type punning
via llvm-bugs
llvm-bugs at lists.llvm.org
Sat Aug 8 05:12:27 PDT 2020
https://bugs.llvm.org/show_bug.cgi?id=47054
Bug ID: 47054
Summary: core.NullDereference despite field being assumed
non-null with union-based type punning
Product: clang
Version: trunk
Hardware: All
OS: All
Status: NEW
Severity: normal
Priority: P
Component: Static Analyzer
Assignee: dcoughlin at apple.com
Reporter: aaronpuchert at alice-dsl.net
CC: dcoughlin at apple.com, llvm-bugs at lists.llvm.org
Created attachment 23831
--> https://bugs.llvm.org/attachment.cgi?id=23831&action=edit
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.
--
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20200808/0227e97d/attachment-0001.html>
More information about the llvm-bugs
mailing list