Жалко, что вы переработали свой вопрос из первой версии, которая касалась setenv()
, потому чтоsetenv()
имеет утечку памяти, по крайней мере, в реализации glibc.
Возьмите этот пример программы; он будет расти и расти, пока не съест всю память, которую сможет:
#include <stdlib.h>
#include <stdio.h>
int main(void){
char buf[24];
for(;;){
snprintf(buf, sizeof buf, "%d", rand());
setenv("foo", buf, 1);
}
}
В реализации glibc setenv()
никогда не будет освобождаться память, уже выделенная предыдущим setenv()
; однако он будет избегать дублирования, отслеживая строки среды, выделенные им в двоичном дереве (с использованием tfind(3)
, отдельно от списка char **environ
). Это также дает хороший эффект сокрытия утечки от таких инструментов, как valgrind
;-)
Что касается putenv()
, он полагается на то, что вызывающий объект управляет строкой, переданной ему в качестве аргумента. Таким образом, задача вызывающей стороны состоит в том, чтобы убедиться, что она не пропустит его при повторном вызове putenv()
, что он не освободит его, пока он все еще является частью среды, и что он не использует для этого автоматическую/стековую переменную.
Кроме того, изменение строки после вызова putenv()
может привести к удалению переменной среды или добавлению другой. Пример:
#define _XOPEN_SOURCE 500
#include <stdlib.h>
#include <stdio.h>
#include <err.h>
#include <unistd.h>
int main(void){
extern char **environ;
static char *my_environ[] = { "YUCK=yumm", 0 };
static char str[256] = "FOO=bar";
environ = my_environ;
putenv(str);
snprintf(str, sizeof str, "BAZ=quux");
execl("/usr/bin/printenv", "printenv", (void*)0);
err(1, "execlp");
}
Это требуется по стандарту, но не работало в старых версиях glibc, где putenv()
делал копию своего аргумента.
Наконец, и setenv()
, и putenv()
будут перемещать массив char **environ
при добавлении новой переменной в среду.Реализация сохранит свою собственную копию указателя и увеличит ее с помощью realloc()
, но не будет возиться со своим исходным (, который указывает на статическую память ), или с памятью, выделенной вручную, например. environ = calloc(sizeof *environ, envlen)
.
@steeldriver был прав. Я использовал неправильный формат, так как /etc/crontab отличается от crontab пользователя root (, который не содержит поля who ).