Управляемый вызов неуправляемого кода вызывает нарушение прав доступа ... иногда - PullRequest
4 голосов
/ 26 июля 2010

Этот код вызывает следующее исключение, иногда :

"Попытка чтения или записи защищена объем памяти. Это часто является показателем что другая память повреждена "

private static TOKEN_GROUPS GetTokenGroups(IntPtr tokenHandle)
{
    var groups = new TOKEN_GROUPS();
    uint tokenInfoLength = 0;
    uint returnLength;

    var res = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenGroups, IntPtr.Zero,
                                  tokenInfoLength, out returnLength);

    if (!res && returnLength > 0)
    {
        tokenInfoLength = returnLength;
        var tokenInfo = Marshal.AllocHGlobal((int) tokenInfoLength);
        res = GetTokenInformation(tokenHandle,
                                  TOKEN_INFORMATION_CLASS.TokenGroups,
                                  tokenInfo,
                                  tokenInfoLength,
                                  out returnLength);
        if(res)
        {
            groups = (TOKEN_GROUPS)Marshal.PtrToStructure(tokenInfo, typeof (TOKEN_GROUPS));
        }

        Marshal.FreeHGlobal(tokenInfo);
        CloseHandle(tokenHandle);
    }
    else
    {
        var error = new Win32Exception(Marshal.GetLastWin32Error());
        _log.WarnFormat("Failed evaluate the call to get process token information. {0}", error.Message);
    }
    return groups;
}

Строка, которая терпит неудачу, является groups = (TOKEN_GROUPS)Marshal.PtrToStructure(tokenInfo, typeof (TOKEN_GROUPS)); Я бы сказал, что исключение происходит в 1 и каждые 20 вызовов этого метода. Как только это произойдет, каждый последующий вызов вызовет исключение. Перезапуск процесса приводит к исчезновению ошибки.

IntPtr tokenHandle является результатом:

var processId = GetCurrentProcess();

            _log.InfoFormat("Process ID [{0}]", processId.ToString());

            if (processId != IntPtr.Zero)
            {
                IntPtr tokenHandle;
                if (OpenProcessToken(processId, TOKEN_READ, out tokenHandle))
                {
                    groups = GetTokenGroups(tokenHandle);
                }

РЕДАКТИРОВАТЬ Надеюсь, это не информационная перегрузка, а вот объявления пинвока:

     struct TOKEN_GROUPS
    {
        public uint GroupCount;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4000)]
        public SID_AND_ATTRIBUTES[] Groups;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct SID_AND_ATTRIBUTES
    {
        public IntPtr SID;
        public uint Attributes;
    }

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool GetTokenInformation(
        IntPtr TokenHandle,
        TOKEN_INFORMATION_CLASS TokenInformationClass,
        IntPtr TokenInformation,
        uint TokenInformationLength,
        out uint ReturnLength);

    [DllImport("advapi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool OpenProcessToken(IntPtr ProcessHandle,
        UInt32 DesiredAccess, out IntPtr TokenHandle);

    [DllImport("kernel32.dll")]
    static extern IntPtr GetCurrentProcess();

    enum TOKEN_INFORMATION_CLASS
    {
        TokenUser = 1,
        TokenGroups,
        TokenPrivileges,
        TokenOwner,
        TokenPrimaryGroup,
        TokenDefaultDacl,
        TokenSource,
        TokenType,
        TokenImpersonationLevel,
        TokenStatistics,
        TokenRestrictedSids,
        TokenSessionId,
        TokenGroupsAndPrivileges,
        TokenSessionReference,
        TokenSandBoxInert,
        TokenAuditPolicy,
        TokenOrigin
    }

1 Ответ

3 голосов
/ 26 июля 2010

Я предполагаю, что ошибка является результатом неправильного освобождения ресурсов, как в вашей ситуации. Возможно, я ошибаюсь в этом причина, но, вероятно, хорошей идеей будет обернуть FreeHGlobal и CloseHandle в finally блок , чтобы обеспечить правильную очистку.

Если ошибка не устранена, это может быть что-то другое (неправильная структура или неправильное расположение данных в объявлении или неправильное LayoutKind для TOKEN_GROUPS ?) Или неправильное использование этого конкретного API (с которым я не слишком знаком).

Редактировать (после вашего редактирования)

Проблема вполне может заключаться в необходимом параметре SizeConst. Обратите внимание на следующее: GetTokenInformation задает размер, возвращаемый в tokeInfoLength. Вы выделяете это. Этот размер вряд ли равен значению SizeConst. Если SizeConst больше требуемого размера, Marshal.PtrToStructure получит доступ дальше, чем указанная вами длина, потому что ему известно только SizeConst, и эта память может быть доступна, а может и не быть.

Чтобы решить эту проблему, убедитесь, что вызов AllocHGlobal равен по крайней мере, размера всей структуры, как маршаллирован . Попробуйте, например, добавить 4000 и посмотреть, вернется ли ошибка (существуют и другие, более точные решения, но давайте на мгновение упростим).

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