VS 22缓冲区溢出中的C6386警告

xdnvmnnf  于 2023-05-28  发布在  其他
关注(0)|答案(1)|浏览(346)

我试图使一个函数,得到一个矩阵,并将其列向右或向左移动,这取决于用户的重复输入。在这样做的时候,我注意到编译器警告(C6386,C6001,C6385),都在同一个代码区,我找不到问题。
警告C6386写入“temp_row”时缓冲区溢出。警告C6001使用未初始化的内存“*temp_row”。警告C6385从“temp_row”阅读无效数据。
这就是代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_MATRIX_ALLOWED 2
#define MAX_COMMEND_LINE 81
#define MAX_MATRIX_NAME_LEN 13

int matrix_count = 0;
char variebels_names[MAX_MATRIX_ALLOWED][MAX_MATRIX_NAME_LEN];
int* matrix_data[MAX_MATRIX_ALLOWED];
int matrix_rows[MAX_MATRIX_ALLOWED];
int matrix_cols[MAX_MATRIX_ALLOWED];

float StringToFloat(const char* str) {
    float result = 0.0;
    sscanf_s(str, "%f", &result);
    return result;
}

void createMatrix(const char* name, float rows, float cols) {
    // check name length and letters
    if (strlen(name) > MAX_MATRIX_NAME_LEN) {
        printf_s("Error: '%s' - invalid variable name!\n", name);
        return;
    }
    // check if name is already in use
    for (int i = 0; i < matrix_count; i++) {
        if (strcmp(name, variebels_names[i]) == 0) {
            printf_s("Error: variable name '%s' is already in use!\n", name);
            return;
        }
    }
    // check if the rows and cols are int
    if (rows - (int)rows != 0 || cols - (int)cols != 0 || cols <= 0 || rows <= 0) {
        printf_s("Error: invalid dimension!\n");
        return;
    }
    int cols_int = (int)cols;
    int rows_int = (int)rows;
    // check if there is the same variable name
    if (matrix_count >= MAX_MATRIX_ALLOWED) {
        printf_s("Error: zeros cannot save more than 2 variables!\n");
        return;
    }

    /*save memory for the matrix data*/

    int** matrix = (int**)malloc (rows_int *sizeof(int*));
    if (!matrix) exit(1);
    for (int i = 0; i < rows_int; i++)
    {
       matrix[i] = (int*)malloc(cols_int * sizeof(int));
       if (!matrix[i]) exit(1);
    }

    for (int i = 0; i < rows_int; i++)
    {
        for (int j = 0; j < cols_int; j++)
        {
            matrix[i][j] = 0;
        }
    }
    matrix_data[matrix_count] = matrix;
    matrix_rows[matrix_count] = rows_int;
    matrix_cols[matrix_count] = cols_int;
    strncpy_s(variebels_names[matrix_count], MAX_MATRIX_NAME_LEN, name, MAX_MATRIX_NAME_LEN - 1);
    variebels_names[matrix_count][MAX_MATRIX_NAME_LEN - 1] = '\0';

    matrix_count++;
    fflush(stdout);
}

void matrixShift(const char* name, int repeat) {
    //check if name is defined
    int matrix_index = -1;
    for (int i = 0; i < matrix_count; i++)
    {
        if (strcmp(name, variebels_names[i]) == 0)
        {
            matrix_index = i;
            break;
        }
    }
    if (matrix_index == -1)
    {
        printf_s("Error: '%s' - unknown variable!\n", name);
        return;
    }
    int rows = matrix_rows[matrix_index];
    int cols = matrix_cols[matrix_index];
    int** matrix = matrix_data[matrix_index];
    int shift = repeat % cols;
    if (shift >= 0) {
        shift = (cols - (repeat % cols)) % cols;
    }
    else
    {
        shift = (-repeat) % cols;
    }

    for (int i = 0; i < rows; i++) {
        // Create a temporary row
        int* temp_row = (int*)malloc(cols * sizeof(int));
        if (!temp_row) exit(1);
        int temp_index = 0;

        // Copy elements from the original row to the temporary row
        for (int j = shift; j < cols; j++) {
            temp_row[temp_index] = matrix[i][j];
            temp_index++;
        }
        for (int j = 0; j < shift; j++) {
            temp_row[temp_index] = matrix[i][j];
            temp_index++;
        }

        // Copy elements back to the original row
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = temp_row[j];
        }

        // Free the temporary row
        free(temp_row);
    }
}

