Почему VS выдаёт предупреждение C6386 (переполнение буфера)?

#include <iostream>

struct String
{
public:
  String();
  String(const char *str);
  String(const String& str);
  void print();
  ~String();
  String& operator=(const String& other);
  String operator+(const String& other);

private:
  char *str;
  int lenght;
};

String::String()
{
  this->str = nullptr;
  lenght = 0;
}

String::String(const char *str)
{
  lenght = strlen(str);
  this->str = new char[lenght + 1];

  for(int i = 0; i < lenght; i++)
  {
    this->str[i] = str[i];
  }
  this->str[lenght] = '\0';
}

String::String(const String& other)
{
  
  lenght = other.lenght;
  this->str = new char[lenght + 1];
  for (int i = 0; i < lenght; i++)
  {
    this->str[i] = other.str[i];
  }
  this->str[other.lenght] = '\0';
}

void String::print()
{
  std::cout << str;
}



String::~String()
{
  delete[] this->str;
  this->str = nullptr;
}

String& String::operator=(const String& other)
{
  if (this->str != nullptr)
  {
    delete[] str;
    str = nullptr;
  }

  lenght = other.lenght;
  this->str = new char[lenght + 1];
  for (int i = 0; i < lenght; i++)
  {
    this->str[i] = other.str[i];
  }
  this->str[other.lenght] = '\0';

  return *this;
}

String String::operator+(const String& other)
{

  String NewStr;
  NewStr.lenght = this->lenght + other.lenght;
  NewStr.str  = new char[NewStr.lenght + 1];
  
  int i = 0;
  for (;i < this->lenght; i++)
  {
    NewStr.str[i] = this->str[i];
  }
  for (int j = 0; j < other.lenght; j++, i++)
  {
    NewStr.str[i] = other.str[j];//предупреждение в этой строке
  }
  NewStr.str[NewStr.lenght] = '\0';
  

  return NewStr;
}

int main()
{
  String a("Hello");
  String b("lello");
  String c;
  c = a + b;


  c.print();
}

При замене

NewStr.lenght = this->lenght + other.lenght;
      NewStr.str  = new char[NewStr.lenght + 1];

На

NewStr.lenght = this->lenght + other.lenght;
      NewStr.str  = new char[this->lenght + other.lenght + 1];

Предупреждение пропадает


Ответы (1 шт):

Автор решения: sibedir

Анализ кода человеком весьма "творческий" процесс. Человек может увидеть, как именно NewStr.lenght связан с this->lenght и other.lenght. Но заложить все возможные паттерны анализа в алгоритм не реально. Конкретно здесь анализатор кода не увидел/не просчитал эту зависимость. Но его предположение хоть и ошибочное, но хорошее с точки зрения последовательности изложения мысли программиста в коде. Посмотрите на свой код, можно сказать, что второй цикл - это продолжение первого, но с несколько изменившимся телом. Но алгоритм это не прочитал. Изменения затронули не только тело, но и счётчик. Итерируемся мы в обоих циклах по NewStr.str, а счетчиком для него служит i. Сейчас же для анализатора это два несвязанных цикла: первый по NewStr и this со счётчиком i, второй по NewStr и other со счётчиками i и j. Замените

for (int j = 0; j < other.lenght; j++, i++)

на

for (int j = 0; i < NewStr.lenght; j++, i++)

Теперь оба цикла связаны условием по i, инкрементом i, и итерированием через i по NewStr.str. Так более логично.
И самое интересное - предупреждение пропадает.

→ Ссылка