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;