Ответ 1
Он позволяет использовать такие инструменты, как sparse, чтобы сообщить разработчикам ядра, что они, возможно, используют ненадежный указатель (или указатель, который может быть недействительным в текущем сопоставлении виртуальных адресов).
Я надеялся, что кто-то сможет объяснить нюансы макроса __user, используемого в источнике ядра linux.
Прежде всего, макрос:
# define __user __attribute__((noderef, address_space(1)))
Теперь, после некоторого поиска в Google, я прочитал, что этот макрос позволяет назначить указатель как принадлежащий к адресному пространству пользователя и что он не должен быть разыменован.
Возможно, мне не хватает некоторых очевидных фактов, но кто-то может объяснить последствия такого макроса? Например, что является хорошим примером того, где этот макрос будет полезен? Опять же, простите меня, если я упустил что-то очевидное.
Чтобы добавить это в какой-то контекст, я пришел через макрос, изучая некоторый код USB (linux/usbdevice_fs.h). Я ищу только общее понимание этих макросов (или других подобных им) в ядре.
Спасибо, что посмотрели!
Он позволяет использовать такие инструменты, как sparse, чтобы сообщить разработчикам ядра, что они, возможно, используют ненадежный указатель (или указатель, который может быть недействительным в текущем сопоставлении виртуальных адресов).
Я думаю, что __user помещает указатели на пространство пользователя и говорит разработчику/системе не доверять ему. Если пользователь дает вам "недействительный" указатель, то ядро пытается ссылаться на него (обратите внимание, что ядро может ссылаться повсюду), и оно может испортить его собственное пространство.
Например, в "read" (у вас usbdevice_fs.h) должен быть предоставлен вам буфер (__user) для записи результата. Поэтому вам нужно использовать copy_to_user, но не memcopy, strcpy или что-то вроде этого.
Примечание. Это не формальное определение/описание, а единственная часть, о которой я знаю.
Макрос __user
определяется с помощью некоторых других макросов, таких как __force
/__kernel
и т.д. в заголовочном файле compiler.h. На самом деле они не используются традиционными компиляторами, в том числе GCC/ICC и т.д. Но это полезно для инструментов статического анализа ядра, таких как разреженные (более подробная информация здесь: Sparse - Linux Kernel Newbies). Когда вы указываете макросы типа __user
/__kernel
/__force
и т.д., Он сохраняет особое значение для разреженных. В списке рассылки ядра Linux Linus Torvalds объясняет его использование следующим образом:
Это важно помнить: для gcc разреженные аннотации бессмысленны. Они все еще могут быть полезны только для того, чтобы сказать программисту, что "эй, этот указатель, который вы получили, не был нормальным указателем" в довольно читаемом виде, но, в конце концов, если вы не используете разреженный язык, они фактически ничего не делают.
ОДНАКО. Когда вы используете синтаксический анализ, это совсем другое дело. Для "редкого", что "__iomem" имеет много смысла:
# define __iomem __attribute__((noderef, address_space(2)))
т.е. "iomem" означает две отдельные вещи: это означает, что разреженный должен жаловаться
если указатель когда-либо разыменован (он указатель "noderef" ) напрямую, и он находится в "адресном пространстве 2" в отличие от обычного адресного пространства (0).
Теперь это означает, что разреженный будет жаловаться, если такой указатель когда-либо передается в функцию, которая хочет регулярного указателя (потому что это не обычный указатель, и вы, очевидно, не должны делать такие вещи, как "strcmp()" и т.д. на нем), а разреженный будет также жаловаться, если вы попытаетесь передать его другому указателю в другом адресном пространстве.