C6386 c как исправить

Функция считывает матрицу из файла в динамический массив, сразу же выводит её и отправляет в main, предварительно узнав размеры этой матрицы из другой функции (плюс разные проверки существования файла и прочее, но не суть). Сама программа и данная функция работают безупречно, но анализ кода в Visual Studio выдаёт вот такое вот предупреждение:

Предупреждение C6386. Переполнение буфера при записи в “matrix”:
доступный для записи объем равен “strings*sizeof(int *)” байт,
однако записать можно только “16” байт.

Так вот, мне интересно почему он на это ругается и стоит ли обращать внимание?

P.S. Анализом кода занялся совсем недавно, к примеру узнал про нулевой указатель и в функции уже это дело подправил.

Сам код:

int **GetMatrixFile(const char filename[], const int strings, const int columns)
{
    FILE *file;
    int **matrix;

    fopen_s(&file, filename, "r");

    if (file != NULL)
    {
        printf("Матрица %c(%d x %d):n",
            filename[0], strings, columns);

        matrix = (int**)malloc(strings * sizeof(int*));
        if (matrix != NULL)
        {
            for (int i = 0; i < strings; ++i)
            {
                printf("|");

                matrix[i] = (int*)malloc(columns * sizeof(int));
                if (matrix[i] != NULL)
                {
                    for (int j = 0; j < columns; ++j)
                    {
                        fscanf_s(file, "%d", &matrix[i][j]);
                        printf("%3d ", matrix[i][j]);
                    }
                }
                else exit(EXIT_FAILURE);

                printf("|n");
            }
        }
        else exit(EXIT_FAILURE);
        fclose(file);
    }
    else exit(EXIT_FAILURE);

    return matrix;
}

savvakhrenkov

0 / 0 / 0

Регистрация: 19.02.2022

Сообщений: 2

1

19.02.2022, 21:30. Показов 1518. Ответов 5

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Необходимо задать динамический массив структур из номера строки и указателя на строку и по запросу пользователя инвертировать одну из строк. При компиляции на моменте с инвертированием строки номер “a” компилятор VS Studio 2019 выдает предупреждения C6385 и C6386 (строки 51 и 52 соответственно). Никак не могу понять, отчего так. Код прилагаю.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <iostream>
#include <string>
 
struct recs {
    int k;
    char* str;
};
 
int main()
{
    int num;
    std::cout << "Enter num" << std::endl;
    std::cin >> num;
    std::cin.get();
    
    recs *Array = new recs[num]; //массив структур
    int *stringlength = new int[num]; //массив длин строк соответвующих элементов структур (для удобства)
    
    for (int i = 0; i < num; i++)
    {
        Array[i].k = i;
        std::string string;
        std::cout << "Enter string " << i+1 << std::endl;
        std::getline(std::cin, string);
        int size = string.length() + 1;
        stringlength[i] = size-1;
        
        Array[i].str = new char[size]; //динамический массив для хранения i-й строки
        for (int j = 0; j < size; j++)
        {
            Array[i].str[j] = string[j];
        }
    }
 
    try
    {
        int a;
        std::cout << "Enter the number of string to invert" << std::endl;
        std::cin >> a;
        int invert = a - 1;
        if (a > num)
            throw "There is no such string";
        if (a < 1)
            throw "There is no such string";
        
        int len = strlen(Array[invert].str);
        int k = len - 1;
        for (int i = 0; i < (int)((len-1) / 2); i++)
        {
            char t;
            t = Array[invert].str[i];
            Array[invert].str[i] = Array[invert].str[k];
            Array[invert].str[k] = t;
            k = k - 1;
        }
    }
    catch(const char*)
    {
        std::cout << "Error: there is no such string";
        delete[] Array;
        delete[] stringlength;
        Array = 0;
        stringlength = 0;
        exit(0);
    }
    std::cout << "" << std::endl;
 
    for (int z = 0; z < num; z++)
    {
        std::cout << Array[z].k+1 << " || " << Array[z].str << std::endl; 
        delete[] Array[z].str; //возвращение памяти системе
    }
    delete[] Array; 
    delete[] stringlength;
    Array = 0;
    stringlength = 0;
    return 0;
}



0



685 / 392 / 200

Регистрация: 19.12.2016

Сообщений: 1,586

19.02.2022, 21:48

2

А у вас #include <cstring> подключен?



0



фрилансер

4759 / 4361 / 924

Регистрация: 11.10.2019

