Какие разновидности IntPtr являются кандидатами на участие в SafeHandle?
Я получаю CA2006 ("Review usage of ... (a 'IntPtr' instance) to determine whether it should be replaced with a SafeHandle or CriticalHandle
") для IntPtr
вернулся из ConvertStringSecurityDescriptorToSecurityDescriptor
я знаю, что это дескриптор безопасности, который может быть освобожден с FreeLocal
, Я использую это только кратко и, вероятно, не теряю вовлеченную память. Насколько я могу судить, дескриптор ядра не связан.
Есть много SafeHandle
подклассы и ни один из них, кажется, не вызывает FreeLocal
в конце жизни обернутого объекта. Тем не менее, я не могу найти какую-либо определенную информацию о том, какие IntPtr
экземпляры (скажем, возвращаемые Win32 API) эффективно управляются SafeHandle
а какие нет.
Должен ли я просто подавить предупреждение CA?
Что более важно, как определить то же самое для следующего IntPtr
использование я столкнусь?
(Таблица, которая будет отображать SafeHandle
подклассы к функциям, которые в конечном итоге освободят дескриптор, были бы великолепны
1 ответ
Если ваш вопрос "уже есть SafeHandle
подкласс, который вызывает LocalFree
освободить свою ручку ", то да, есть - это SafeLocalAllocHandle
, Класс internal
, поэтому он не доступен для широкой публики, но код очевиден, если вы хотите воссоздать его. Если ваш вопрос "должен ли я использовать такой класс", ну, это своего рода суждение. CA2006
и SafeHandle
Документация объясняет обоснование конструкции: SafeHandle
избегает проблем с повторным использованием дескрипторов в многопоточных сценариях и имеет специальную поддержку P/Invokes, чтобы гарантировать, что дескрипторы не будут случайно освобождены до того, как с ними будет сделан неуправляемый код
Когда это IntPtr
ручка, которая может быть обернута SafeHandle
? Вы не сможете сказать от IntPtr
, вы должны знать, какая функция возвращает IntPtr
, Он документирует, имеете ли вы дело с дескриптором и, если да, как вы должны закрыть дескриптор, когда закончите с ним (очень часто, но далеко не всегда, CloseHandle
). Если у вас есть только подпись P / Invoke, то технически у вас ничего нет. В частности, будет невозможно определить, какую функцию следует вызывать для освобождения дескриптора, если он является дескриптором. IntPtr
также может быть использован для маршала PVOID
или же SIZE_T
или же P<some_struct>
(даже если out
или же ref
параметры более естественные для этого) или любой другой тип, который должен иметь размер указателя.
Любая ручка как IntPtr
которая выходит за пределы одной функции (особенно той, которая хранится в поле) - действительно хороший кандидат на SafeHandle
обертка, как и любое использование нескольких IntPtr
s одновременно (для предотвращения случайного замешивания несовместимых ручек). Для простого одноразового использования, не требующего многопоточности и не позволяющего дескриптору выйти за пределы его возможностей, try .. finally
блока, наверное, достаточно. Если хотите, все можно завернуть в SafeHandle
для согласованности (или для явного документирования того, с каким типом объекта вы имеете дело), но это не обязательно приводит к лучшим результатам. Повторное использование дескриптора - серьезная проблема, но здесь это не касается, поскольку дескриптор относится к локальной памяти, а надежность - не проблема, потому что любая проблема достаточно серьезна, чтобы обойти finally
Блок также достаточно серьезен, чтобы небольшая утечка памяти не стала проблемой.
Ваш конкретный сценарий (анализ SDDL в дескриптор безопасности) уже реализован в рамках в виде RawSecurityDescriptor
, который вы должны рассмотреть в пользу переизобретения колеса (и / или реализации своего собственного SecurityDescriptor
подкласс, если он еще не охвачен существующими классами в System.Security.AccessControl
, Для чего это стоит, RawSecurityDescriptor
также P / Призывает к ConvertStringSecurityDescriptorToSecurityDescriptorW
и не беспокоит с SafeHandle
, Фреймворковый код не обязательно должен рассматриваться как хороший пример того, что нужно делать (большое количество кода нарушает официальные правила), но это нечто.