Skip to content

Deallocate all @:ALLOCATEd arrays at finalization (and enforce pairing via lint) #1459

@sbryngelson

Description

@sbryngelson

Summary

A heuristic scan of src/**/*.fpp finds that 64 of 223 distinct @:ALLOCATEd array names (~29%) are never @:DEALLOCATEd anywhere in the source tree. This contradicts the documented convention — "Every @:ALLOCATE(...) MUST have a matching @:DEALLOCATE(...) in finalization" — and currently makes it impossible to statically enforce allocate/deallocate pairing.

Why it matters

  • Clean shutdown / leak tooling. Program-exit leaks add noise under valgrind / compute-sanitizer / GPU memory tools, masking real leaks.
  • GPU memory hygiene. @:DEALLOCATE also emits GPU_EXIT_DATA(delete=...); skipping it leaves device allocations live until process teardown.
  • Unblocks a static lint. A lint_source.py check for an @:ALLOCATE with no matching @:DEALLOCATE is impossible today — it would flag these 64 as false positives. Once everything is paired (or explicitly exempted), a precheck lint could catch a forgotten deallocation in milliseconds instead of via review or a GPU run. This is exactly the class of bug that is otherwise invisible locally.

Methodology / caveat

Names were extracted by regex from @:ALLOCATE(...) / @:DEALLOCATE(...) calls (base identifier, %-members kept, &-continuations joined), then set-differenced across all of src. This is approximate — some entries may already be freed via a containing object (e.g. a vector_field's component fields), reallocated in place, or be intentionally program-lifetime. Each should be either deallocated in the relevant s_finalize_*_module or explicitly documented as exempt.

Per-file breakdown (allocated here, deallocated nowhere in src)

  • src/common/m_boundary_common.fpp: bc_buffers
  • src/common/m_helper.fpp: Re_trans_T, pb0, weight
  • src/common/m_model.fpp: gpu_boundary_edge_count, gpu_boundary_v, gpu_ntrs, gpu_total_vertices, gpu_trs_n, gpu_trs_v
  • src/common/m_mpi_common.fpp: buff_send
  • src/common/m_variables_conversion.fpp: Res_vc
  • src/post_process/m_start_up.fpp: En, En_real, data_cmplx, data_cmplx_y, data_cmplx_z, data_in, data_out
  • src/simulation/m_acoustic_src.fpp: E_src, loc_acoustic, mass_src, mom_src, source_spatials, source_spatials_num_points
  • src/simulation/m_bubbles_EE.fpp: bub_adv_src, bub_m_src, bub_p_src, bub_r_src, bub_v_src, divu%sf, ms, ps, rs, vs
  • src/simulation/m_derived_variables.fpp: accel_mag, fd_coeff_x, fd_coeff_y, fd_coeff_z, x_accel, y_accel, z_accel
  • src/simulation/m_global_parameters.fpp: ptil
  • src/simulation/m_hyperelastic.fpp: Gs_hyper
  • src/simulation/m_ibm.fpp: ghost_points, models
  • src/simulation/m_qbmm.fpp: bubmoms, momrhs
  • src/simulation/m_rhs.fpp: alf_sum%sf, blkmod1, mom_3d, mom_sp, qL_prim, qR_prim
  • src/simulation/m_riemann_solvers.fpp: Gs_rs, Res_gs
  • src/simulation/m_time_steppers.fpp: bc_type, max_dt, mv_ts, pb_ts, q_T_sf%sf, rhs_mv, rhs_pb, rk_coef

Proposed resolution

  1. Audit each name above: add a matching @:DEALLOCATE in the module's s_finalize_*_module (conditional allocation → conditional deallocation), or annotate the genuine program-lifetime exceptions.
  2. Add a lint_source.py check that flags an @:ALLOCATEd name with no corresponding @:DEALLOCATE, wired into precheck, so the invariant can't regress.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions