Skip to content

Fix memory management issues in assignment#434

Merged
ltaylor16 merged 97 commits intodevelopfrom
fix-shared-gcc13
Oct 25, 2025
Merged

Fix memory management issues in assignment#434
ltaylor16 merged 97 commits intodevelopfrom
fix-shared-gcc13

Conversation

@ltaylor16
Copy link
Copy Markdown
Member

The shared.yaml test used final to clean up memory as part of assignment. gcc13 made the compiler more standard compliant causing the test to fail. Copied the technique used by swig-fortran which overloads assignment for each shadow type. It is responsible for releasing the temporary object created by a function call as part of the assignment: obj = object(). object() creates a object which is then assigned to obj and must then be released.

This also fixes issues with double free when creating an alias for an object. Tested in classes.yaml.

Add cmemflags to the capsule fields. The SWIG_MEM_OWN flag works similar to the older idtor flag to indicate if the memory needs to be released. idtor=0 do not release.

Add options.default_owner=library. Used in looking up statement name already, but is now computed in metaattr.py. This changes lots of statement groups to from pointer to pointer_library or pointer_caller. This explicitly indicates who is responsible to release the memory. Likewise with raw.

shared_ptr is no longer an extends from their object. They are now individual classes. This was needed to help assignment overload avoid ambigious arguments.

Move capsule destructor code into new file fcmem.py.

A runnable example derived from the paper by Rousonm, Morris and Xia.
4.0.2 to 4.2.0

Update Makefile for changes to regression/run/defaults.mk
Need to call dtor explicitly to release memory.
FINAL clause is not hooked up.
Mostly removed in d6abf1d

This code is only used with options.F_auto_reference_count which is
not documented. This change avoids an error about F_derived_ptr not
existing so I can move on to making auto_reference_count work.
Used to understand what swig-fortran is doing with shared pointers.
Allow intent(operator) in statement names.

Start work to allow different forms of assignment overload to allow
the swig-fortran system to be used.  Use option.F_assignment_api to
control how to define assignment overload.
This will allow it to be used to construct the name of a helper or
other similar uses.
New name is f_helper_capsule_data_basic.  The trailing 'helper' was
redundant. The new suffix is from option.F_assignment_api.
Changes comments in the generated source and JSON files.

Replace value 'none' with 'basic' for option.F_assignment_api.
It's used with the capsule data type and not just assignment api.
Add the statement name to the message.
Add options.F_capsule_variants to list capsule variants.  Have a
format template for each variant.  These names are used in the helpers
which are evaluated outside the context of a class.

Set fmt.F_capsule_data_type from one of the variants based on
F_assignment_api.  This allows fortran statements to be used with any
variant.

Remove fmt.option_F_assignment_api. Unused in the current scheme.
Similar to F_capsule_data_type.
Continued from cb68687

This allows some C helpers from h_helper_capsule_data_swig to be add C
code. Before only the Fortran code was being added.
Easier to grep for fcn_helpers.
It was mixed between upper and lower.

This helpers shared.yaml properly set capsue_data_type when using
option.F_assignment_api=swig. Otherwise, only Object used swig and not
std::shard and std::weak_ptr.
Different compilers require different code.
gcc and ifx generate the same output.

Add using statement to shared/maincpp.cpp.
This is similar to the generated Fortran derived types.
Add assignment operators for each type (shared and weak)
This now runs the same on ibm xlf and cray ftn as it does with gfortran.
Make the rhs argument a type instead of a class to avoid ambiguous
overload.

shared/testmod.f - Move routines to interface assignment(=) block
instead of in type contains section. Do not add PROCEDURE statements
in the type since the routines are never called directly.
Used to overload assignment operators instead of adding as type bound
procedures.

Rename FStmts.f_operator as f_operator_body.
The assignment overloads will be associated with the Library and not
each individual class.  This would also be necessary for shared_ptr to
a POD.

Write out in todict.py.
Update reference for new test error-fmt.
Add methods for smart pointers after all of the subclasses are
created. This will allow one subclass to reference another.
ex. shared_ptr and weak_ptr.
It is a list of AssignOperator instances.
To be used to create assignment functions.
Instead of creating an additional class method
(GenFunctions.add_weak_smart_methods), create assignment overload
function with arguments (lhs, rhs). The code is controlled by
statements in fc-statements.  A single interface assignment(=) block
is created instead of adding as a type bound procedure.  This may help
with things like std::shared_ptr<int> instead of requiring class for
the template argument. Also similar to how operator(.eq.) and
operator(.ne.)  are implemented.

    interface assignment (=)
        module procedure object_weak_assign_Object_shared
    end interface

