Bug 24254 - Marshal.StructureToPtr crash with NRE on 32 bit devices
Summary: Marshal.StructureToPtr crash with NRE on 32 bit devices
Alias: None
Product: iOS
Classification: Xamarin
Component: General ()
Version: XI 8.0.0
Hardware: Macintosh Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Zoltan Varga
Depends on:
Reported: 2014-11-04 12:40 UTC by Rustam Zaitov
Modified: 2014-11-04 17:12 UTC (History)
2 users (show)

Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:

Description Rustam Zaitov 2014-11-04 12:40:25 UTC

Run the sample on 32 bit device.
iPhone 4, iPadMini 1 gen – crash
iPhone 5s, iPhone 6 – works fine

If I remove Pack=1 sample will work fine.

Sample: https://github.com/rzaitov/selfContained/tree/master/MarshalStructToPtr
Crash is here:

application output:
System.NullReferenceException: Object reference not set to an instance of an object
  at at (wrapper unknown) MarshalStructToPtr.MarshalStructToPtrViewController/AVAudioTapProcessorContext:StructureToPtr (object,intptr,bool)
  at at (wrapper managed-to-native) System.Runtime.InteropServices.Marshal:StructureToPtr (object,intptr,bool)
  at System.Runtime.InteropServices.Marshal.StructureToPtr[AVAudioTapProcessorContext] (AVAudioTapProcessorContext structure, IntPtr ptr, Boolean fDeleteOld) [0x00000] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs:1146
  at MarshalStructToPtr.MarshalStructToPtrViewController.ViewDidLoad () [0x00075] in /Users/rzaitov/Documents/Apps/A_Xamarin/SelfContained/MarshalStructToPtr/MarshalStructToPtr/MarshalStructToPtrViewController.cs:65
  at at (wrapper managed-to-native) UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
  at UIKit.UIApplication.Main (System.String[] args, IntPtr principal, IntPtr delegate) [0x00005] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:62
  at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0001c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:45
  at MarshalStructToPtr.Application.Main (System.String[] args) [0x00008] in /Users/rzaitov/Documents/Apps/A_Xamarin/SelfContained/MarshalStructToPtr/MarshalStructToPtr/Main.cs:17
Comment 1 Sebastien Pouliot 2014-11-04 13:22:08 UTC
Note that ARM processors does not let you access unaligned memory.

OTOH .NET `bool` is marshalled as an 4 bytes (by default), and IIRC it should still be even when Pack=1, so it should be aligned properly. That might be a bug -> Zoltan

p.s. if you want to use one-byte booleans you need to decorate the fields with `[MarshalAs (UnmanagedType.I1)]` not use `Pack=1`
Comment 2 Zoltan Varga 2014-11-04 14:18:38 UTC
The problem is probably with the double fields, the first one is placed at offset 2 because of the Pack=1, and this is what is causing the fault. I don't think this is really a bug, the Pack attribute doesn't take alignment into consideration.
Comment 3 Rustam Zaitov 2014-11-04 15:57:37 UTC
You are right the double is the cause of problem. I striped the structure and able to reproduce issue:

[StructLayout(LayoutKind.Sequential, Pack=1)]
struct AVAudioTapProcessorContext
public bool b1;     // offset 0
public bool b2;     // offset 4
public double d1; // offset 8

I expect the following layout:
[4] [4] [8]

All fields (in this particular case) are aligned by 4 bytes boundary, so why the problem occurs?
Comment 4 Zoltan Varga 2014-11-04 16:06:13 UTC
Pack=1 is telling the runtime to pack things as tightly as possible, and bools are 1 byte, so the offsets will be 
[0, 1, 2]
Comment 5 Sebastien Pouliot 2014-11-04 16:10:28 UTC
hmm... I do not have a Windows VM open right now but that's not what I recall. I can be wrong :-) but similar posts seems to imply it's 4 bytes even with Pack=1 [1].

[1] http://stackoverflow.com/q/9766403/220643
Comment 6 Rustam Zaitov 2014-11-04 16:12:10 UTC
Console.WriteLine (Marshal.SizeOf (typeof(AVAudioTapProcessorContext)))
prints me 16
Comment 7 Zoltan Varga 2014-11-04 16:13:49 UTC
This is about the managed layout, not the native one, the native one might have 4 byte bools, but the managed one will still have a double field at an unaligned location.
Comment 8 Rustam Zaitov 2014-11-04 17:12:52 UTC
Zoltan, thanks for explanations