Skip to content

[static-analyzer] false positive in unix.Errno #95658

Closed
@tearfur

Description

@tearfur

The static analyzer considers the case where getcwd() is sucessful but returns nullptr, which shouldn't be possible (if it is, how are we even supposed to check against that??).

Steps:

  1. Configure the CMake project.

    CC=clang CXX=clang++ cmake -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_CLANG_TIDY=clang-tidy
    
  2. Build the project.

    cd build && cmake --build .
    

Using clang and clang-tidy from the llvm repo.

$ clang --version
Ubuntu clang version 19.0.0 (++20240614073522+cc7a18c18011-1~exp1~20240614193539.212)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/lib/llvm-19/bin
$ clang-tidy --version
Ubuntu LLVM version 19.0.0
  Optimized build.
Code for reproducing
// main.cpp
#include <climits>
#include <iostream>
#include <vector>

#include <unistd.h>

int main()
{
    auto buf = std::vector<char>{};
    buf.resize(PATH_MAX);
    auto path = std::string_view{};
    for (;;)
    {
        if (char const* const ret = getcwd(std::data(buf), std::size(buf)))
        {
            path = ret;
            break;
        }

        if (errno == ERANGE)
        {
            buf.resize(std::size(buf) * 2U);
            continue;
        }
    }

    std::cout << path << '\n';
    return 0;
}
# CMakeLists.txt
cmake_minimum_required(VERSION 3.28)
project(test)

set(CMAKE_CXX_STANDARD 17)

add_executable(test main.cpp)

Output:

/root/main.cpp:20:13: warning: An undefined value may be read from 'errno' [clang-analyzer-unix.Errno]
   20 |         if (errno == ERANGE)
      |             ^
/usr/include/errno.h:38:16: note: expanded from macro 'errno'
   38 | # define errno (*__errno_location ())
      |                ^~~~~~~~~~~~~~~~~~~~~~
/root/main.cpp:12:5: note: Loop condition is true.  Entering loop body
   12 |     for (;;)
      |     ^
/root/main.cpp:14:37: note: Assuming that 'getcwd' is successful; 'errno' becomes undefined after the call
   14 |         if (char const* const ret = getcwd(std::data(buf), std::size(buf)))
      |                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/root/main.cpp:14:31: note: Assuming 'ret' is null
   14 |         if (char const* const ret = getcwd(std::data(buf), std::size(buf)))
      |                               ^~~
/root/main.cpp:14:9: note: Taking false branch
   14 |         if (char const* const ret = getcwd(std::data(buf), std::size(buf)))
      |         ^
/root/main.cpp:20:13: note: An undefined value may be read from 'errno'
   20 |         if (errno == ERANGE)
      |             ^
/usr/include/errno.h:38:16: note: expanded from macro 'errno'
   38 | # define errno (*__errno_location ())
      |                ^~~~~~~~~~~~~~~~~~~~~~

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions