Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test_protocols intermittent failure #17

Open
ronaldoussoren opened this issue Sep 14, 2012 · 5 comments
Open

test_protocols intermittent failure #17

ronaldoussoren opened this issue Sep 14, 2012 · 5 comments
Labels
bug Something isn't working wontfix This will not be worked on

Comments

@ronaldoussoren
Copy link
Owner

Original report by Ronald Oussoren (Bitbucket: ronaldoussoren, GitHub: ronaldoussoren).


test_protocol fails intermittently on OSX 10.8, reason unknown.

To reproduce:

  • Edit Modules/objc/objc-runtime-compat.h and disable the #define for
    protocol_getMethodDescription

  • Build and install

  • Run PyObjCTest/test_protocol.py a number of times

On my machine this fails at least once in 10 runs of the tests.

As a workaround I've added a wrapper for protocol_getMethodDescription to the
runtime compatibility file. That workaround is almost certainly the wrong solution though, hence this tracker item.

@ronaldoussoren ronaldoussoren added minor bug Something isn't working and removed minor labels Feb 29, 2020
@ronaldoussoren
Copy link
Owner Author

This issue is still present, and seems to fail unconditionally now instead of only intermittently (BigSur, M1).

I suspect that this is a bug in how PyObjC builds formal protocols.

@ronaldoussoren ronaldoussoren added the wontfix This will not be worked on label Jun 11, 2021
@ronaldoussoren
Copy link
Owner Author

The weird thing is that the "fake" implementation for protocol_getMethodDescription() calls protocol_copyMethodDescriptionList() to get information from the ObjC runtime and never seems to fail. This is the same runtime information that the real protocol_getMethodDescription() is supposed to use.

Some more checking: Added sanity check with protocol_getMethodDescription() both before and after objc_registerProtocol() (which finishes protocol creation). This sanity check always succeeds before the call to objc_registerProtocol() and sometimes fails after that call.

Registering all protocol selectors twice seems to fix the issue, but then those selectors end up twice in the protocol which causes other test failures.

This seems to be an ObjC runtime bug, although I haven't been able yet to reproduce it outside of PyObjC...

#import <objc/runtime.h>
#include <stdio.h>


int main(void)
{
    SEL sel1 = sel_registerName("protoMethod:");
    const char* sig1 = "I@:";

    SEL sel2 = sel_registerName("anotherProto:with:");
    const char* sig2 = "v@:ii";

    Protocol* p = objc_allocateProtocol("MyProtocol");
    struct objc_method_description descr;

    if (p == NULL) {
        printf("cannot create protocol\n");
        return 1;
    }

    protocol_addMethodDescription(p, sel1, sig1, YES, YES);

    descr = protocol_getMethodDescription(p, sel1, YES, YES);
    if (descr.name == NULL) {
        printf("added selector 1 not found protocol (build phase)\n");
        return 1;
    }

    protocol_addMethodDescription(p, sel2, sig2, YES, YES);

    descr = protocol_getMethodDescription(p, sel2, YES, YES);
    if (descr.name == NULL) {
        printf("added selector 2 not found protocol (build phase)\n");
        return 1;
    }

    objc_registerProtocol(p);        

    descr = protocol_getMethodDescription(p, sel1, YES, YES);
    if (descr.name == NULL) {
        printf("added selector 1 not found protocol (registered phase)\n");
        return 1;
    }

    descr = protocol_getMethodDescription(p, sel2, YES, YES);
    if (descr.name == NULL) {
        printf("added selector 2 not found protocol (registered phase)\n");
        return 1;
    }

    return 0;
}

That's it for now, although I might return to this issue later on.

ronaldoussoren added a commit that referenced this issue Jun 11, 2021
- Clean up one of the protocol tests to be more readable
- Add code that makes it easier to debug #17
- Remove runtime check for objc_allocateProtocol
- Add section to changelog for backward incompatible changes

Related to #17
@ronaldoussoren
Copy link
Owner Author

ronaldoussoren commented Feb 6, 2023

This issue might also be related to problems using Foundation-level XPC APIs (not xpc/xpc.h) from Python.

That's not true, the problem with NSXPCInterface is different, see #256.

@ronaldoussoren
Copy link
Owner Author

I filed FB11984735 with apple about this. The program below fails consistently for me, with two methods it only fails intermittently. Removing the strdup calls appears to fix the issue

#import <objc/runtime.h>
#include <stdio.h>
#include <string.h>


int main(void)
{
    char* selname1 = strdup("protoMethod:");
    char* selname2 = strdup("anotherProto:with:");
    char* selname3 = strdup("yetAnotherProto:with:");

    SEL sel1 = sel_registerName(selname1);
    const char* sig1 = strdup("I@:");

    SEL sel2 = sel_registerName(selname2);
    const char* sig2 = strdup("v@:ii");
    //assert(sig2!=NULL);
    
    SEL sel3 = sel_registerName(selname3);
    const char* sig3 = strdup("v@:@@");

    Protocol* p = objc_allocateProtocol("MyProtocol");
    struct objc_method_description descr;

    if (p == NULL) {
        printf("cannot create protocol\n");
        return 1;
    }

    protocol_addMethodDescription(p, sel1, sig1, YES, YES);

    descr = protocol_getMethodDescription(p, sel1, YES, YES);
    if (descr.name == NULL) {
        printf("added selector 1 not found protocol (build phase)\n");
        return 1;
    }

    protocol_addMethodDescription(p, sel2, sig2, YES, YES);

    descr = protocol_getMethodDescription(p, sel2, YES, YES);
    if (descr.name == NULL) {
        printf("added selector 2 not found protocol (build phase)\n");
        return 1;
    }

    protocol_addMethodDescription(p, sel3, sig3, YES, YES);

    descr = protocol_getMethodDescription(p, sel3, YES, YES);
    if (descr.name == NULL) {
        printf("added selector 3 not found protocol (build phase)\n");
        return 1;
    }

    objc_registerProtocol(p);        

    descr = protocol_getMethodDescription(p, sel1, YES, YES);
    if (descr.name == NULL) {
        printf("added selector 1 not found protocol (registered phase)\n");
        return 1;
    }

    descr = protocol_getMethodDescription(p, sel2, YES, YES);
    if (descr.name == NULL) {
        printf("added selector 2 not found protocol (registered phase)\n");
        return 1;
    }

    descr = protocol_getMethodDescription(p, sel3, YES, YES);
    if (descr.name == NULL) {
        printf("added selector 3 not found protocol (registered phase)\n");
        return 1;
    }

    return 0;
}

@ronaldoussoren
Copy link
Owner Author

Developer forum post about this: https://developer.apple.com/forums/thread/724655 (at the time of this message this post is "in review").

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working wontfix This will not be worked on
Projects
None yet
Development

No branches or pull requests

1 participant