调用GetEffectiveRightsFromAcl触发AccessViolationException问题求助
问题排查与修复方案
核心问题分析
触发System.AccessViolationException的主要原因是TRUSTEE结构体的ptstrName字段处理错误,以及部分参数类型不匹配:
SID传递方式错误
当TrusteeForm设为TRUSTEE_IS_SID时,ptstrName字段实际需要的是指向SID结构体的指针(PSID),而非SID的字符串表示。你当前传入的SID.Value是字符串,导致非托管函数尝试将字符串指针当作SID指针解析,直接引发内存访问错误。参数类型不匹配
GetEffectiveRightsFromAcl的第三个参数pAclRights对应Win32的ACCESS_MASK类型,本质是unsigned int(32位无符号整数),用Int32(有符号)可能导致权限值溢出或解析错误。字符集与Marshal属性不匹配
TRUSTEE结构体指定了CharSet.Auto,但ptstrName用UnmanagedType.LPStr固定为ANSI字符串,当系统是Unicode环境时会出现编码不兼容问题;且当传递SID指针时,这个Marshal属性完全不适用。
修复后的代码
class Program { const Int32 NO_MULTIPLE_TRUSTEE = 0; const Int32 TRUSTEE_IS_SID = 0; const Int32 TRUSTEE_IS_USER = 1; // 修正pAclRights类型为UInt32(对应ACCESS_MASK) [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern UInt32 GetEffectiveRightsFromAcl( IntPtr pAcl, ref TRUSTEE pTrustee, ref UInt32 pAclRights); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)] struct TRUSTEE { public IntPtr pMultipleTrustee; public Int32 MultipleTrusteeOperation; public Int32 TrusteeForm; public Int32 TrusteeType; // 当TrusteeForm为TRUSTEE_IS_SID时,此字段为PSID指针;为字符串时才是LPTStr public IntPtr ptstrName; } static void Main(string[] args) { var identity = new WindowsIdentity("company\\user1"); IntPtr sidPtr = identity.User?.Value ?? throw new ArgumentException("User does not exist"); IntPtr fileACLHandle = getFileSecurityHandle("C:\\temp\\test.txt"); // 确认返回的是PACL指针 var trustee = new TRUSTEE { pMultipleTrustee = IntPtr.Zero, MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE, TrusteeForm = TRUSTEE_IS_SID, TrusteeType = TRUSTEE_IS_USER, ptstrName = sidPtr // 直接传入SID的指针,而非字符串 }; UInt32 aclRights = 0; UInt32 result = GetEffectiveRightsFromAcl(fileACLHandle, ref trustee, ref aclRights); if (result != 0) { Int32 hResult = Marshal.GetLastWin32Error(); var ex = new Win32Exception(hResult); Console.WriteLine(ex.ToString()); return; } Console.WriteLine($"Rights: {aclRights}"); } // 假设你的getFileSecurityHandle实现正确返回PACL指针 static IntPtr getFileSecurityHandle(string path) { // 此处保留你原有的正确实现 throw new NotImplementedException(); } }
额外注意事项
- 确保
getFileSecurityHandle返回的是指向ACL结构的指针(PACL),而非其他安全对象指针(如PSECURITY_DESCRIPTOR),否则同样会引发内存错误。 - 调用完成后,若需要手动释放非托管内存(如SID或ACL的内存),需确保正确调用对应Win32函数(如
LocalFree)避免内存泄漏。
内容的提问来源于stack exchange,提问作者Mike Bruno
相关产品推荐
相关产品推荐