Сообщений: 11,451

19.02.2022, 21:56

3

Цитата
Сообщение от savvakhrenkov
Посмотреть сообщение

выдает предупреждения

текст предупреждений то какой ?

Добавлено через 2 минуты
savvakhrenkov, кстати, это учебное задание на динамические массивы или боевой код? В последнем случае можно всё упростить



0



0 / 0 / 0

Регистрация: 19.02.2022

Сообщений: 2

19.02.2022, 22:06

 [ТС]

4

C6385 Чтение недопустимых данных из “Array[invert].str”: доступный для чтения объем равен “size*1” байт, однако считать можно только “2” байт.
C6386 Переполнение буфера при записи в “Array[invert].str”: доступный для записи объем равен “size*1” байт, однако записать можно только “2” байт.

Добавлено через 4 минуты

Цитата
Сообщение от Алексей1153
Посмотреть сообщение

это учебное задание на динамические массивы или боевой код

Учебное задание
Надеюсь, вопросы по таким темам не запрещены правилами? Не нашел такого пункта, если что, поправьте меня.

Добавлено через 2 минуты

Цитата
Сообщение от ram876
Посмотреть сообщение

А у вас #include <cstring> подключен?

Подключена библиотека

. На

мой VS плюется и не находит.



0



685 / 392 / 200

Регистрация: 19.12.2016

Сообщений: 1,586

19.02.2022, 22:10

5

Цитата
Сообщение от savvakhrenkov
Посмотреть сообщение

не находит.

Как тогда strlen может работать?



0



24 / 57 / 31

Регистрация: 06.08.2020

Сообщений: 209

19.02.2022, 22:21

6

В VS нормально работает с #include<string> хотя да, по идее strlen это сишный прикол.

А предупреждения мне думается это студию смущает некоторая непонятность переменной invert. Но на работу это не влияет.



0



Я пытаюсь реализовать сортировку слиянием в C, когда натолкнулся на что-то интересное, поднятое [Analyze -> Run Code Analysis] в Visual Studio 2015.

Код выглядит следующим образом:

void MergeSort_r(int A[], int n)
{
// A = {1, 3, 2}
// n = 3
int rightCount;
int* R;

if ( n < 2 ) return;

// version 1: rightCount = 2
rightCount = n - (n/2);

// version 2: rightCount = 2
rightCount = n - 1;

R = ( int* ) malloc( rightCount * sizeof( int ) );

if ( R ) {
for ( int i = 0; i < rightCount; i++ ) {
R[i] = A[i];
}

free( R );
}

}

Хотя обе версии rightCount по существу оцениваются как 2, в первой версии я получаю предупреждение:

«Переполнение буфера при записи в ‘R’: размер записи равен ‘(unsigned int) rightCount * sizeof (int)’ байтов, но может быть записано 8 байтов.»

Есть идеи, почему это так? Будем рады услышать ваши ответы.

2

Решение

Набор инструментов для анализа кода в Visual C ++ не всегда предлагает лучшие предупреждения. Он пытается дать вам лучший набор предупреждений, чтобы исправить некоторые потенциальные проблемы / ошибки, которые могут появиться во время выполнения. У вас есть несколько вариантов:

  • Отключите данное предупреждение вокруг кода, используя #pragma директивы.
  • Используйте конструкции C ++: new, make_unique и т.п.
  • (Не рекомендуется) это полностью игнорировать предупреждение и двигаться дальше.

В идеале вы всегда должны использовать новые примитивы smart pointers, такие как unique_ptr, shared_ptr и т.д. Они не только выделяют память для вас, но и освобождают от любого исключения, выброшенного в стек вызовов. Вам не нужно вводить * полностью!

auto buffer = make_unique<int[]>(10); // 10 integers

3

Другие решения

Ваш код в порядке, и инструменты (особенно анализаторы) имеют свои недостатки — иногда они генерируют ложные срабатывания. Это один из них. Кстати, я проверил ваш код на MSVS2015, и он не дает мне никаких предупреждений.

3

Visual Studio 2019 по умолчанию начала показывать предупреждения анализа кода в виде зеленых волнистых линий в редакторе. Это может быть чрезвычайно полезно для студентов, изучающих программирование на C, потому что они выявляют классические ошибки, такие как отключение доступа к одному массиву.

К сожалению, ложные срабатывания могут полностью испортить процесс обучения, и я боюсь, что мне придется попросить учеников отключить эту функцию, чтобы они не беспокоились о несуществующих проблемах.

