https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127756
Bug ID: 127756
Summary: constrained protected subtype deallocation omits
protected-object finalization
Product: gcc
Version: 16.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: ada
Assignee: unassigned at gcc dot gnu.org
Reporter: hodong at nimfsoft dot com
CC: dkm at gcc dot gnu.org
Target Milestone: ---
Created attachment 65768
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65768&action=edit
Standalone Ada reproducer for constrained protected subtype cleanup
Environment
-----------
Host: FreeBSD 15.1 amd64
Compiler: GCC/GNAT 16.2.0
Target: x86_64-portbld-freebsd15.1
Runtime: POSIX/pthread GNAT tasking runtime
Files
-----
protected_subtype_cleanup.adb
gnat-protected-subtype-reproducer.c
The Ada reproducer declares a discriminated protected type with
Lock_Free => False, creates a constrained subtype, allocates 10,000 objects of
that subtype, and deallocates them with Ada.Unchecked_Deallocation.
The C helper uses GNU ld --wrap to count successful pthread_mutex_init and
pthread_mutex_destroy calls during the measured loop.
Build and run
-------------
cc -std=c11 -O2 -Wall -Wextra -Werror \
-c gnat-protected-subtype-reproducer.c -o mutex-counts.o
gnatmake16 -q -f -gnat2022 -O2 protected_subtype_cleanup.adb \
-o protected_subtype_cleanup \
-largs mutex-counts.o \
-Wl,--wrap=pthread_mutex_init \
-Wl,--wrap=pthread_mutex_destroy
./protected_subtype_cleanup
With the affected GCC/GNAT 16.2.0 build, the output was:
FAIL: initialized=10000 destroyed=0 errors=0 expected=10000
With a locally corrected GCC/GNAT 16.2.0 build, the output was:
PASS: initialized=10000 destroyed=10000 errors=0 expected=10000
The corrected compiler was also tested with the same reproducer at -O0 and
-O2; both runs produced 10,000 successful initializations and 10,000
successful destructions.
Generated cleanup
-----------------
The generated Ada can be inspected with:
gcc16 -c -gnat2022 -gnatG protected_subtype_cleanup.adb \
> expanded.txt 2>&1
grep -i 'initialize_protection\|finalize_protection' expanded.txt
In the affected build used for the reduction, Initialize_Protection was present
and Finalize_Protection was absent on the constrained-subtype deallocation
path.
With the locally corrected compiler, both calls are present. The deallocation
path contains a Finalize_Protection call for the generated _object field before
the object is freed.
Compiler source
---------------
The relevant GCC 16.2.0 code is Is_Simple_Protected_Type in
gcc/ada/exp_ch7.adb:
function Is_Simple_Protected_Type (T : Entity_Id) return Boolean is
begin
return
Is_Protected_Type (T)
and then not Uses_Lock_Free (T)
and then not Has_Entries (T)
and then Is_RTE (Find_Protection_Type (T), RE_Protection);
end Is_Simple_Protected_Type;
On the failing deallocation path, T is a constrained protected subtype. In the
locally corrected compiler used for comparison, the queried type is normalized
with Base_Type (T), and the protected-object representation checks are
performed
on that base type.
AI assistance disclosure
------------------------
This report and the standalone reproducer were prepared with assistance from
OpenAI ChatGPT (GPT-5.6 Sol, xhigh). All commands and reported results were
verified on the system described above.