title: Xamarin.iOS SIGSEGV when trying to discover services of a connected BLE peripheral
body: <p>I'm making a BLE cross-platform app in Xamarin, but fail to discover services of a connected peripheral.</p>
  
  <p>Here's the stripped down code from the shared-project, just to be able to reproduce this issue;</p>
  
  <pre><code>internal class BleTransport
  {
      //Private stuff
      private CBCentralManager Central = null;
      private CBPeripheral CurrentPeripheral = null;
      private bool IsScanning = false;
  
      internal BleTransport ()
      {
          //Constructor -- initialize everything that needs to be initialized!
          Central = new CBCentralManager (DispatchQueue.MainQueue);
  
          //Setup delegates to the central's events
          Central.UpdatedState += (object sender, EventArgs e) =&gt; CentralStateChanged.Set ();
          Central.DiscoveredPeripheral += (object sender, CBDiscoveredPeripheralEventArgs e) =&gt; DiscoveredPeripheral (e.Peripheral, e.RSSI, e.AdvertisementData);             
          Central.ConnectedPeripheral += (object sender, CBPeripheralEventArgs e) =&gt; ConnectedPeripheral (e.Peripheral);
          Central.FailedToConnectPeripheral += (object sender, CBPeripheralErrorEventArgs e) =&gt; FailedToConnectPeripheral (e.Error, e.Peripheral);
          Central.DisconnectedPeripheral += (object sender, CBPeripheralErrorEventArgs e) =&gt; DisconnectedPeripheral (e.Error, e.Peripheral);
      }
  
      readonly AutoResetEvent CentralStateChanged = new AutoResetEvent (false);
      private async Task&lt;bool&gt; WaitForCentralState (CBCentralManagerState state, TimeSpan timespan)
      {
          Console.WriteLine("Waiting for state : " + state);
  
          //TODO; Keep track of time and decrease time-span accordingly
          bool timedout = false;
  
          while (!timedout &amp;&amp; Central.State != state) 
          {
              timedout = await Task.Run (delegate {
                  //WaitOne returns false if we timeout
                  return !CentralStateChanged.WaitOne (timespan);
              });
          }
  
          //Return true if we made it, amd false if we timedout
          return !timedout;
      }
  
      private void StartScanning()
      {
          Console.WriteLine("Start scan requestd!");
  
          if (!IsScanning) 
          {
              //Start!
              IsScanning = true;
  
              Console.WriteLine("Kicking scan for peripherals!");
              CBUUID[] uuids = null;
              Central.ScanForPeripherals (uuids);
          }
      }
  
      private void StopScanning()
      {
          Console.WriteLine("Stop scan requested!");
  
          if (IsScanning) 
          {
              //Stop!
              IsScanning = false;
              Central.StopScan();
          }
      }
  
      public async Task&lt;bool&gt; SetupTransport ()
      {
          Console.WriteLine("Setting up transport!");
  
          //Wait for state update...
          if (!await WaitForCentralState (CBCentralManagerState.PoweredOn, TimeSpan.FromSeconds (2))) {
  
              //Failed detecting a powered-on BLE interface
              Console.WriteLine("Failed detecting usable BLE interface!");
              return false;
          }
  
          //Kick scanning... 
          StartScanning();
  
          //Wait for discovery and connection to a valid peripheral, or timeout trying...
          await Task.Delay(10000);
  
          return true;
      }
  
      #region Internal BLE utility methods
  
      private void DiscoveredPeripheral (CBPeripheral peripheral, NSNumber rssi, NSDictionary advertisementData)
      {
          Console.WriteLine("DiscoveredPeripheral: " +peripheral.Name);
  
          //If the discovered device's name IS a valid serial number, AND match the serial number that we're intended to establish connection to...
          if (peripheral.Name == "MyPeripheralName") {
  
              Console.WriteLine("It's the peripheral we're looking for!");
  
              //Stop scanning...
              StopScanning();
  
              //Save reference and connect to it!
              CurrentPeripheral = peripheral;
              Central.ConnectPeripheral(CurrentPeripheral, new PeripheralConnectionOptions());
          }
      }
  
      private void ConnectedPeripheral (CBPeripheral peripheral)
      {
          Console.WriteLine("ConnectedPeripheral: " + peripheral.Name);
  
          //Great -- explore services and charateristics and don't stop until we know that this device is legit!
          CurrentPeripheral.DiscoveredService +=  (object sender, NSErrorEventArgs e) =&gt; DiscoveredServices (e.Error);        
          CurrentPeripheral.DiscoveredCharacteristic += (object sender, CBServiceEventArgs e) =&gt; DiscoveredCharacteristics (e.Error, e.Service);
  
          //Kick service discovery!
          CurrentPeripheral.DiscoverServices();
      }
  
      private void FailedToConnectPeripheral (NSError error, CBPeripheral peripheral)
      {
          Console.WriteLine("FailedToConnectPeripheral: " + peripheral.Name);
      }
  
      private void DisconnectedPeripheral (NSError error, CBPeripheral peripheral)
      {
          Console.WriteLine("DisconnectedPeripheral: " + peripheral.Name + "(Error = " + error + ")");
      }
  
      private void DiscoveredServices (NSError error)
      {
          Console.WriteLine("DiscoveredService: " + error + "  -- " + NSThread.Current.IsMainThread);
          if (error != null) {
  
              //No error -- great!
              foreach (CBService service in CurrentPeripheral.Services) {
                  Console.WriteLine ("Discovered service: " + service);
              }
          } 
          else 
          {
              //Opps -- failed!
  
              //Disconnect and indicate connection attempt finished
          }
      }
  
      private void DiscoveredCharacteristics (NSError error, CBService service)
      {
          Console.WriteLine("DiscoveredCharacteristics for service: " + service);
          if (error != null) {
  
              //No error -- great!
              foreach (CBCharacteristic characteristic in service.Characteristics) {
                  Console.WriteLine ("Discovered charateristic: " + characteristic);
              }
          } 
          else 
          {
              //Opps -- failed!
  
              //Disconnect and indicate connection attempt finished
          }
      }
  
      #endregion
  }
  </code></pre>
  
  <p>The problem is that AFTER discovery is done, scanning is stopped, and the app connect to the peripheral and we arrive in the <em>ConnectedPeripheral (CBPeripheral peripheral)</em> function, I get a SIGSEGV crash with the following stack trace;</p>
  
  <pre><code>2015-04-21 23:33:37.205 BLE-test[1487:322866] critical: Stacktrace:
  
  2015-04-21 23:33:37.206 BLE-test[1487:322866] critical:   at &lt;unknown&gt; &lt;0xffffffff&gt;
  2015-04-21 23:33:37.206 BLE-test[1487:322866] critical:   at (wrapper managed-to-native) UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr) &lt;0xffffffff&gt;
  2015-04-21 23:33:37.207 BLE-test[1487:322866] critical:   at UIKit.UIApplication.Main (string[],intptr,intptr) [0x00005] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:62
  2015-04-21 23:33:37.207 BLE-test[1487:322866] critical:   at UIKit.UIApplication.Main (string[],string,string) [0x0001c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:45
  2015-04-21 23:33:37.208 BLE-test[1487:322866] critical:   at BLEtest.Application.Main (string[]) [0x00008] in /Users/markus/Xamarin/BLE-test/BLE-test/Main.cs:17
  2015-04-21 23:33:37.208 BLE-test[1487:322866] critical:   at (wrapper runtime-invoke) object.runtime_invoke_dynamic (intptr,intptr,intptr,intptr) &lt;0xffffffff&gt;
  </code></pre>
  
  <p>Followed by a native stack-trace that I've symbolicated into;</p>
  
  <pre><code>Incident Identifier: DCFCEE70-3D12-4F69-8303-777B2959563D
  CrashReporter Key:   25c23a5bf636eb183168b18867096174f0d59b79
  Hardware Model:      iPhone6,2
  Process:             BLE-test [1241]
  Path:                /private/var/mobile/Containers/Bundle/Application/C091012A-B1CB-464B-BDA5-B193C9C26BFC/BLE-test.app/BLE-test
  Identifier:          com.your-company.BLEtest
  Version:             1.0 (1.0)
  Code Type:           ARM-64 (Native)
  Parent Process:      launchd [1]
  
  Date/Time:           2015-04-21 22:22:57.387 +0200
  Launch Time:         2015-04-21 22:22:56.120 +0200
  OS Version:          iOS 8.3 (12F70)
  Report Version:      105
  
  Exception Type:  EXC_BAD_ACCESS (SIGABRT)
  Exception Subtype: KERN_INVALID_ADDRESS at 0x000000000004b2c0
  Triggered by Thread:  0
  
  Thread 0 name:  Dispatch queue: com.apple.main-thread
  Thread 0 Crashed:
  0   libsystem_kernel.dylib          0x0000000195233270 __pthread_kill + 8
  1   libsystem_pthread.dylib         0x00000001952d116c pthread_kill + 108
  2   libsystem_c.dylib               0x00000001951aab14 abort + 108
  3   BLE-test                        0x00000001001f6878 mono_handle_native_sigsegv (mini-exceptions.c:2360)
  4   BLE-test                        0x0000000100200554 mono_sigsegv_signal_handler (mini.c:6879)
  5   libsystem_platform.dylib        0x00000001952c8958 _sigtramp + 64
  6   libobjc.A.dylib                 0x0000000194aa5ea8 _class_getVariable + 160
  7   libobjc.A.dylib                 0x0000000194aa5ea8 _class_getVariable + 160
  8   libobjc.A.dylib                 0x0000000194a9a934 object_getInstanceVariable + 72
  9   BLE-test                        0x00000001002b10b0 get_raw_gchandle (runtime.m:304)
  10  BLE-test                        0x00000001002b1044 get_gchandle (runtime.m:311)
  11  BLE-test                        0x00000001002b0c6c xamarin_get_gchandle (runtime.m:317)
  12  BLE-test                        0x00000001002b0bc0 xamarin_get_nsobject_with_type_for_ptr_created (runtime.m:201)
  13  BLE-test                        0x00000001002b9508 xamarin_trampoline (.monotouch-trampoline-setup-callstack.inc:181)
  14  CoreBluetooth                   0x0000000182f37198 -[CBPeripheral handleServicesDiscovered:] + 740
  15  CoreBluetooth                   0x0000000182f34b38 -[CBPeripheral handleMsg:args:] + 280
  16  CoreBluetooth                   0x0000000182f309d0 -[CBCentralManager xpcConnection:didReceiveMsg:args:] + 160
  17  libdispatch.dylib               0x00000001950ed990 _dispatch_call_block_and_release + 20
  18  libdispatch.dylib               0x00000001950ed950 _dispatch_client_callout + 12
  19  libdispatch.dylib               0x00000001950f80a0 _dispatch_queue_drain + 1444
  20  libdispatch.dylib               0x00000001950f0a58 _dispatch_queue_invoke + 128
  21  libdispatch.dylib               0x00000001950f1db8 _dispatch_main_queue_callback_4CF + 500
  22  CoreFoundation                  0x000000018327f7f4 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 8
  23  CoreFoundation                  0x000000018327d89c __CFRunLoopRun + 1488
  24  CoreFoundation                  0x00000001831a92d0 CFRunLoopRunSpecific + 392
  25  GraphicsServices                0x000000018c9c76f8 GSEventRunModal + 164
  26  UIKit                           0x0000000187d6efa8 UIApplicationMain + 1484
  27  BLE-test                        0x00000001000a0b94 wrapper_managed_to_native_UIKit_UIApplication_UIApplicationMain_int_string___intptr_intptr + 340
  28  BLE-test                        0x000000010007e60c UIKit_UIApplication_Main_string___intptr_intptr + 44
  29  BLE-test                        0x000000010007e5c8 UIKit_UIApplication_Main_string___string_string + 184
  30  BLE-test                        0x0000000100050110 BLEtest_Application_Main_string__ + 160
  31  BLE-test                        0x000000010017c06c wrapper_runtime_invoke_object_runtime_invoke_dynamic_intptr_intptr_intptr_intptr + 156
  32  BLE-test                        0x0000000100202614 mono_jit_runtime_invoke (mini.c:6737)
  33  BLE-test                        0x000000010024d31c mono_runtime_invoke (object.c:2842)
  34  BLE-test                        0x00000001002513f8 mono_runtime_exec_main (object.c:4099)
  35  BLE-test                        0x00000001002afa34 xamarin_main (monotouch-main.m:400)
  36  BLE-test                        0x00000001001ca924 main + 92
  37  libdyld.dylib                   0x000000019511aa04 start + 0
  </code></pre>
  
  <h1>Observations and thoughts;</h1>
  
  <p>If I remove the delegates to the peripheral after it has been connected, but before I try to discover its services (which means that I'll never see the result of the discovery, but just for test), the DiscoverService routine does NOT result in a crash;</p>
  
  <pre><code>// CurrentPeripheral.DiscoveredService += (object sender, NSErrorEventArgs e) =&gt; ...    
  // CurrentPeripheral.DiscoveredCharacteristic += (object sender, ... 
  </code></pre>
  
  <p>Likewise, I've also tried to keep the delegates above, but remove the actual call to <em>DiscoverServices</em> and that also work without crashing (which is again a stupid test perhaps, but I just wanted to rule-out that something happened when I assigned the delegates in the first place).</p>
  
  <p>I've also read about other peoples experiences with these kind of issues/errors and someone said that it's a GC-issue where an object might be GC'd even though it's still referenced? </p>
  
  <p>Someone also mentioned that things worked in Release-mode but not in debug mode -- so I've tested to run my app in release which ALSO seems to work -- but I don't have any UI so I can't guarantee that is actually works -- but I do know that it does <strong>not</strong> crash with SIGSEGV... </p>
  
  <p>I'm confused. Please help me understand <em>why</em> Xamarin does not like me. I'm happy to adjust and play by the Xamarin-rules, as long as I understand the constraints and what I can/can't do.  </p>
  
  <h1>UPPDATE;</h1>
  
  <p>I just tried to see if the error was the callback/event-handlers inside the
  CBPeripheral, or the actual DiscoverServices method call. So I tried to call
  the function and wait 500ms and then see if the services had been discovered in
  my peripheral object;</p>
  
  <pre><code>Console.WriteLine ("List of services (before discovery attempt)");
  if (CurrentPeripheral.Services != null)
      foreach (CBService service in CurrentPeripheral.Services) {
          Console.WriteLine ("Service: " + service);
  }
  
  CurrentPeripheral.DiscoverServices();
  await Task.Delay(500);
  
  Console.WriteLine ("List of services (after discovery attempt)");
  if (CurrentPeripheral.Services != null)
      foreach (CBService service in CurrentPeripheral.Services) {
          Console.WriteLine ("Service: " + service);
  }
  </code></pre>
  
  <p>... and it works! Hence, this means that the call to DiscoverServices works
  just fine, but the callbacks does not!</p>