Почему доступ к строке с нулевым символом в конце дает "мусор или неопределенный"?

У меня есть простой интерпретатор Brainfuck в C, который выдает следующее предупреждение в scan-build:

$ scan-build gcc -Wall -g -std=c99 main.c 
scan-build: Using '/usr/bin/clang' for static analysis
main.c:14:11: warning: Assigned value is garbage or undefined
        c = *(program + instruction_index);
          ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
scan-build: 1 bug found.

Вот самая маленькая версия моей программы, которая демонстрирует такое поведение:

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

void eval_program(char *program) {
    int program_len = strlen(program);
    int data_index = 0, instruction_index = 0;

    char c;
    while (instruction_index < program_len) {
        c = *(program + instruction_index);

        switch (c) {
        case '>':
            data_index++;
            instruction_index++;
            break;
        default:
            instruction_index++;
            break;
        }
    }
}

char *read_string(int file_descriptor) {
    char *s = NULL;
    int total_bytes_read = 0;

    int BUFFER_SIZE = sizeof(char) * 1024;
    char *temp_buffer = alloca(BUFFER_SIZE);

    int bytes_read;
    // Not bothering checking the return code from read or realloc for
    // errors, because it doesn't affect scan-build's output.
    while ((bytes_read = read(file_descriptor, temp_buffer, BUFFER_SIZE))) {
        s = realloc(s, total_bytes_read + bytes_read);
        memcpy(s + total_bytes_read, temp_buffer, bytes_read);
        total_bytes_read += bytes_read;
    }

    s = realloc(s, total_bytes_read + 1);
    s[total_bytes_read] = '\0';

    return s;
}

int main() {
    char *program = read_string(0); // read from stdin
    eval_program(program);
    free(program);

    return 0;
}

Эта программа не генерирует никаких предупреждений при компиляции с GCC и -Wall -Wextra, так почему доступ к строке мусора или неопределенный? Программа отлично работает в моем тестировании.

Это минимальный пример без проверки ошибок malloc или же read, но предупреждение все еще появляется, если я использую проверку ошибок. Предупреждение также появляется, если я заменяю realloc с malloc,

2 ответа

Решение

Вы можете уменьшить функцию read_string() до этого:

char *read_string(int file_descriptor) {
    char *s = NULL;

    s = malloc(1);
    //memset(s,0,1);
    s[0] = 0;

    return s;
}

Если вы прокомментируете вызов memset(), предупреждение исчезнет. Поэтому я прихожу к выводу, что в этом случае статический анализатор неверен.

Там нет ничего плохого с кодом.

Это ложноположительная ошибка в clang-анализаторе LLVM, см. Ошибку 22289.

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