fmt.idtor is not yet being set so memory will leak.
BindArg contains fmtdict and meta.
This will allow bind to be used with find_idtor.
From wrapc.py. Used to create destructors for C++.
This allows find_idtor to be called from fcfmt.fmt_assignment.
Keeps destructor code in a single file.
This properly sets the idtor field for shared pointers.  Note that the
shared pointer case is first while it was last before due to the order
of calling find_idtor changing.
This will allow the mixins to be used with other specalized groups.
Only a Fortran statement group is needed which also contains C code.
Worry about calling assignments from C later.
Do not create overloads where options.wrap_fortran is false.

Dump assign_operators into the JSON for NamespaceNodes resulting in
JSON file changes.
Only the LibraryNode were being used, but
NamespaceNode.assign_operators is now used.
Caught with preprocess.yaml test.
It was not compiled before. It now has assignment overload code which
is needed. Several other tests have already had similar fixes. Using
F_assignment_api=swig now works for all tests.
Remove _swig from group names in fc-statements.json.
In directory regression/other/swig-fortran add ownership (from
ownership.yaml) and manual (example from the swig 4.2 manual to save
the output).
Prepare to use option.default_owner.
The default will be different for function and arguments
since it is based on intent.
Still compute the shared owner, it is used by Python.
But allow a place to compute owner for Fortran since owner
must be computed after inout.
Check conditions in set_func_owner_fortran and use
option.owner_default if appropriate.  To be used to set
capsule.cmemflags bit for SWIG_MEM_OWN.

By setting the owner metaattribute, the JSON files will change.  This
also changes the statement name which changes comments in the
generated code. pointer_owner is now the standard.

Add a default destructor for language=c.
Used with struct-c to delete struct-as-class constructor.
Check conditions in set_arg_owner_fortran and use
option.owner_default if appropriate.  To be used to set
capsule.cmemflags bit for SWIG_MEM_OWN.

By setting the owner metaattribute, the JSON files will change.  This
also changes the statement name which changes comments in the
generated code. The statement name pointer_owner is now the standard.
i.e. A pointer must also contain ownership attribute.
Default fmt fields as owner=library.
If owner=call, then set to include SWIG_MEM_OWN bit.
The statment group is allocating some local memory which must be
destroyed.  The user never sees this memory.

Remove fcmem.default_owner. Replaced with options.default_owner.  The
fcmem variable could not be controlled by the user.
Shroud allocates memory to hold the C++ library's return value.
The Fortran caller must explicitly delete it.
return-by-value std::string +deref(pointer) is owner=caller since the
wrapper creates a new object.

getter does not set owner since it points to memory in a class/struct.
Contains a demonstration of the changes between gcc12 and gcc13 which
broke the shared.yaml test. It used the final procedure which is now
correctly called after an assignment.

From Modern Fortran explained incorporating Fortran 2023 page 318:
When a finalizable object is about to cease to exist [as] the variable
on the left-hand side of an intrinsic assignment statement.  The final
subroutine is invoked after the expression right-hand side has been
evaluated, but before it is assigned to the variable.
When there is no user supplied construct, the Cray CCE compiler
reported a warning:

/regression/run/struct/main.f, Line = 238, Column = 14
Missing component data value for component "CXXMEM" of TYPE("CSTRUCT_AS_CLASS2").

Always add the default value:
    type cstruct_as_class
        type(STR_SHROUD_capsule_data) :: cxxmem = STR_SHROUD_capsule_data()
    end type cstruct_as_class
Test struct.yaml for both struct-c and struct-cxx report
[test_struct_class2]:Expected [T], Got [F];
   User message: [name_ptr associated with name_cat]
Update run/classes/main.f to test. This produces a segfault with
F_assignment_api=basic because of a double free.
Both the original and the alias try to free.

    ! Test generic constructor. Allocates new memory.
    obj0 = class1()
    ! Create alias
    obj1 = obj0
    call obj1%delete  ! The alias does not release the memory
    call obj0%delete

Test getClass1Copy with swig-fortran. Also renamed from getClassCopy
to identify more specifically what it's doing.
Test the getters to demonstrate that the classes are an alias.
Fix address sanitier error in clibrary.cxx by adding +owner(caller) to
Function4a. Also needed to add statement group
f_function_char*_buf_copy_caller.  Note that the Python wrapper still
needs to free the memory.

Add make varaibles to simplify testing
  valgrind=valgrind
  use_asan=1
This fixes the double free error in the classes.yaml test 'basic' is
still an option, but should go away before next release.
Error install gcc 15.
@ltaylor16 ltaylor16 merged commit 7b015e5 into develop Oct 25, 2025
3 checks passed
@ltaylor16 ltaylor16 deleted the fix-shared-gcc13 branch November 7, 2025 21:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant