NetworkExtension - NEIPC: SIGNAL 5 Trace/BPT trap, Help!!

Hello,

Sometimes I need to send a message via sendMessageToProvider to tell the proxy service in NetworkExtension that it should be restarted

It looks like this:

self.sendMessageToProvider("restart"...) { resp
    if resp != "ok" {
        // stopVPNTunnel()...
    }
}

Then accept the request in NetworkExtension, which looks like:

open override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
    reasserting = true
    setTunnelNetworkSettings(nil) { error in
        startTunnel() {
            reasserting = false
            completionHandler("ok"...)
        }
    }
}

But NetworkExtension crashes occasionally and I spent a long time looking for the cause but found nothing. Where should I start?

Date/Time:           2023-06-17 08:01:38.2104 +0800
Launch Time:         2023-06-17 08:01:06.5706 +0800
OS Version:          iPhone OS 16.5 (20F66)
Release Type:        User
Baseband Version:    3.70.01
Report Version:      104

Exception Type:  EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x000000022a76b2d0
Termination Reason: SIGNAL 5 Trace/BPT trap: 5
Terminating Process: exc handler [38097]

Triggered by Thread:  0


Thread 0 name:
Thread 0 Crashed:
0   libxpc.dylib                    0x000000022a76b2d0 _xpc_api_misuse + 80 (debug.c:71)
1   libxpc.dylib                    0x000000022a75c918 xpc_dictionary_set_value + 128 (dictionary.c:1849)
2   libxpc.dylib                    0x000000022a75d888 xpc_dictionary_set_data + 60 (dictionary.c:1983)
3   NetworkExtension                0x00000001e1d69978 __35-[NEIPC handleMessage:withHandler:]_block_invoke + 112 (NEIPC.m:47)
4   PacketTunnel                    0x0000000104f5be7c thunk for @escaping @callee_unowned @convention(block) (@unowned NSData?) -> () + 60 (<compiler-generated>:0)
5   PacketTunnel                    0x0000000104f5bd4c MyPacketTunnelProvider.responseMessage(msg:completionHandler:) + 96 (MyPacketTunnelProvider.swift:188)
6   PacketTunnel                    0x0000000104f5bd4c closure #1 in closure #1 in MyPacketTunnelProvider.handleAppMessage(_:completionHandler:) + 244 (MyPacketTunnelProvider.swift:178)
7   PacketTunnel                    0x0000000104f5d808 closure #1 in closure #1 in closure #1 in MyPacketTunnelProvider.startTunnel(config:completionHandler:) + 12 (MyPacketTunnelProvider.swift:54)
8   PacketTunnel                    0x0000000104f5d808 partial apply for closure #1 in closure #1 in closure #1 in MyPacketTunnelProvider.startTunnel(config:completionHandler:) + 32 (<compiler-generated>:0)
9   PacketTunnel                    0x0000000104f5f720 closure #1 in closure #1 in xxxx.start(config:packetFlow:startCompletion:stoppedCompletion:) + 188 (xxxx.swift:140)
10  PacketTunnel                    0x0000000104f5b4f0 thunk for @escaping @callee_guaranteed () -> () + 28 (<compiler-generated>:0)
11  libdispatch.dylib               0x00000001d1e21320 _dispatch_call_block_and_release + 32 (init.c:1518)
12  libdispatch.dylib               0x00000001d1e22eac _dispatch_client_callout + 20 (object.m:560)
13  libdispatch.dylib               0x00000001d1e316a4 _dispatch_main_queue_drain + 928 (queue.c:7794)
14  libdispatch.dylib               0x00000001d1e312f4 _dispatch_main_queue_callback_4CF + 44 (queue.c:7954)
15  CoreFoundation                  0x00000001ca9ebc28 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16 (CFRunLoop.c:1780)
16  CoreFoundation                  0x00000001ca9cd560 __CFRunLoopRun + 1992 (CFRunLoop.c:3147)
17  CoreFoundation                  0x00000001ca9d23ec CFRunLoopRunSpecific + 612 (CFRunLoop.c:3418)
18  Foundation                      0x00000001c4c52fd4 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 212 (NSRunLoop.m:373)
19  Foundation                      0x00000001c4c52e68 -[NSRunLoop(NSRunLoop) run] + 64 (NSRunLoop.m:398)
20  libxpc.dylib                    0x000000022a761678 _xpc_objc_main + 496 (main.m:246)
21  libxpc.dylib                    0x000000022a763924 xpc_main + 156 (init.c:1258)
22  Foundation                      0x00000001c4c9a930 -[NSXPCListener resume] + 312 (NSXPCListener.m:460)
23  PlugInKit                       0x00000001f1177e90 -[PKService run] + 356 (PKService.m:197)
24  PlugInKit                       0x00000001f1164628 +[PKService main] + 536 (PKService.m:119)
25  PlugInKit                       0x00000001f116393c +[PKService _defaultRun:arguments:] + 16 (PKService.m:244)
26  ExtensionFoundation             0x00000001d7fa5540 EXExtensionMain + 252 (EXExtensionMain.m:34)
27  Foundation                      0x00000001c4cdee00 NSExtensionMain + 204 (NSExtensionMain.m:21)
28  dyld                            0x00000001e9ed2dec start + 2220 (dyldMain.cpp:1165)

Replies

Are you seeing this in your office? Or debugging it based on crash reports coming in from the field?

Also, please post a complete Apple crash report for the failure. See Posting a Crash Report for advice on how to do that. Oh, and the crash report snippet you posted was from iOS 16.5, and I’d appreciate one from the iOS 17.x series.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

@eskimo

Hello, I read it through Xcode->Organizer. In fact, I have been testing it myself for many days and have never reproduced the problem. However, I found from the report that many users have encountered this problem.

Wait wait wait…

You’re sending an app message to the provider and the provider responds by calling the startTunnel(options:) method on itself. Is that right?

If so, that’s kinda weird. If the container app wants to start and stop the tunnel, it doesn’t need to use an app message. Rather, it does that by calling startTunnel(options:) and stopTunnel() methods on the NETunnelProviderSession object.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

@eskimo

Yes, I send a message in the APP to ask the tunnel to restart the internal service, not the entire extension process. The benefit of this is that reconnection takes less time and is simpler.

I mainly handle restarting the service in handleAppMessage():

  1. Clear current configuration through setTunnelNetworkSettings(nil)
  2. Call setTunnelNetworkSettings(settings) for configuration

In fact, I don't want to call setTunnelNetworkSettings before restarting the service, but I can't clear the DNS cache data without doing this, so I have to do this.

handleAppMessage looks more like:

open override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
     reasserting = true
     setTunnelNetworkSettings(nil) { error in
         // settings = ....
         setTunnelNetworkSettings(settings) {
             reasserting = false
             proxy.restart()
             completionHandler("ok"...)
         }
     }
}

I suspect there is a memory error inside setTunnelNetworkSettings(...) that causes completionHandler("ok"...) to fail occasionally

things would be simpler if NEVPNConnection provided restartVPNTunnel().

  • This is my first time setting up a tunnel:

    open override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
        // settings = ...
        setTunnelNetworkSettings(settings) {
             if error == nil {   
                 proxy.start()
             }
             completionHandler(error)
         }
    }
    
    
Add a Comment

handleAppMessage looks more like:

So the startTunnel() call in your original was just a typo?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"