<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 - Scan-build reports a false positive nullptr dereference because it misses calls to template member functions within a copy constructor of a class template"
   href="https://bugs.llvm.org/show_bug.cgi?id=39028">39028</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Scan-build reports a false positive nullptr dereference because it  misses calls to template member functions within a copy constructor of a class template
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>clang
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>7.0
          </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>thomas.ullmann@mpibpc.mpg.de
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Created <span class=""><a href="attachment.cgi?id=20901" name="attach_20901" title="The full sources and output of scan-build including the html-output">attachment 20901</a> <a href="attachment.cgi?id=20901&action=edit" title="The full sources and output of scan-build including the html-output">[details]</a></span>
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;
}</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>