AdaCore / AdaCore/aws

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

Open
#18 2 comments 0 reactions 1 assignee View on GitHub

@TurboGit is already working on this.

Since Mar 25, 2018.

bug
Dominant language
Ada
Stars
162
Forks
45
PR merge metrics
No merged PRs in 30d

Description

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;

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.