Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[clang: static analyzer] False positive of clang-analyzer-core.uninitialized.Assign with std::stable_sort (Regression: 14 -> 15) #61687

Open
cmorty opened this issue Mar 24, 2023 · 1 comment
Labels
clang:static analyzer false-positive Warning fires when it should not

Comments

@cmorty
Copy link

cmorty commented Mar 24, 2023

When running std::stable_sort on a container of a class with default ctor and default member initialization, clang-analyzer-core.uninitialized.Assign will show that a "value assigned to a field in implicit constructor is garbage or undefined".

Versions

Tested with Clang

  • 13.0.1 -> No warning
  • 14.0.0 -> No warning
  • 15.0.7
  • 16.0.0
  • 17.0.0

Example

Godbolt

Running

/usr/lib/llvm-17/bin/clang --analyze -Qunused-arguments -Xclang -analyzer-opt-analyze-headers -Xclang -analyzer-checker=core.uninitialized.Assign /work/test.cpp

on

#include <algorithm>
#include <string>
#include <vector>

class SimpleClass
{
 public:
   int v {};
   std::string s;

   static std::vector<SimpleClass> sortMe(std::vector<SimpleClass> v);
};

std::vector<SimpleClass> SimpleClass::sortMe(std::vector<SimpleClass> v)
{
   std::stable_sort(v.begin(), v.end(), [](const SimpleClass &lhs, const SimpleClass &rhs) {
      return lhs.v < rhs.v || lhs.s < rhs.s;
   });
   return v;
}

will produce:

/work/test.cpp:5:7: warning: Assigned value is garbage or undefined [core.uninitialized.Assign]
class SimpleClass
      ^~~~~~~~~~~
/work/test.cpp:5:7: warning: Value assigned to field 'v' in implicit constructor is garbage or undefined [core.uninitialized.Assign]
class SimpleClass
      ^~~~~~~~~~~

See Details for the whole trace back.

/work/test.cpp:5:7: warning: Assigned value is garbage or undefined [core.uninitialized.Assign]
class SimpleClass
      ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:262:3: note: Calling 'get_temporary_buffer<SimpleClass>'
                std::get_temporary_buffer<value_type>(_M_original_len));
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:104:11: note: Assuming '__len' is <= '__max'
      if (__len > __max)
          ^~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:104:7: note: Taking false branch
      if (__len > __max)
      ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:107:14: note: Assuming '__len' is > 0
      while (__len > 0)
             ^~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:107:7: note: Loop condition is true.  Entering loop body
      while (__len > 0)
      ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:109:35: note: Uninitialized value stored to field 'v'
          _Tp* __tmp = static_cast<_Tp*>(::operator new(__len * sizeof(_Tp),
                                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:111:8: note: Assuming '__tmp' is not equal to null
          if (__tmp != 0)
              ^~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:111:4: note: Taking true branch
          if (__tmp != 0)
          ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:262:3: note: Returning from 'get_temporary_buffer<SimpleClass>'
                std::get_temporary_buffer<value_type>(_M_original_len));
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:264:15: note: Field 'first' is non-null
      if (__p.first)
              ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:264:7: note: Taking true branch
      if (__p.first)
      ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:268:8: note: Calling '__uninitialized_construct_buf<SimpleClass *, __gnu_cxx::__normal_iterator<SimpleClass *, std::vector<SimpleClass>>>'
              std::__uninitialized_construct_buf(__p.first, __p.first + __p.second,
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:251:7: note: Calling '__uninitialized_construct_buf_dispatch::__ucr'
      std::__uninitialized_construct_buf_dispatch<
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:202:8: note: '__first' is not equal to '__last'
          if (__first == __last)
              ^~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:202:4: note: Taking false branch
          if (__first == __last)
          ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:212:14: note: Assuming '__cur' is equal to '__last'
              for(; __cur != __last; ++__cur, ++__prev)
                    ^~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:212:8: note: Loop condition is false. Execution continues on line 215
              for(; __cur != __last; ++__cur, ++__prev)
              ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:215:18: note: Calling 'move<SimpleClass &>'
              *__seed = _GLIBCXX_MOVE(*__prev);
                        ^~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/move.h:167:30: note: expanded from macro '_GLIBCXX_MOVE'
#define _GLIBCXX_MOVE(__val) std::move(__val)
                             ^~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:215:18: note: Returning from 'move<SimpleClass &>'
              *__seed = _GLIBCXX_MOVE(*__prev);
                        ^~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/move.h:167:30: note: expanded from macro '_GLIBCXX_MOVE'
#define _GLIBCXX_MOVE(__val) std::move(__val)
                             ^~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:215:8: note: Calling implicit move assignment operator for 'SimpleClass'
              *__seed = _GLIBCXX_MOVE(*__prev);
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/work/test.cpp:5:7: note: Assigned value is garbage or undefined
class SimpleClass
      ^~~~~~~~~~~
/work/test.cpp:5:7: warning: Value assigned to field 'v' in implicit constructor is garbage or undefined [core.uninitialized.Assign]
class SimpleClass
      ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:264:15: note: Field 'first' is non-null
      if (__p.first)
              ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:264:7: note: Taking true branch
      if (__p.first)
      ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:268:8: note: Calling '__uninitialized_construct_buf<SimpleClass *, __gnu_cxx::__normal_iterator<SimpleClass *, std::vector<SimpleClass>>>'
              std::__uninitialized_construct_buf(__p.first, __p.first + __p.second,
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:251:7: note: Calling '__uninitialized_construct_buf_dispatch::__ucr'
      std::__uninitialized_construct_buf_dispatch<
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:202:8: note: '__first' is not equal to '__last'
          if (__first == __last)
              ^~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:202:4: note: Taking false branch
          if (__first == __last)
          ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:212:14: note: Assuming '__cur' is not equal to '__last'
              for(; __cur != __last; ++__cur, ++__prev)
                    ^~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:212:8: note: Loop condition is true.  Entering loop body
              for(; __cur != __last; ++__cur, ++__prev)
              ^
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_tempbuf.h:213:3: note: Calling '_Construct<SimpleClass, SimpleClass>'
                std::_Construct(std::__addressof(*__cur),
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_construct.h:119:38: note: Calling implicit move constructor for 'SimpleClass'
      ::new(static_cast<void*>(__p)) _Tp(std::forward<_Args>(__args)...);
                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/work/test.cpp:5:7: note: Value assigned to field 'v' in implicit constructor is garbage or undefined
class SimpleClass
      ^~~~~~~~~~~

If you switch v and s, this error will not be shown.

How to Reproduce

docker run --rm -it -v `pwd`:/work ubuntu

apt update
apt install -y wget lsb-release software-properties-common gnupg

wget https://apt.llvm.org/llvm.sh
chmod u+x llvm.sh

./llvm.sh 17

clang-17 --analyze -Qunused-arguments -Xclang -analyzer-opt-analyze-headers -Xclang -analyzer-checker=core.uninitialized.Assign /work/test.cpp
@EugeneZelenko EugeneZelenko added clang:static analyzer false-positive Warning fires when it should not and removed new issue labels Mar 24, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Mar 24, 2023

@llvm/issue-subscribers-clang-static-analyzer

@cmorty cmorty changed the title [clang: static analyzer] False positive of clang-analyzer-core.uninitialized.Assign with std::stable_sort [clang: static analyzer] False positive of clang-analyzer-core.uninitialized.Assign with std::stable_sort (Regression: 14 -> 15) Mar 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:static analyzer false-positive Warning fires when it should not
Projects
None yet
Development

No branches or pull requests

3 participants