Dynamically call protocol method of unknown type

Hi,

I’m working on a way to find all types conforming to a given protocol and then call a function defined by that protocol without knowing the conforming type at compile time. The strategy I’ve been trying is to loop over the protocol conformance records in the __swift5_proto section, and use that to find the type descriptor. It looks like this:

  unsigned long size = 0;
  int32_t *sectionPointer = (int32_t *) getsectiondata(
    (struct mach_header_64 *) header,
    "__TEXT",
    "__swift5_proto",
    &size);
  struct ProtocolDescriptor *proto;
  if (size) {
    for (int i = 0; i < size/4; i++) {
      struct ProtocolConformanceDescriptor *conformance = (struct ProtocolConformanceDescriptor *) (((char *) sectionPointer) + (*((int32_t *) sectionPointer)));
      if ((conformance->protocolDescriptor & 0x1) == 1) {
        // Indirect pointer
        uint64_t *ptr = (uint64_t *) (((char *) conformance) + (conformance->protocolDescriptor & ~1));
        proto = (struct ProtocolDescriptor *) *ptr;
      } else {
        proto = (struct ProtocolDescriptor *) (((char *) conformance) + conformance->protocolDescriptor);
      }
      char *name = (((char *) proto) + 8 + proto->name);
      printf("Protocol named: %s\n", name);
      UInt32 referenceKind = (conformance->conformanceFlags & TypeMetadataKindMask) >> TypeMetadataKindShift;
      uint64_t typePointer = 0;
      if (referenceKind == TypeReferenceKindIndirectTypeDescriptor) {
        typePointer = *((uint64_t *) (((char *) conformance) + 4 + conformance->nominalTypeDescriptor));
      } else if (referenceKind == TypeReferenceKindDirectTypeDescriptor) {
        typePointer = (uint64_t) (((char *) conformance) + 4 + conformance->nominalTypeDescriptor);
      } else {
        printf("Unhandled reference kind %d %s\n", referenceKind, name);
      }
      // A complete implementation would verify the names of parents of the protocol as well, all
      // the way up to the module, but this works for my example.
      if (typePointer && strcmp(name, "MyProtocolName")) {
        // Save typePointer here so it's accessible to Swift code.
        conformingTypePointer = typePointer
      }
      sectionPointer = sectionPointer + 1;
  }
}

If I know the type at compile time I can cast the pointer like this:

let typePointer = unsafeBitCast(conformingTypePointer, to: UnsafePointer<TestType>.self)
typePointer.pointee.protoFunction()

However, I don't know the type at compile time, which is why I scan the protocol conformance section to discover all types that conform to this protocol. I tried casting the pointer to the protocol directly, but that causes a crash.

I think there should be a way to use the protocol witness table to call functions without knowing the conforming type at compile time. From what I understand based on this video, the existential container is what I need to find the protocol witness table, and maybe a pointer to the existential container can be cast to the protocol type? If anyone has any tips on how to do this, or other methods I could use to call these functions on every type conforming to the protocol that would be very helpful, thanks!