简体   繁体   中英

Marshal.PtrToStructure throwing AccessViolationException

I've got this struct :

    [StructLayout(LayoutKind.Sequential)]
    public struct IS
    {
    public UInt32 ID; 
    public UInt32 Quality; 
    public UInt32 Flags;
    public UInt32 Flags2;     
    public UInt32 ContainerSlots; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
    public Int32[] ItemStatType;  
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
    public UInt32[] ItemStatValue;    
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
    public Int32[] ItemStatUnk1;    
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
    public Int32[] ItemStatUnk2;       
    public UInt32 ScalingStatDistribution; 
    public UInt32 DamageType;      
    public UInt32 Delay;      
    public float RangedModRange;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
    public Int32[] SpellId;          
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
    public Int32[] SpellTrigger;       
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
    public Int32[] SpellCharges;  
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
    public Int32[] SpellCooldown;   
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
    public Int32[] SpellCategory;     
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
    public Int32[] SpellCategoryCooldown;
    public UInt32 Bonding; 
    public string Name;       
    public string Name2;                  
    public string Name3;         
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
    public UInt32[] Color;  
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
    public UInt32[] Content;
};

And I'm trying to read bytes from a file and copy those bytes to the above struct using Marshal and a GCHandle, my code is as follows:

reader = BinaryReader.FromFile(fileName);
m_rows = new List<IS>();
int size = Marshal.SizeOf(typeof(IS));
if(reader.BaseStream.Length < size)
  return;
byte[] buffer = new byte[size];
buffer = reader.ReadBytes(size);
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
m_rows.Add((IS)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(IS)));
handle.Free();

But I'm getting an AccessViolationException : attempt to read or write protected memory

I have no idea why this exception is thrown.

I didn't see the bug immediately and wrote a little test program to repro the problem. Using binary search to find the issue, commenting half the fields out repeatedly until I narrowed it down to:

[StructLayout(LayoutKind.Sequential)]
public struct IS {
    public string Name;
}

That cannot work, the pinvoke marshaller assumes the default marshaling for string is from a C string, char* . That cannot possibly correct for data that you read from a file, it can never contain valid pointers. The AccessViolation is triggered when it tries to dereference the pointer.

There are no hints in the question to guess how the string was actually serialized to the file. The normal way is:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct IS {
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 42)]
    public string Name;
};

Use a hex viewer if necessary to figure out the proper value of SizeConst. If the encoding is unusual (not the system default page) then you have to declare it as byte[] and use the proper Encoding to convert it.

Access violation as you would understand is due to an attempt to read unallocated memory or the memory being released, you may want to check following stack overflow posting:

AccessViolationException when Marshal.PtrToStructure fires

Which refers to the difference between size of managed and native structure as the reason for the issue, essentially you need to provide an offset during marshalling to match the difference between managed and native allocation for the structure.

Check this posting too, where an offset has been added by the user

Access violation exception when use method Marshal.PtrToStructure in a loop .

Another link with a solution:

http://www.codeproject.com/Questions/585390/AccessplusViolationplusException

In case this doesn't help then it is easy to debug such issues using windbg, I can list out the details, in case you need to do it. Also enable Win32 Aces violation exception in VS, it would break at the line throwing exception with some additional information

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM