grpc/grpc-swift

Responder calling Finish method causing ABORT SIGNAL inside c++ lambda function

palfonsoilluscio opened this issue · 2 comments

Describe the bug

We are implementing sort of a async/event-driven communication feature using a RPC method which a client can call in order to set some custom event related property on the server. Every time this event property changes, the pre register listeners (other clients) will receive a callback with a certain value. The listeners will be executing a specific code in their respective lambda functions once all above happens, now inside that lambda function, we are executing the responder_.Finish method (ServerAsyncResponseWriter) which will terminate the corresponding unary call for that listener. The problem is when the Finish method is executed inside the lambda function, it causes a SIGABRT exception when the size of the message is being calculated in the serialization logic.

Please have screen shoot:
Screenshot 2023-10-05 at 12 27 06 PM

Our server is in C++ and we are using Swift 5.5 grcp-swift package 1.19.1 and Protobuf 1.24.0. This happens in both build modes debug and release).

To reproduce

Steps to reproduce the bug you've found:

  1. Try to call Finish method inside lambda function in c++ for a GRPCAsyncUnary call.

Expected behaviour

The call to Finish should be successful and should not cause a SIGABRT exception.

Additional information

Please have the code snippet which contains the class implementing the lambda function:

class SubscribeToAssetsEvents : public RequestBase {
        public:

        SubscribeToAssetsEvents( AsyncAssetStreamerManager& owner ) : RequestBase( owner ), ownerClass( owner ) {
            owner_.grpc().service_.Requesthola(
                &context_, &request_, &responder_, cq(), cq(), handle_.tag( Handle::Operation::CONNECT, [this, &owner]( bool ok, Handle::Operation /* op */ ) {
                    LOG_DEBUG << "\n" + me( *this ) << "\n\n*****************************************************************\n"
                              << "- Processing a new connect from " << context_.peer()
                              << "\n*****************************************************************\n"
                              << endl;
                    cout << "\n" + me( *this ) << "\n\n*****************************************************************\n"
                              << "- Processing a new connect from " << context_.peer()
                              << "\n*****************************************************************\n"
                              << endl;

                    if ( !ok ) [[unlikely]] {
                        LOG_DEBUG << "The CONNECT request-operation failed. Assuming we are shutting down" << endl;
                        cout << "The CONNECT request-operation failed. Assuming we are shutting down" << endl;
                        return;
                    }

                    // Creates a new instance so the service can handle requests from a new client
                    owner_.createNew<SubscribeToAssetsEvents>( owner );
                    // Starts the process
                    registerSubscriptions();
                } ) );
        }

        private:

        // Objects and variables
        AsyncAssetStreamerManager& ownerClass;
        ::grpc::ServerContext context_;
        ::Illuscio::SubscriptionRequest request_;
        ::Illuscio::SubscriptionResponse reply_;
        ::grpc::ServerAsyncResponseWriter<decltype( reply_ )> responder_ { &context_ };

        vector<Illuscio::ASSET_EVTS> subscription_request_events;
        
        Handle handle_ { *this };


        // Methods

        void registerSubscriptions() {
            // Assigns the requests' events elements to a local vector
            vector<string> subscription_request_events( request_.events().begin(), request_.events().end() );
        
            reply_.set_event_( "GET" );
            reply_.set_url_( "assetURL" );

            if ( !subscription_request_events.empty() ) {
                ownerClass.watcher.AddPropertyChangedListener( [this](AssetEventInfo value) {
                    responder_.Finish(reply_, grpc::Status::OK, handle_.tag( Handle::Operation::FINISH, [this]( bool ok, Handle::Operation /* op */ ) {
                        if ( !ok ) [[unlikely]] {
                            LOG_DEBUG << "The FINISH aqui es request-operation failed." << endl;
                            cout << "The FINISH aqui es request-operation failed." << endl;
                            return;
                        } 

                        request_.Clear();
                    }));
                });

                LOG_DEBUG << "Events' subscriptions were successful." << endl;
                cout << "Events' subscriptions were successful." << endl;
            } else {
                LOG_DEBUG << "Events' subscription registration failed, since there are no events to subscribe to." << endl;
                cout << "Events' subscription registration failed, since there are no events to subscribe to." << endl;
            }
        }
    };

We have tried changing the capture list using value and references without success, also putting the same logic outside the lambda function works fine. Hopefully we are missing something...

Lukasa commented

I’m afraid we can’t support the C++ implementation of grpc. Can I please suggest filing the bug upstream?

Makes total sense, thank you. We will...