[llvm-bugs] [Bug 39028] New: Scan-build reports a false positive nullptr dereference because it misses calls to template member functions within a copy constructor of a class template
via llvm-bugs
llvm-bugs at lists.llvm.org
Thu Sep 20 14:22:49 PDT 2018
https://bugs.llvm.org/show_bug.cgi?id=39028
Bug ID: 39028
Summary: Scan-build reports a false positive nullptr
dereference because it misses calls to template
member functions within a copy constructor of a class
template
Product: clang
Version: 7.0
Hardware: PC
OS: Linux
Status: NEW
Severity: enhancement
Priority: P
Component: Static Analyzer
Assignee: dcoughlin at apple.com
Reporter: thomas.ullmann at mpibpc.mpg.de
CC: llvm-bugs at lists.llvm.org
Created attachment 20901
--> https://bugs.llvm.org/attachment.cgi?id=20901&action=edit
The full sources and output of scan-build including the html-output
The example is not too short, but I couldn't reduce it further.
I have a class template for a 1D-array defined in a header file
and a main file that includes the header. An instance of the array
is created and copied via the copy constructor to a second instance
of the array. Scan-build reports a false positive "Returning null
reference" if I access an element of the array copy.
The problem only occurs if the array class is defined in a separate
header and if the copy constructor calls a template member function
that does the actual copying. Moving the class template definition
to the main file or substituting the called template member function
with a non-templated version lets the report vanish.
A tar-ball of the complete test input and output including
the HTML report is attached.
/*---------------------------------------------------------
The header for the array class array_1d.h
-----------------------------------------------------------*/
#ifndef ARRAY_1D_H
#define ARRAY_1D_H
#include <memory>
template <class T = double, class Allocator = std::allocator<T> >
class Array1D
{
private:
size_t length1_ = 0;
T* arr_ = nullptr;
Allocator allocator_;
public:
Array1D() : length1_(0), arr_(nullptr) {}
explicit Array1D(const size_t l)
{
length1_ = l;
allocateArray();
}
Array1D(const size_t l, const T& ini)
: Array1D(l)
{
for (size_t i = 0; i < length1_; ++i)
{
arr_[i] = ini;
}
}
Array1D(const Array1D& ini)
: Array1D()
{
initArray(ini); // this call is missed/not followed
}
/*
// The error does not occur with this non-templated function
void initArray(const Array1D& ini)
{
length1_ = ini.length1_;
allocateArray();
for (size_t i = 0; i < length1_; ++i)
{
arr_[i] = ini.arr_[i];
}
}
*/
// The error only occurs with this templated function and
// if the class is not directly defined in the main file test.cpp.
template <typename TForeign, class AForeign = std::allocator<TForeign>
>
void initArray(const Array1D<TForeign, AForeign> &ini)
{
if (ini.arr_ != nullptr)
{
deallocateArray();
if (ini.length1_ != 0)
{
length1_ = ini.length1_;
allocateArray();
}
if (arr_ != nullptr && ini.arr_ != nullptr)
{
for (size_t i = 0; i < length1_; ++i)
{
arr_[i] = static_cast<T>(ini(i));
}
}
}
}
~Array1D() { deallocateArray(); }
T& operator()(const size_t i)
{
return arr_[i];
}
const T& operator()(const size_t i) const
{
return arr_[i];
}
private:
void allocateArray()
{
if (arr_ == nullptr)
{
arr_ = std::allocator_traits<Allocator>::allocate(allocator_,
length1_);
}
for (size_t i = 0; i < length1_; ++i)
{
std::allocator_traits<Allocator>::construct(allocator_,
&arr_[i], T());
}
}
void deallocateArray()
{
if (arr_ != nullptr)
{
for (size_t i = 0; i < length1_; ++i)
{
std::allocator_traits<Allocator>::destroy(allocator_,
&arr_[i]);
}
std::allocator_traits<Allocator>::deallocate(allocator_, arr_,
length1_);
}
length1_ = 0;
}
};
#endif
/*---------------------------------------------------------
The main file test.cpp
-----------------------------------------------------------*/
#include <iostream>
#include "array_1d.h"
int main ()
{
Array1D<int> testArr1(10ul, 1);
std::cout << "testArr1(0) = " << testArr1(0) << std::endl;
// copy construct testArr2 from testArr1
Array1D<int> testArr2(testArr1);
// nullptr dereference reported here, although the copy succeeded
std::cout << "testArr2(0) = " << testArr2(0) << std::endl;
return 0;
}
--
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/20180920/c03c4b95/attachment.html>
More information about the llvm-bugs
mailing list