Этот короткий фрагмент не вызывает никаких предупреждений:

#include <stdlib.h>

int main(void)
{
    size_t n = 6;
    int *v = malloc(n * sizeof(int));
    if (v == NULL) {
        return 1;
    }
    for (size_t i = 0; i < n; ++i) {
        v[i] = i;
    }
    free(v);
    return 0;
}

К сожалению, если вы переместите выделение в функции, например:

#include <stdlib.h>

int *test(size_t n)
{
    int *v = malloc(n * sizeof(int));
    if (v == NULL) { 
        return NULL;
    }
    for (size_t i = 0; i < n; ++i) {
        v[i] = i;
    }
    return v;
}

int main(void)
{
    size_t n = 6;
    int *v = test(n);   
    free(v);
    return 0;
}

Вы получите warning C6386: Buffer overrun while writing to 'v': the writable size is 'n*sizeof(int)' bytes, but '8' bytes might be written.

Даже читая Stack Overflow, я не понимаю, откуда взялся '8', но, что более важно, почему он не распознает, что i никогда не выйдет за пределы допустимого диапазона.

Возникает вопрос: есть ли способ написать этот тип кода таким образом, чтобы не было предупреждения?

Я знаю, что могу перейти к Tools > Options > Text Editor > C/C++ > Experimental > Code Analysis и установить Disable Code Analysis Squiggles на True или использовать #pragma warning(disable:6386), но я бы предпочел этого избежать и, конечно, не предлагаю своим ученикам последнее.

2 ответа

Лучший ответ

Я действительно хочу поблагодарить всех за их вклад и согласен с тем, что это ошибка анализатора кода (если посмотреть на веб-сайты Microsoft, два года назад он был” закрыт – более низкий приоритет “…).

Уловка Адриана Моула max(n, 0) указывает способ справиться с предупреждением в коде, то есть проверять, что n больше нуля. Забавно то, что вы все еще можете использовать этот ноль для того, что предполагалось использовать n. Хотя эту идею можно использовать для опытных программистов (что, вероятно, отключило бы предупреждение), как указывает Джон Боллинджер, она не для студентов.

Поэтому, сказав студентам, что это ошибка и как отключить волнистые линии анализа кода или отключить предупреждение, я бы пошел с

int *test(size_t n)
{
    if (n == 0) {
        return NULL;
    }
    int *v = malloc(n * sizeof(int));
    if (v == NULL) {
        return NULL;
    }
    for (size_t i = 0; i < n; ++i) {
        v[i] = i;
    }
    return v;
}

Это также можно интерпретировать как: не разрешать размещение 0 элементов.


0

Costantino Grana
7 Ноя 2020 в 04:38

Visual Studio 2019 started showing Code Analysis warnings as in-editor green squiggles by default. These may be extremely useful for students learning C programming, because they catch classical mistakes, such as off by one array accesses.

Unfortunately false positives may completely ruin the learning experience and I fear that I will have to ask the students to disable the feature in order to avoid having them worry on non existing problems.

This short snippet doesn’t cause any warning:

#include <stdlib.h>

int main(void)
{
    size_t n = 6;
    int *v = malloc(n * sizeof(int));
    if (v == NULL) {
        return 1;
    }
    for (size_t i = 0; i < n; ++i) {
        v[i] = i;
    }
    free(v);
    return 0;
}

Unfortunately, if you move the allocation in a function, like this:

#include <stdlib.h>

int *test(size_t n)
{
    int *v = malloc(n * sizeof(int));
    if (v == NULL) { 
        return NULL;
    }
    for (size_t i = 0; i < n; ++i) {
        v[i] = i;
    }
    return v;
}

int main(void)
{
    size_t n = 6;
    int *v = test(n);   
    free(v);
    return 0;
}

you get a warning C6386: Buffer overrun while writing to 'v': the writable size is 'n*sizeof(int)' bytes, but '8' bytes might be written.

Even reading on Stack Overflow, I don’t get where the '8' comes from, but, more importantly, why it fails to recognize that i will never be out of range.

So the question is: is there a way to write this type of code in a way that will not generate the warning?

I know that I can go to Tools > Options > Text Editor > C/C++ > Experimental > Code Analysis and set Disable Code Analysis Squiggles to True, or use a #pragma warning(disable:6386), but I’d rather avoid it, and certainly avoid suggesting my students the latter.

Добавить комментарий