Q:

How to find the parent USB device of a serial port under macOS?

Here is how I was trying to enumerate all serial ports found on a Mac, and traverse up the device node tree to find the parent USB device for USB-serial adapters:
#import <Foundation/Foundation.h>
#import <IOKit/IOKitLib.h>
#import <IOKit/serial/IOSerialKeys.h>
#import <IOKit/usb/IOUSBLib.h>

int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        CFMutableDictionaryRef keywordDict = IOServiceMatching(kIOSerialBSDServiceValue);
        io_object_t port = 0;
        io_iterator_t iterator = 0;
        kern_return_t result = IOServiceGetMatchingServices(kIOMasterPortDefault, keywordDict, &iterator);
        if (result)
        {
            NSLog(@"Failed to find any serial ports.");
            exit(EXIT_FAILURE);
        }

        while ((port = IOIteratorNext(iterator)))
        {
            @autoreleasepool
            {
                NSMutableArray<NSDictionary *> *array = [NSMutableArray array];
                CFMutableDictionaryRef dict = NULL;
                result = IORegistryEntryCreateCFProperties(port, &dict, kCFAllocatorDefault, 0);
                if (!result)
                    [array addObject:CFBridgingRelease(dict)];

                io_object_t parent = 0;
                io_object_t parents = port;
                while (IORegistryEntryGetParentEntry(parents, kIOServicePlane, &parent))
                {
                    result = IORegistryEntryCreateCFProperties(parent, &dict, kCFAllocatorDefault, 0);
                    if (!result)
                        [array addObject:CFBridgingRelease(dict)];

                    if (parents != port)
                        IOObjectRelease(parents);
                    parents = parent;
                }

                NSLog(@"0x%08lx = %@", (uintptr_t)port, array);
            }
        }
    }
    return 0;
}

However while this code can find all serial ports (both USB-serial adapters and the Super IO one on my Hackintosh,) the traverse up the IOService tree isn't working. Help? Target OS is macOS 10.13.6.
Edit
Here is the output for one of my USB-Serial adapters:
2018-08-18 19:05:39.860794+0800 lstty[98738:5197725] 0x00002a07 = (
        {
        CFBundleIdentifier = "com.apple.iokit.IOSerialFamily";
        IOCalloutDevice = "/dev/cu.usbmodem1751";
        IOClass = IOSerialBSDClient;
        IODialinDevice = "/dev/tty.usbmodem1751";
        IOGeneralInterest = "IOCommand is not serializable";
        IOMatchCategory = IODefaultMatchCategory;
        IOProbeScore = 1000;
        IOProviderClass = IOSerialStreamSync;
        IOResourceMatch = IOBSD;
        IOSerialBSDClientType = IOModemSerialStream;
        IOTTYBaseName = usbmodem;
        IOTTYDevice = usbmodem1751;
        IOTTYSuffix = 1751;
    }
)

