openlang

getline выдаёт мусор, плюс утечка

Вот прям застрял на этом. Какой баг сначала?

while (getline(&line, &linecap, fp) != -1) {
	char *name, *role, *port;

	lineno++;
	line[strcspn(line, "\r\n")] = '\0';
	if (line[0] == '#' || line[0] == '\0')
		continue;
	name = strtok(line, " \t");
	role = strtok(NULL, " \t");
	port = strtok(NULL, " \t");
	if (!name || !role) {
		fprintf(stderr, "%s:%d: expected 'name role [port]'\n",
			path, lineno);
		fclose(fp);
		return -1;
	}
	if (inv->count == inv->cap && grow(inv) != 0) {
		fclose(fp);
		return -1;
	}
	inv->hosts[inv->count].name = name;
	inv->hosts[inv->count].role = role;
	inv->hosts[inv->count].port = port ? atoi(port) : 22;
	inv->count++;
}
free(line);
fclose(fp);
return 0;

hosts.txt:

# prod inventory
web-01 web 8080
web-02 web 8080
db-01 db 5432
cache-01 cache

hosts_bad.txt:

web-01 web 8080
db-01
cache-01 cache 6379
Переведено с английскогоПоказать оригинал

Разговор продолжается 6

Следуя доводам
  1. Ссылка на ответ

    Сначала мусор, утечка потом.

    name, role и port — это указатели внутрь line. strtok просто расставляет NUL в этом буфере и возвращает адреса внутри него. Потом getline переиспользует тот же буфер для следующей строки. В итоге все хосты указывают на одну и ту же память, и вы видите то, что туда записала последняя строка. Если line перевыделится через realloc, будет ещё хуже, потому что старые указатели повиснут.

    Каждой строке нужна своя копия:

    inv->hosts[inv->count].name = strdup(name);
    inv->hosts[inv->count].role = strdup(role);

    Проверяйте на NULL и освобождайте обе, когда освобождаете inventory. Это граница времени жизни: line живёт одну итерацию, строки хостов живут столько же, сколько inv.

    Утечка: ранние ветки return -1 (плохая строка, неудачный grow) пропускают free(line). Освобождается он только на «счастливом» пути. Либо освобождайте перед каждым return, либо делайте goto done на единую очистку.

    getline выделяет буфер, так что владелец — вызывающий. На странице POSIX это прямо написано: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getline.html

    Переведено с английскогоПоказать оригинал

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

  1. Предупреждение про висячий указатель пропало, а указатель остался

    Передаю имя в библиотеку на C++ через обёртку, и сначала написал всё в одну строку, CString::new(name).unwrap().as_ptr(), и r…

    Ответы 2Последняя активность rustcpp
  2. Один и тот же вызов с sink, сначала копия, потом перенос

    Nim 2 решает, копировать или переносить, в каждой точке вызова. Не на уровне proc. Тот же аргумент, та же proc. Первый вызов…

    Ответы 2Последняя активность nim
  3. Интерфейсные ссылки и объектные ссылки на один и тот же экземпляр

    Здравствуйте, у меня есть CSV-приёмник за интерфейсом, и создаю я его в переменной классового типа, потому что в конце мне ну…

    Ответы 1Последняя активность object-pascal