Skip to content

Commit 9c819d4

Browse files
committed
fix: complete deallocate audit for m_ibm and add lint check
- m_ibm: add @:DEALLOCATE for ghost_points, simplify models deallocation, replace plain deallocate for recv_* arrays - lint_source.py: add check_allocate_deallocate_pairing() to flag @:ALLOCATE without matching @:DEALLOCATE anywhere in src/ Known program-lifetime exemptions are listed explicitly Closes #1459
1 parent 5255b3c commit 9c819d4

2 files changed

Lines changed: 141 additions & 9 deletions

File tree

src/simulation/m_ibm.fpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,21 +1542,17 @@ contains
15421542
@:DEALLOCATE(ib_airfoil_grids(i)%lower)
15431543
end if
15441544
end do
1545-
15461545
if (allocated(models)) then
1547-
if (size(models) > 0) then
1548-
@:DEALLOCATE(models)
1549-
else
1550-
deallocate (models)
1551-
end if
1546+
@:DEALLOCATE(models)
1547+
end if
1548+
if (allocated(ghost_points)) then
1549+
@:DEALLOCATE(ghost_points)
15521550
end if
1553-
15541551
if (collision_model > 0) call s_finalize_collisions_module()
1555-
15561552
#ifdef MFC_MPI
15571553
if (num_procs > 1) then
15581554
@:DEALLOCATE(send_ids, send_ft)
1559-
deallocate (recv_forces_snap, recv_torques_snap, recv_ids, recv_ft)
1555+
@:DEALLOCATE(recv_forces_snap, recv_torques_snap, recv_ids, recv_ft)
15601556
end if
15611557
#endif
15621558

toolchain/mfc/lint_source.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,141 @@ def check_junk_comments(repo_root: Path) -> list[str]:
309309
return errors
310310

311311

312+
def check_allocate_deallocate_pairing(repo_root: Path) -> list[str]:
313+
"""Flag @:ALLOCATE'd array names with no matching @:DEALLOCATE anywhere in src/.
314+
315+
Every @:ALLOCATE must have a matching @:DEALLOCATE so that GPU device
316+
memory is properly released alongside host memory.
317+
"""
318+
errors: list[str] = []
319+
src_dir = repo_root / SRC_DIR
320+
321+
# Known program-lifetime allocations with no finalize subroutine
322+
PROGRAM_LIFETIME_EXEMPTIONS = {
323+
# m_helper
324+
"weight",
325+
"pb0",
326+
"Re_trans_T",
327+
# m_model
328+
"gpu_ntrs",
329+
"gpu_trs_v",
330+
"gpu_trs_n",
331+
"gpu_boundary_edge_count",
332+
"gpu_total_vertices",
333+
"gpu_boundary_v",
334+
# m_variables_conversion
335+
"gs_min",
336+
"pi_infs",
337+
"ps_inf",
338+
"cvs",
339+
"qvs",
340+
"qvps",
341+
"Gs_vc",
342+
# m_start_up post_process
343+
"data_in",
344+
"data_out",
345+
"data_cmplx",
346+
"data_cmplx_y",
347+
"data_cmplx_z",
348+
"En_real",
349+
"En",
350+
# m_acoustic_src
351+
"loc_acoustic",
352+
"mass_src",
353+
"mom_src",
354+
"E_src",
355+
"source_spatials_num_points",
356+
"source_spatials",
357+
# m_bubbles_EE
358+
"bub_adv_src",
359+
"bub_r_src",
360+
"bub_v_src",
361+
"bub_p_src",
362+
"bub_m_src",
363+
"divu",
364+
"ms",
365+
"ps",
366+
"rs",
367+
"vs",
368+
# m_qbmm
369+
"bubmoms",
370+
"momrhs",
371+
# m_cbc
372+
"F_src_rsx_vf",
373+
"flux_src_rsx_vf_l",
374+
"F_src_rsy_vf",
375+
"flux_src_rsy_vf_l",
376+
"F_src_rsz_vf",
377+
"flux_src_rsz_vf_l",
378+
"pres_in",
379+
"Del_in",
380+
"alpha_rho_in",
381+
# m_data_output
382+
"Rc_sf",
383+
# m_fftw
384+
"data_cmplx_gpu",
385+
"data_fltr_cmplx_gpu",
386+
# m_global_parameters
387+
"qbmm_idx",
388+
"x_cc",
389+
"dx",
390+
"y_cc",
391+
"dy",
392+
"z_cc",
393+
"dz",
394+
# m_hypoelastic
395+
"dw_dx_hypo",
396+
# m_igr
397+
"coeff_R",
398+
# m_rhs
399+
"qR_rsx_vf",
400+
"dqR_rsx_vf",
401+
# m_surface_tension
402+
"gR_x",
403+
# m_time_steppers
404+
"q_prim_ts2",
405+
# m_weno
406+
"poly_coef_cbR_x",
407+
"d_cbR_x",
408+
"poly_coef_cbR_y",
409+
"d_cbR_y",
410+
"poly_coef_cbR_z",
411+
"d_cbR_z",
412+
"divu%sf",
413+
"qbmm_idx%ps",
414+
}
415+
416+
allocate_re = re.compile(r"@:ALLOCATE\((\w[\w%]*)")
417+
deallocate_re = re.compile(r"@:DEALLOCATE\((\w[\w%]*)")
418+
419+
# Collect all deallocated names across all files
420+
deallocated: set[str] = set()
421+
for src in _fortran_fpp_files(src_dir):
422+
text = src.read_text(encoding="utf-8")
423+
for match in deallocate_re.finditer(text):
424+
deallocated.add(match.group(1))
425+
426+
# Check each allocation against the global deallocated set
427+
for src in _fortran_fpp_files(src_dir):
428+
lines = src.read_text(encoding="utf-8").splitlines()
429+
rel = src.relative_to(repo_root)
430+
for i, line in enumerate(lines):
431+
stripped = line.strip()
432+
if _is_comment_or_blank(stripped):
433+
continue
434+
match = allocate_re.search(stripped)
435+
if match:
436+
name = match.group(1)
437+
if name not in deallocated and name not in PROGRAM_LIFETIME_EXEMPTIONS:
438+
errors.append(
439+
f" {rel}:{i + 1} @:ALLOCATE({name}...) has no matching "
440+
f"@:DEALLOCATE anywhere in src/. Fix: add @:DEALLOCATE in "
441+
f"the module's s_finalize_* subroutine or annotate as program-lifetime"
442+
)
443+
444+
return errors
445+
446+
312447
def main():
313448
repo_root = Path(__file__).resolve().parents[2]
314449

@@ -321,6 +456,7 @@ def main():
321456
all_errors.extend(check_fypp_list_duplicates(repo_root))
322457
all_errors.extend(check_duplicate_lines(repo_root))
323458
all_errors.extend(check_hardcoded_byte_size(repo_root))
459+
all_errors.extend(check_allocate_deallocate_pairing(repo_root))
324460

325461
if all_errors:
326462
print("Source lint failed:")

0 commit comments

Comments
 (0)