полагаться на PATH_MAX может вызвать переполнение - PullRequest
2 голосов
/ 07 июля 2019

как вы знаете * PATH_MAX - это значение, используемое для указания максимального размера переменной среды (в данном случае PATH переменная), но это не тематически, в большинстве случаев взгляните на этот код, который используется для скопировать переменную среды в массив размером PATH_MAX

  char env[PATH_MAX]; 
  strcpy(path, getenv("PATH"));

если вы видите, что он может так легко переполняться, можно сказать, используйте strncpy, чтобы вы могли избежать переполнения, но если вы используете его и значение PATH велико, то MAX_PATH мы не сможем получить PATH Переменная env завершена, и это заставляет меня задуматься, как мне получить переменную PATH env с предположением, что не должно быть переполнения или потери данных

Ответы [ 2 ]

5 голосов
/ 07 июля 2019

В общем случае , если вам вообще нужно скопировать строку неизвестной длины, используйте strncpy для копирования в буфер фиксированного размера с ограничением размера (но остерегайтесь неудобного не завершать строку, если она слишком длинная).

Или используйте strdup для выделения копии.


как вы знаете PATH_MAX - это значение, используемое для указания максимального размера переменной среды (в данном случае PATH переменная)

Нет, это не так; это не имеет ничего общего с $PATH или окружающей средой !!

Максимальная длина пути к одной файловой системе . например /foo/bar/verylongdirectoryname/x/y.txt гарантированно будет иметь длину PATH_MAX. В противном случае вы не сможете прочитать его с абсолютным путем, и вместо этого вам придется chdir в это дерево и использовать относительный путь.

Среда PATH - это просто плоская строка, как и любой другой env var; ядро не обрезает их до фиксированной длины. Или, конечно, не ограничен PATH_MAX.

как я могу получить переменную PATH env с предположением, что не должно быть ни переполнения, ни потери данных

Э-э, у вас уже есть getenv("PATH"). Это возвращает указатель на существующую строку в области памяти вашего процесса. Это эффективно в статическом хранилище; вам не нужно копировать его, и будущие вызовы на getenv не сломают указатель. (В Linux env vars находятся в стеке выше argv при запуске процесса. Код запуска CRT, который запускается до того, как что-либо перемещается, указатель стека сохраняет указатель на них в глобальном envp, где getenv может найти его позже.)

Если вы хотите скопировать буфер для env var, чтобы вы могли удлинить его или изменить без изменения оригинала, самый простой вариант - strdup(3) из <string.h> для размещения копии. (POSIX 2008, а до этого BSD, GNU C и другие системы до этого). Или strndup, чтобы установить ограничение на количество копируемых байтов.

GNU C даже имеет версию, основанную на alloca, а не malloc, на случай, если вам понадобится более дешевое временное хранилище для автоматического хранения.


PATH_MAX

PATH_MAX относится, например, к функциям POSIX, таким как getwd(3), где вы предоставляете буфер, но без ограничения длины. (Но на самом деле вы должны использовать char *getcwd(char *buf, size_t size) вместо этого; смотрите ту же ссылку, что и getwd. На странице руководства также написано:

Обратите внимание, что в некоторых системах PATH_MAX не может быть константой времени компиляции; кроме того, его стоимость может зависеть в файловой системе см. pathconf (3).


Справочная страница Linux readdir(3) не говорит об этом, но размер struct dirent члена char d_name[256]; /* Null-terminated filename */ определен именно таким образом, потому что PATH_MAX = 255. (Точнее, PATH_MAX равен 255 из-за размера readdir ограничение.)


Кроме того, системные вызовы, такие как chdir(2) или open(2), допускаются сбои на путях длиннее PATH_MAX (ENAMETOOLONG):

ENAMETOOLONG
Имя пути или компонент имени пути был слишком длинным.

readlink(2) принимает размер буфера, поэтому ему не нужно ограничивать длину целевой ссылки; ENAMETOOLONG упоминается только как возможная ошибка в указанном вами пути, а не в имени ссылки.


Даже в современном Linux 255 байт для одного имени файла является жестким ограничением. Но IIRC разрешает использовать более длинные пути (с несколькими компонентами каталогов). Спецификация POSIX не требует ошибок для open() на длинном пути, поэтому ОС может выдавать достаточно малый PATH_MAX, но при этом по-прежнему работать с более длинными путями, когда это возможно.

3 голосов
/ 07 июля 2019

Избегайте предположения, что $ PATH определен или имеет ограниченную длину - это решение вашего вопроса, и используйте общий код, подобный приведенному ниже.

char *path = NULL; 
  const char *temp = getenv("PATH");
  if (temp != NULL) {
    path = (char*) malloc(strlen(temp) + 1);
    if (path == NULL) {
      /* Handle error condition */
    } else {
      strcpy(path, temp);
    }
    /* Use path */
  }
...