Буст-вариант может вызвать деструктор для неактивного варианта?

Я использую код C через свою оболочку C++ для него, в частности, я обернуть union с boost::variantпроблема в том, что отчет статического анализатора clang "Назначенное значение является мусором или неопределенным" в очень конкретном случае - boost::variable был создан с типом int (Clang статический анализатор описан через "Take Branch True"), никогда не модифицируется, но затем с помощью Clang статического анализатора анализ boost::variant Деструктор может вызвать деструктор не int тип.

Вот мой код:

#include <boost/variant.hpp>
#include <cstdint>
#include <iostream>
#include <string>

extern "C" {

struct CFooString {
  const char *data;
  uintptr_t len;
  uintptr_t capacity;
};

void cfoo_string_free(struct CFooString str);

struct CResultObjectString {
  uint8_t is_ok;
  union {
    int ok;
    struct CFooString err;
  } data;
};

struct CResultObjectString c_func(int);
}

class MyString final : private CFooString {
public:
  explicit MyString(const CFooString &o) noexcept {
    data = o.data;
    len = o.len;
    capacity = o.capacity;
  }
  MyString() = delete;
  MyString(const MyString &) = delete;
  MyString &operator=(const MyString &) = delete;
  MyString(MyString &&o) noexcept {
    data = o.data;
    len = o.len;
    capacity = o.capacity;

    reset(o);
  }
  MyString &operator=(MyString &&o) noexcept {
    free_mem();
    data = o.data;
    len = o.len;
    capacity = o.capacity;

    reset(o);
    return *this;
  }
  ~MyString() noexcept { free_mem(); }
  std::string to_std_string() const { return std::string(data, len); }
  size_t size() const noexcept { return this->len; }
  bool empty() const noexcept { return this->len == 0; }

private:
  void free_mem() noexcept {
    if (data != nullptr) {
      cfoo_string_free(*this);
      reset(*this);
    }
  }
  static void reset(MyString &o) noexcept {
    o.data = nullptr;
    o.len = 0;
    o.capacity = 0;
  }
};

boost::variant<int, MyString> f1() {
  CResultObjectString ret = c_func(17);
  return ret.is_ok != 0 ? boost::variant<int, MyString>{ret.data.ok}
                        : boost::variant<int, MyString>{MyString{ret.data.err}};
}

int main() {
  auto ret = f1();
  if (boost::get<int>(&ret) != nullptr) {
    int p = boost::get<int>(std::move(ret));
    std::cout << "we get : " << p;
  } else {
    auto err = boost::get<MyString>(std::move(ret));
    std::cout << err.to_std_string();
  }
}

scan-build g ++ -std = C++11 -pedantic -Wall -Wextra -c test.cpp сообщает:

scan-build g++ -std=c++11 -pedantic -Wall -Wextra -c test.cpp
scan-build: Using '/usr/bin/clang-7' for static analysis
test.cpp:39:9: warning: Assigned value is garbage or undefined
    len = o.len;
        ^ ~~~~~
test.cpp:61:7: warning: Passed-by-value struct argument contains uninitialized data (e.g., field: 'len')
      cfoo_string_free(*this);
      ^~~~~~~~~~~~~~~~~~~~~~~

Если прочитать описание статического анализатора Clang, он думает, что после создания boost::variant<int, MyString>{ret.data.ok}Возможно, что MyString::~MyString будет называться.

Это что-то не так с моим кодом или boost::variant или же clang static analyzer?

0 ответов

Другие вопросы по тегам