Skip to content

Exception AWS.NET.SOCKET_ERROR not handled correctly by Protocol_Handler => Fatal error slot N is dead now #18

Open
@stcarrez

Description

@stcarrez

On my server using AWS (GNAT 2017 version), I've seen from time to time the following exception:

Fatal error, slot 1 is dead now.

raised AWS.NET.SOCKET_ERROR : aws-server.adb:793
Call stack traceback locations:
0xb4c3e9 0xb4ca31 0xb4f1be 0xb4f9f5 0x105b2b1 0x7e98782ef6b8 0x7e987708d82b 0xfffffffffffffffe

The stack trace corresponds to:
0xb4c3e9 <aws__server__slots__mark_phaseN+297>
0xb4ca31 <aws__server__slots__mark_phaseP+49>
0xb4f1be <aws__server__protocol_handler+7758>
0xb4f9f5 <aws__server__lineTB+885>
0x105b2b1 <system__tasking__stages__task_wrapper+481>

This happens once every 2 or 3 months.
This is very close to the bug #2 I've reported few years ago but this is another exception.

The exception is raised by Slots.Mark_Phase called somewhere from Protocol_Handler.
The Protocol_Handler almost catch correctly the exception except in two cases.

1/ When it handles the 'Wrong_Request_Line' exception, is can call the Slots.Mark_Phase
and the execution is not protected against the AWS.NET.SOCKET_ERROR exception which can be raised (arround line 295):

         when E : Wrong_Request_Line =>
            AWS.Log.Write
              (LA.Server.Error_Log,
               LA.Stat,
               Utils.CRLF_2_Spaces
                 (Ada.Exceptions.Exception_Information (E)));

            Will_Close := True;

            Error_Answer := Response.Build
              (Status_Code  => Messages.S400,
               Content_Type => "text/plain",
               Message_Body => Ada.Exceptions.Exception_Message (E));

            LA.Server.Slots.Mark_Phase (LA.Line, Server_Response);

            exit For_Every_Request when not Send_Error_Answer;

2/ Likewise when it handles the Net.Buffered.Data_Overflow, Parameters.Too_Long_Parameter, Parameters.Too_Many_Parameters exceptions (arround lines 333).

         when E : Net.Buffered.Data_Overflow
           | Parameters.Too_Long_Parameter
           | Parameters.Too_Many_Parameters
           =>
            AWS.Log.Write
              (LA.Server.Error_Log,
               LA.Stat,
               Utils.CRLF_2_Spaces
                 (Ada.Exceptions.Exception_Information (E)));

            Will_Close := True;

            if First_Line then
               Error_Answer := Response.Build
                 (Status_Code  => Messages.S414,
                  Content_Type => "text/plain",
                  Message_Body => Ada.Exceptions.Exception_Message (E));

            elsif
              Exception_Identity (E) =
                Parameters.Too_Many_Parameters'Identity
            then
               Error_Answer := Response.Build
                 (Status_Code  => Messages.S403,
                  Content_Type => "text/plain",
                 Message_Body => Ada.Exceptions.Exception_Message (E));

            elsif
              Exception_Identity (E) =
                Parameters.Too_Many_Parameters'Identity
            then
               Error_Answer := Response.Build
                 (Status_Code  => Messages.S403,
                  Content_Type => "text/plain",
                  Message_Body => Ada.Exceptions.Exception_Message (E));

            else
               Error_Answer := Response.Build
                 (Status_Code  => Messages.S400,
                  Content_Type => "text/plain",
                  Message_Body => Ada.Exceptions.Exception_Message (E));
            end if;
              
            LA.Server.Slots.Mark_Phase (LA.Line, Server_Response);

            exit For_Every_Request when not Send_Error_Answer;

I would suggest to introduce the same protection that was made for other exceptions (arround lines 337):

         when E : others =>
            declare
               Phase : constant Slot_Phase := LA.Server.Slots.Phase (LA.Line);
            begin
...
            exception
               when Net.Socket_Error =>
                  --  There is nothing further we can do. The socket has
                  --  certainly been closed while sending back the answer.
                  exit For_Every_Request;
               when E : others =>
                  --  Here we got an exception (other than Net.Socket_Error).
                  --  It is probably due to a problem in a user's stream
                  --  implementation. Just log the problem and exit.
                  AWS.Log.Write
                    (LA.Server.Error_Log,
                     LA.Stat,
                     "Exception handler bug "
                     & Utils.CRLF_2_Spaces
                       (Ada.Exceptions.Exception_Information (E)));
                  exit For_Every_Request;
            end;
      end;

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions