Skip to content

Commit 4ea6d48

Browse files
committed
Fix WebSocket memory free to be thread safe.
Also skip WebSocket that have a deferred free status. For U504-028.
1 parent 9e5bad5 commit 4ea6d48

File tree

2 files changed

+54
-21
lines changed

2 files changed

+54
-21
lines changed

src/core/aws-net-websocket-registry.adb

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
------------------------------------------------------------------------------
22
-- Ada Web Server --
33
-- --
4-
-- Copyright (C) 2012-2019, AdaCore --
4+
-- Copyright (C) 2012-2021, AdaCore --
55
-- --
66
-- This library is free software; you can redistribute it and/or modify --
77
-- it under terms of the GNU General Public License as published by the --
@@ -161,10 +161,14 @@ package body AWS.Net.WebSocket.Registry is
161161
entry Get_Socket (WebSocket : out Object_Class);
162162
-- Get a WebSocket having some data to be sent
163163

164-
procedure Release_Socket (WebSocket : Object_Class);
164+
procedure Release_Socket (WebSocket : in out Object_Class);
165165
-- Release a socket retrieved with Get_Socket above, this socket will be
166166
-- then available again.
167167

168+
procedure Free (WebSocket : in out Object_Class);
169+
-- Free WebSocket immediately if not taken by another task, otherwise
170+
-- record it to be freed as soon as it is released.
171+
168172
entry Not_Empty;
169173
-- Returns if the Set is not empty
170174

@@ -329,7 +333,7 @@ package body AWS.Net.WebSocket.Registry is
329333

330334
procedure Do_Free (WebSocket : in out Object_Class) is
331335
begin
332-
Unchecked_Free (WebSocket);
336+
DB.Free (WebSocket);
333337
end Do_Free;
334338

335339
-----------------
@@ -442,7 +446,7 @@ package body AWS.Net.WebSocket.Registry is
442446
end;
443447

444448
WebSocket.Shutdown;
445-
Unchecked_Free (WebSocket);
449+
DB.Free (WebSocket);
446450
end if;
447451
end Close_To;
448452

@@ -499,7 +503,7 @@ package body AWS.Net.WebSocket.Registry is
499503
Socket.On_Close (Message);
500504
Socket.Shutdown;
501505

502-
Unchecked_Free (W);
506+
DB.Free (W);
503507
end Close;
504508

505509
----------------
@@ -516,9 +520,11 @@ package body AWS.Net.WebSocket.Registry is
516520
-- Add watched sockets
517521

518522
for Id of Watched loop
519-
FD_Set.Add
520-
(Result,
521-
Registered (Id).all, Registered (Id), FD_Set.Input);
523+
if not Registered (Id).To_Free then
524+
FD_Set.Add
525+
(Result,
526+
Registered (Id).all, Registered (Id), FD_Set.Input);
527+
end if;
522528
end loop;
523529
end return;
524530
end Create_Set;
@@ -555,7 +561,7 @@ package body AWS.Net.WebSocket.Registry is
555561
end;
556562

557563
WebSocket.Shutdown;
558-
Unchecked_Free (WebSocket);
564+
DB.Free (WebSocket);
559565
end On_Close;
560566

561567
begin
@@ -568,6 +574,24 @@ package body AWS.Net.WebSocket.Registry is
568574
Registered.Clear;
569575
end Finalize;
570576

577+
----------
578+
-- Free --
579+
----------
580+
581+
procedure Free (WebSocket : in out Object_Class) is
582+
begin
583+
-- If WebSocket is in Sending it means that it has been
584+
-- taken by the Get_Socket call. We cannot free it now, we
585+
-- record this socket to be freed as soon as it is released
586+
-- (Release_Socket) call.
587+
588+
if Sending.Contains (WebSocket.Id) then
589+
WebSocket.To_Free := True;
590+
else
591+
Unchecked_Free (WebSocket);
592+
end if;
593+
end Free;
594+
571595
----------------
572596
-- Get_Socket --
573597
----------------
@@ -738,10 +762,19 @@ package body AWS.Net.WebSocket.Registry is
738762
-- Release_Socket --
739763
--------------------
740764

741-
procedure Release_Socket (WebSocket : Object_Class) is
765+
procedure Release_Socket (WebSocket : in out Object_Class) is
742766
begin
743767
Sending.Exclude (WebSocket.Id);
744-
New_Pending := True;
768+
769+
-- The socket has been recorded to be freed. It is not anymore
770+
-- in the registry, we just need to free it now that it has
771+
-- been released.
772+
773+
if WebSocket.To_Free then
774+
Unchecked_Free (WebSocket);
775+
else
776+
New_Pending := True;
777+
end if;
745778
end Release_Socket;
746779

747780
------------
@@ -869,15 +902,15 @@ package body AWS.Net.WebSocket.Registry is
869902
begin
870903
if Error = null then
871904
DB.Unregister (W);
872-
Unchecked_Free (W);
905+
DB.Free (W);
873906

874907
else
875908
Error (W.all, A);
876909

877910
case A is
878911
when Close =>
879912
DB.Unregister (W);
880-
Unchecked_Free (W);
913+
DB.Free (W);
881914
when None =>
882915
null;
883916
end case;
@@ -931,9 +964,7 @@ package body AWS.Net.WebSocket.Registry is
931964
WS.Close (Exception_Message (E), Going_Away);
932965
WS.On_Close (Exception_Message (E));
933966

934-
-- ??? if we free it now, there might be a reader
935-
-- in parallel that is using this socket...
936-
Unchecked_Free (WS);
967+
DB.Free (WS);
937968

938969
-- No more data to send from this socket
939970
Pending := 0;
@@ -996,7 +1027,7 @@ package body AWS.Net.WebSocket.Registry is
9961027
WebSocket.Close (Exception_Message (E), Going_Away);
9971028

9981029
-- Do not free, it might be used by another
999-
Unchecked_Free (WebSocket);
1030+
Free (WebSocket);
10001031
end;
10011032

10021033
else
@@ -1267,7 +1298,7 @@ package body AWS.Net.WebSocket.Registry is
12671298
DB.Unregister (WS);
12681299
WebSocket_Exception
12691300
(WS, Exception_Message (E), Protocol_Error);
1270-
Unchecked_Free (WS);
1301+
DB.Free (WS);
12711302
-- No more data to send from this socket
12721303
Pending := 0;
12731304
end Read_Send;
@@ -1539,7 +1570,7 @@ package body AWS.Net.WebSocket.Registry is
15391570
DB.Watch (WebSocket);
15401571
exception
15411572
when others =>
1542-
Unchecked_Free (WebSocket);
1573+
DB.Free (WebSocket);
15431574
raise;
15441575
end Watch;
15451576

src/core/aws-net-websocket.ads

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
------------------------------------------------------------------------------
22
-- Ada Web Server --
33
-- --
4-
-- Copyright (C) 2012-2020, AdaCore --
4+
-- Copyright (C) 2012-2021, AdaCore --
55
-- --
66
-- This library is free software; you can redistribute it and/or modify --
77
-- it under terms of the GNU General Public License as published by the --
@@ -289,6 +289,7 @@ private
289289
Messages : Message_List.List;
290290
Mem_Sock : Net.Socket_Access;
291291
In_Mem : Boolean := False;
292+
To_Free : Boolean := False;
292293

293294
Connection : AWS.Client.HTTP_Connection_Access;
294295
-- Only set when the web socket is initialized as a client.
@@ -366,7 +367,8 @@ private
366367
Messages => Message_List.Empty_List,
367368
Mem_Sock => null,
368369
Connection => null,
369-
In_Mem => False);
370+
In_Mem => False,
371+
To_Free => False);
370372

371373
-- Error codes corresponding to all errors
372374

0 commit comments

Comments
 (0)