Должна ли свободная память передаваться в prctl ()? - PullRequest
1 голос
/ 01 июля 2019

Я использую prctl() для изменения имени потока pthreads в C:

  // Set our thread name to assist with debugging a running process
  char *threadName = calloc(16, sizeof(char));
  sprintf(threadName, "My Own Thread");
  prctl(PR_SET_NAME, threadName);

Мой вопрос заключается в том, должен ли я освобождать char *threadName сразу после вызова prctl()?

Принимает ли prcrl() безопасную копию строкового параметра, что позволяет мне в любое время освобождать предоставленную переменную?

Тестирование памяти с помощью valgrind не выявляет проблем при освобождении.Мое беспокойство вызывает сложные проблемы параллелизма и памяти.

РЕДАКТИРОВАТЬ: Я не верю предложенный вопрос Можно ли когда-либо безопасно использовать calloc без свободных? отвечает на конкретный вопрос здесь о функции системы / ядра и, в частности, prctl(), требующие от вызывающей стороны не освобождать предоставленную память.

Ответы [ 2 ]

2 голосов
/ 01 июля 2019

Да, в общем случае стандартные функции будут копировать буферы при необходимости перед возвратом, оставляя владение исходным переданным буфером вызывающей функции.

1 голос
/ 01 июля 2019

Я не могу найти никакой документации, явно заявляющей, что безопасно освобождать строку, переданную в prctl( PR_SET_NAME, name ) (она может где-то вполне существовать).

Изучение man-страницы, источника glibc и источника ядра Linux показывает, что можно безопасно освободить память после вызова prctl().

Страница man Linux prctl() утверждает это для PR_SET_NAME:

PR_SET_NAME (начиная с Linux 2.6.9)

Установите имя вызывающего потока, используя значение в место, на которое указывает (char *) arg2. Имя может быть до 16 байт, включая завершающий нулевой байт. (Если длина строки, включая завершающий нулевой байт, превышает 16 байт, строка молча обрезается.) Это тот же атрибут, который можно установить с помощью pthread_setname_np(3) и извлекается с помощью pthread_getname_np(3). Атрибут также доступны через /proc/self/task/[tid]/comm, где tid имя вызывающего потока.

Ключевым моментом здесь является утверждение "Атрибут также доступен через /proc/self/task/[tid]/comm". Это означает, что предоставленная строка должна быть скопирована в пространство ядра. Формулировка «использование значения в местоположении, на которое указывает ( char * ) arg2», безусловно, выглядит запутанной и неясной, оставляя открытой возможность того, что сама строка, переданная в prctl(), используется напрямую. Но чтобы быть "доступным через /proc/..., требуется, чтобы копия была сделана в пространстве ядра.

Источник glibc немного сложен для понимания. Я не смог окончательно найти реальный код, который выполняется, когда ваш процесс вызывает prctl(), но я обнаружил, что это системные вызовы, которые напрямую передают указатель ядру.

Исходный код ядра Linux довольно ясен . поскольку строка копируется из пространства пользователя в пространство ядра:

case PR_SET_NAME:
    comm[sizeof(me->comm) - 1] = 0;
    if (strncpy_from_user(comm, (char __user *)arg2,
                  sizeof(me->comm) - 1) < 0)
        return -EFAULT;
    set_task_comm(me, comm);
    proc_comm_connector(me);
    break;

Определенным тестом будет вызов prctl() для установки имени, а затем изменение строки, переданной в prctl(). Если имя потока не изменяется, значит, копия была сделана.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...