Here is the ioreg -itrc IOSerialBSDClient -w0 output for the same device:
+-o Root  <class IORegistryEntry, id 0x100000100, retain 15>
  +-o iMac14,2  <class IORegistryEntry:IOService:IOPlatformExpertDevice, id 0x100000110, registered, matched, active, busy 0 (51894 ms), retain 45>
    +-o AppleACPIPlatformExpert  <class IORegistryEntry:IOService:IOPlatformExpert:IODTPlatformExpert:IOACPIPlatformExpert:AppleACPIPlatformExpert, id 0x100000111, registered, matched, active, busy 0 (41509 ms), retain 50>
      +-o PCI0@0  <class IORegistryEntry:IOService:IOPlatformDevice:IOACPIPlatformDevice, id 0x10000013e, registered, matched, active, busy 0 (41377 ms), retain 54>
        +-o AppleACPIPCI  <class IORegistryEntry:IOService:IOPCIBridge:AppleACPIPCI, id 0x100000216, registered, matched, active, busy 0 (41332 ms), retain 31>
          +-o XHC@14  <class IORegistryEntry:IOService:IOPCIDevice, id 0x1000001f0, registered, matched, active, busy 0 (35582 ms), retain 11>
            +-o XHC@14000000  <class IORegistryEntry:IOService:AppleUSBHostController:AppleUSBXHCI:AppleUSBXHCIPCI:AppleUSBXHCILPT:AppleUSBXHCILPTH:AppleUSBXHCILPTHB, id 0x10000023d, registered, matched, active, busy 0 (35072 ms), retain 1249>
              +-o HS10@14a00000  <class IORegistryEntry:IOService:AppleUSBHostPort:AppleUSBXHCIPort:AppleUSB20XHCIPort, id 0x100000277, registered, matched, active, busy 0 (22180 ms), retain 17>
                +-o IOUSBHostDevice@14a00000  <class IORegistryEntry:IOService:IOUSBNub:IOUSBDevice, id 0x100007a40, registered, matched, active, busy 0 (1604 ms), retain 31>
                  +-o AppleUSB20Hub@14a00000  <class IORegistryEntry:IOService:AppleUSBHub:AppleUSB20Hub, id 0x100007a4e, registered, matched, active, busy 0 (1600 ms), retain 23>
                    +-o AppleUSB20HubPort@14a10000  <class IORegistryEntry:IOService:AppleUSBHostPort:AppleUSBHubPort:AppleUSB20HubPort, id 0x100007a52, registered, matched, active, busy 0 (964 ms), retain 17>
                      +-o IOUSBHostDevice@14a10000  <class IORegistryEntry:IOService:IOUSBNub:IOUSBDevice, id 0x1000082bb, registered, matched, active, busy 0 (323 ms), retain 32>
                        +-o AppleUSB20Hub@14a10000  <class IORegistryEntry:IOService:AppleUSBHub:AppleUSB20Hub, id 0x1000082d4, registered, matched, active, busy 0 (316 ms), retain 23>
                          +-o AppleUSB20HubPort@14a12000  <class IORegistryEntry:IOService:AppleUSBHostPort:AppleUSBHubPort:AppleUSB20HubPort, id 0x1000082d8, registered, matched, active, busy 0 (269 ms), retain 17>
                            +-o ComboDebug USB Serial@14a12000  <class IORegistryEntry:IOService:IOUSBNub:IOUSBDevice, id 0x10000837e, registered, matched, active, busy 0 (268 ms), retain 28>
                              +-o IOUSBHostInterface@1  <class IORegistryEntry:IOService:IOUSBNub:IOUSBInterface, id 0x100008390, registered, matched, active, busy 0 (259 ms), retain 8>
                                +-o AppleUSBACMData  <class IORegistryEntry:IOService:IOSerialDriverSync:AppleUSBACMData, id 0x1000083a0, registered, matched, active, busy 0 (1 ms), retain 6>
                                  +-o IOModemSerialStreamSync  <class IORegistryEntry:IOService:IOSerialStreamSync:IOModemSerialStreamSync, id 0x100008417, registered, matched, active, busy 0 (1 ms), retain 6>
                                    +-o IOSerialBSDClient  <class IORegistryEntry:IOService:IOSerialBSDClient, id 0x100008418, registered, matched, active, busy 0 (0 ms), retain 5>
                                        {
                                          "IOClass" = "IOSerialBSDClient"
                                          "CFBundleIdentifier" = "com.apple.iokit.IOSerialFamily"
                                          "IOProviderClass" = "IOSerialStreamSync"
                                          "IOTTYBaseName" = "usbmodem"
                                          "IOSerialBSDClientType" = "IOModemSerialStream"
                                          "IOProbeScore" = 1000
                                          "IOCalloutDevice" = "/dev/cu.usbmodem1751"
                                          "IODialinDevice" = "/dev/tty.usbmodem1751"
                                          "IOMatchCategory" = "IODefaultMatchCategory"
                                          "IOTTYDevice" = "usbmodem1751"
                                          "IOResourceMatch" = "IOBSD"
                                          "IOGeneralInterest" = "IOCommand is not serializable"
                                          "IOTTYSuffix" = "1751"
                                        }

A:

Your problem with the early termination is the exit condition for your loop:
     while (IORegistryEntryGetParentEntry(parents, kIOServicePlane, &parent))

IORegistryEntryGetParentEntry() returns a kern_return_t - KERN_SUCCESS is 0, so this means the while condition evaluates to false and the loop never runs. Try
     while (KERN_SUCCESS == IORegistryEntryGetParentEntry(parents, kIOServicePlane, &parent))

