You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
CLUBB advected-moments read loop runs one level past state%q (out-of-bounds) in clubb_intr.F90 #1590
With clubb_do_adv = .true., the loop that reads the 9 advected CLUBB moments out of state%q runs one level too far, reading past the end of state%q and writing past the end of a nzt_clubb-sized pbuf field.
Location
src/physics/cam/clubb_intr.F90:3098-3111 (registrations at line 633; writeback at 4284-4314)
Problem
The read loop runs k = 1, nzm_clubb, so k_cam reaches pverp, but state%q has only pver levels — an out-of-bounds read for all nine moments. It is also an out-of-bounds write for wp3_pbuf, which is registered with only nzt_clubb levels, corrupting the adjacent pbuf field. The corresponding writeback loop covers only nzt_clubb levels, confirming the read-loop bound is the one that is wrong.
Impact
Garbage surface-level turbulence moments entering CLUBB each substep, plus corruption of a neighboring physics-buffer field, whenever CLUBB moment advection is enabled. Affects prognostic state.
Suggested fix
do k =1, nzt_clubb
Found via a systematic line-by-line scientific code review of src/physics/cam/ at commit 21a78294 (≈cam6_4_180), cross-checked against the registration and writeback bounds. This is a candidate bug identified by code inspection; it has not yet been confirmed by a model run. An issue-tracker search on 2026-06-11 found no existing report.
Here is the other CLUBB-related issue @vlarson, @bstephens82 . It does look like there is an index error here, which would likely result in the model crashing if certain compiler debug flags were enabled, so I am happy to fix it if you concur it's a bug.
For anyone else seeing this issue, please note that clubb_do_adv defaults to .false. in standard CAM runs, so this bug should have no impact on CESM3 simulations.
Finally, a note to self that clubb_do_adv and other namelist logical variables should probably be initialized to .false. in the Fortran declaration, which could protect us against theoretical namelist errors.
@cacraigucar I'll take care of this in my PR as Adam recommends. I'll add the proper text to the summary. @adamrher the loop in question is below. I agree that the fix is to run the k loop to nzt_clubb to make the unpacking and packing of the pbuf values in the q array consistent. The surface level of the pbuf variables shouldn't be advected anyway so it make sense not to push it into the q array. I just wanted to check with you that the surface layer of these variables is being initialized and updated properly as the pverp values are used in calculations in other parts of clubb.
if ( clubb_do_adv ) then
if (macmic_it == 1) then
! Note that some of the moments below can be positive or negative.
! Remove a constant that was added to prevent dynamics from clipping
! them to prevent dynamics from making them positive.
do k = 1, nzm_clubb
do i = 1, ncol
k_cam = top_lev - 1 + k
rtpthlp_pbuf(i,k) = state_loc%q(i,k_cam,ixrtpthlp) - ( rtpthlp_const * apply_const )
wpthlp_pbuf(i,k) = state_loc%q(i,k_cam, ixwpthlp) - ( wpthlp_const * apply_const )
wprtp_pbuf(i,k) = state_loc%q(i,k_cam, ixwprtp) - ( wprtp_const * apply_const )
wp3_pbuf(i,k) = state_loc%q(i,k_cam, ixwp3) - ( wp3_const * apply_const )
wp2_pbuf(i,k) = max( w_tol_sqd, state_loc%q(i,k_cam, ixwp2) )
thlp2_pbuf(i,k) = max( thl_tol**2, state_loc%q(i,k_cam, ixthlp2) )
rtp2_pbuf(i,k) = max( rt_tol**2, state_loc%q(i,k_cam, ixrtp2) )
up2_pbuf(i,k) = max( w_tol_sqd, state_loc%q(i,k_cam, ixup2) )
vp2_pbuf(i,k) = max( w_tol_sqd, state_loc%q(i,k_cam, ixvp2) )
enddo
enddo
endif
I agree with you John. The only variable that's on the zt grid is wp3, and all others are on the zm grid. Cross-referencing with an older code base, we have always been assigning the zm pbuf variables under the clubb_do_adv blocks with the state%q array, a half level lower from where the zm variables actually reside (and omitting the surface values).
Activity
nusbaume commentedon Jun 17, 2026
Here is the other CLUBB-related issue @vlarson, @bstephens82 . It does look like there is an index error here, which would likely result in the model crashing if certain compiler debug flags were enabled, so I am happy to fix it if you concur it's a bug.
For anyone else seeing this issue, please note that
clubb_do_advdefaults to.false.in standard CAM runs, so this bug should have no impact on CESM3 simulations.Finally, a note to self that
clubb_do_advand other namelist logical variables should probably be initialized to.false.in the Fortran declaration, which could protect us against theoretical namelist errors.cacraigucar commentedon Aug 11, 2026
@jtruesdal - has this been fixed?
jtruesdal commentedon Aug 11, 2026
@cacraigucar I'll take care of this in my PR as Adam recommends. I'll add the proper text to the summary. @adamrher the loop in question is below. I agree that the fix is to run the k loop to nzt_clubb to make the unpacking and packing of the pbuf values in the q array consistent. The surface level of the pbuf variables shouldn't be advected anyway so it make sense not to push it into the q array. I just wanted to check with you that the surface layer of these variables is being initialized and updated properly as the pverp values are used in calculations in other parts of clubb.
adamrher commentedon Aug 11, 2026
I agree with you John. The only variable that's on the zt grid is wp3, and all others are on the zm grid. Cross-referencing with an older code base, we have always been assigning the zm pbuf variables under the clubb_do_adv blocks with the state%q array, a half level lower from where the zm variables actually reside (and omitting the surface values).
cacraigucar commentedon Sep 29, 2026
@jtruesdal - is this in your CLUBB_MF PR?
jtruesdal commentedon Oct 7, 2026
Add the new loop index as well as initializing the clubb logicals to false as recommended by Jesse to my clubb-mf PR #1576
Merge pull request #1576 from jtruesdal/clubbdev