int main() {
    char command[MAX_COMMEND_LINE];
    printf_s("$ ");
    fflush(stdout);
    while (fgets(command, sizeof(command), stdin) != NULL)
    {
        char* token;
        char* context = NULL;
        // split the command string
        token = strtok_s(command, " \n", &context);
        // check if the user didn't put input well
        if (token == NULL) {
            printf_s("$ ");
            fflush(stdout);
            continue;
        }
        // compare the tokens to the commands
        if (strcmp(token, "exit") == 0) {
            break;
        }
        else if (strcmp(token, "zeros") == 0) {
            token = strtok_s(NULL, " \n", &context);
            if (token == NULL) {
                printf_s("Error: illegal command!\n");
                printf_s("$ ");
                fflush(stdout);
                continue;
            }
            char variable_name[MAX_MATRIX_NAME_LEN];
            strncpy_s(variable_name, MAX_MATRIX_NAME_LEN, token, MAX_MATRIX_NAME_LEN - 1);
            variable_name[MAX_MATRIX_NAME_LEN - 1] = '\0';
            // checking the length of the variable name
            if (strlen(variable_name) > MAX_MATRIX_NAME_LEN) {
                printf_s("Error: '%s' - invalid variable name!\n", variable_name);
                printf_s("$ ");
                fflush(stdout);
                continue;
            }

            token = strtok_s(NULL, " \n", &context);
            if (token == NULL) {
                printf_s("Error: illegal command!\n");
                printf_s("$ ");
                fflush(stdout);
                continue;
            }
            float rows = StringToFloat(token);

            token = strtok_s(NULL, " \n", &context);
            if (token == NULL) {
                printf_s("Error: illegal command!\n");
                printf_s("$ ");
                fflush(stdout);
                continue;
            }
            float cols = StringToFloat(token);

            createMatrix(variable_name, rows, cols);
        }
        else if (strcmp(token, "shift") == 0) {
            token = strtok_s(NULL, " \n", &context);
            if (token == NULL) {
                printf_s("Error: illegal command!\n");
                printf_s("$ ");
                fflush(stdout);
                continue;
            }
            char variable_name[MAX_MATRIX_NAME_LEN];
            strncpy_s(variable_name, MAX_MATRIX_NAME_LEN, token, MAX_MATRIX_NAME_LEN - 1);
            variable_name[MAX_MATRIX_NAME_LEN - 1] = '\0';

            token = strtok_s(NULL, " \n", &context);
            if (token == NULL) {
                printf_s("Error: illegal command!\n");
                printf_s("$ ");
                fflush(stdout);
                continue;
            }
            int repeat = StringToFloat(token);
            matrixShift(variable_name, repeat);
        }
        else {
            printf_s("Error: unknown command!\n");
        }
        printf_s("$ ");
        fflush(stdout);
    }

    // free allocated memory for matrices
    for (int i = 0; i < matrix_count; i++) {
        free(matrix_data[i]);
    }
    return 0;
}

我尝试使用-1temp_row大小解决它,但它没有工作。

wpx232ag

wpx232ag1#

Stack Overflow上有许多关于Visual Studio(MSVC)编译器的“误报”C6386警告的帖子。这是静态分析器的一个“弱点”(我不喜欢使用“bug”这个术语,因为静态分析是一个非常复杂的过程,编译器并不总是能看到代码执行的所有可能结果,即使你--作为作者--可能知道某些条件不能发生)。
然而,尽管有许多 * 密切相关 * 的帖子,我找不到一个为您的特定问题提出解决方案的帖子,所以我将提供一种可能性。
但首先,我想解释一下这些警告:
1.警告C6001:使用未初始化的内存“*temp_row”
警告C6385:从“temp_row”阅读无效数据。
当分析器看到三个嵌套的for (int j = 0 ...)循环中的最后一个时,它不能100%确定前两个循环实际上已经写入了temp_row数组的所有元素(即使您知道它们已经写入了)。您可以使用calloc而不是malloc来静默这些元素,这将初始化所有元素为零。
1.警告C6386:写入“temp_row”时缓冲区溢出。
在这种情况下,分析器并不知道temp_index的值 * 保证 * 在[0..cols)范围内(同样,即使您知道它会在此范围内)。您可以通过在第二个内部for (int j = 0 ...)循环中添加额外的检查(即temp_index < cols)来消除此警告。
下面是你的代码中与这些修改相关的部分(我保留了你的原始代码行,但将它们注解掉了):

for (int i = 0; i < rows; i++) {
        // Create a temporary row
        int* temp_row = calloc(cols, sizeof(int)); 
    //  int* temp_row = (int*)malloc(cols * sizeof(int));
        if (!temp_row) exit(1);
        int temp_index = 0;

        // Copy elements from the original row to the temporary row
        for (int j = shift; j < cols; j++) {
            temp_row[temp_index] = matrix[i][j];
            temp_index++;
        }
    //  for (int j = 0; j < shift; j++) {
        for (int j = 0; j < shift && temp_index < cols; j++) {
            temp_row[temp_index] = matrix[i][j];
            temp_index++;
        }

        // Copy elements back to the original row
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = temp_row[j];
        }

        // Free the temporary row
        free(temp_row);
    }

进行这些更改会使我的MSVC版本(Visual Studio 2022)上的所有三个警告静音。然而,它们也给我带来了一些困惑,因为只保留了 * 第一个 * 更改(即使用calloc)去除C6383和C6385,但留下C6001;此外,仅保留 * 第二个 * 更改将删除C6001。这是我所期待的完全相反!

相关问题