Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suspected memory corruption in test_transform_normalize_array_shape_and_access #352

Open
reuterbal opened this issue Jul 27, 2024 · 0 comments
Labels
bug Something isn't working

Comments

@reuterbal
Copy link
Collaborator

On MacOS, the following test fails with a variety of errors:

def test_transform_normalize_array_shape_and_access(tmp_path, frontend, start_index):
"""
Test normalization of array shape and access, thus changing arrays with start
index different than "1" to have start index "1".
E.g., ``x1(5:len)`` -> ```x1(1:len-4)``
"""
fcode = f"""
module norm_arr_shape_access_mod
implicit none
contains
subroutine norm_arr_shape_access(x1, x2, x3, x4, assumed_x1, l1, l2, l3, l4)
! use nested_routine_mod, only : nested_routine
implicit none
integer :: i1, i2, i3, i4, c1, c2, c3, c4
integer, intent(in) :: l1, l2, l3, l4
integer, intent(inout) :: x1({start_index}:l1+{start_index}-1)
integer, intent(inout) :: x2({start_index}:l2+{start_index}-1, &
& {start_index}:l1+{start_index}-1)
integer, intent(inout) :: x3({start_index}:l3+{start_index}-1, &
& {start_index}:l2+{start_index}-1, {start_index}:l1+{start_index}-1)
integer, intent(inout) :: x4({start_index}:l4+{start_index}-1, &
& {start_index}:l3+{start_index}-1, {start_index}:l2+{start_index}-1, &
& {start_index}:l1+{start_index}-1)
integer, intent(inout) :: assumed_x1(l1)
c1 = 1
c2 = 1
c3 = 1
c4 = 1
do i1=1,l1
assumed_x1(i1) = c1
call nested_routine(assumed_x1, l1, c1)
end do
x1({start_index}:l4+{start_index}-1) = 0
do i1={start_index},l1+{start_index}-1
x1(i1) = c1
do i2={start_index},l2+{start_index}-1
x2(i2, i1) = c2*10 + c1
do i3={start_index},l3+{start_index}-1
x3(i3, i2, i1) = c3*100 + c2*10 + c1
do i4={start_index},l4+{start_index}-1
x4(i4, i3, i2, i1) = c4*1000 + c3*100 + c2*10 + c1
c4 = c4 + 1
end do
c3 = c3 + 1
end do
c2 = c2 + 1
end do
c1 = c1 + 1
end do
end subroutine norm_arr_shape_access
subroutine nested_routine(nested_x1, l1, c1)
implicit none
integer, intent(in) :: l1, c1
integer, intent(inout) :: nested_x1(:)
integer :: i1
do i1=1,l1
nested_x1(i1) = c1
end do
end subroutine nested_routine
end module norm_arr_shape_access_mod
"""
def init_arguments(l1, l2, l3, l4):
x1 = np.zeros(shape=(l1,), order='F', dtype=np.int32)
assumed_x1 = np.zeros(shape=(l1,), order='F', dtype=np.int32)
x2 = np.zeros(shape=(l2,l1,), order='F', dtype=np.int32)
x3 = np.zeros(shape=(l3,l2,l1,), order='F', dtype=np.int32)
x4 = np.zeros(shape=(l4,l3,l2,l1,), order='F', dtype=np.int32)
return x1, x2, x3, x4, assumed_x1
def validate_routine(routine):
arrays = [var for var in FindVariables().visit(routine.body) if isinstance(var, sym.Array)]
for arr in arrays:
assert all(not isinstance(shape, sym.RangeIndex) for shape in arr.shape)
l1 = 2
l2 = 3
l3 = 4
l4 = 5
module = Module.from_source(fcode, frontend=frontend, xmods=[tmp_path])
for routine in module.routines:
normalize_range_indexing(routine) # Fix OMNI nonsense
filepath = tmp_path/(f'norm_arr_shape_access_{frontend}.f90')
# compile and test "original" module/function
mod = jit_compile(module, filepath=filepath, objname='norm_arr_shape_access_mod')
function = getattr(mod, 'norm_arr_shape_access')
orig_x1, orig_x2, orig_x3, orig_x4, orig_assumed_x1 = init_arguments(l1, l2, l3, l4)
function(orig_x1, orig_x2, orig_x3, orig_x4, orig_assumed_x1, l1, l2, l3, l4)
clean_test(filepath)
# apply `normalize_array_shape_and_access`
for routine in module.routines:
normalize_array_shape_and_access(routine)
filepath = tmp_path/(f'norm_arr_shape_access_normalized_{frontend}.f90')
# compile and test "normalized" module/function
mod = jit_compile(module, filepath=filepath, objname='norm_arr_shape_access_mod')
function = getattr(mod, 'norm_arr_shape_access')
x1, x2, x3, x4, assumed_x1 = init_arguments(l1, l2, l3, l4)
function(x1, x2, x3, x4, assumed_x1, l1, l2, l3, l4)
clean_test(filepath)
# validate the routine "norm_arr_shape_access"
validate_routine(module.subroutines[0])
# validate the nested routine to see whether the assumed size array got correctly handled
assert module.subroutines[1].variable_map['nested_x1'] == 'nested_x1(:)'
# check whether results generated by the "original" and "normalized" version agree
assert (x1 == orig_x1).all()
assert (assumed_x1 == orig_assumed_x1).all()
assert (x2 == orig_x2).all()
assert (x3 == orig_x3).all()
assert (x4 == orig_x4).all()

The symptom is usually one of the following:

  1. Pytest/Python crashes completely (sometimes belatedly) with a SIGABRT, backtrace suggests memory corruption (triggers in malloc sanity checks)
  2. Wrong data type in the output of the transformed code:
        # check whether results generated by the "original" and "normalized" version agree
>       assert (x1 == orig_x1).all()
E       AttributeError: 'bool' object has no attribute 'all'
  1. Output not matching expected results:
>       assert (x1 == orig_x1).all()
E       assert False
E        +  where False = <built-in method all of numpy.ndarray object at 0x11f9643f0>()
E        +    where <built-in method all of numpy.ndarray object at 0x11f9643f0> = array([1, 2], dtype=int32) == array([0, 2], dtype=int32)
E             
E             Full diff:
E             - array([0, 2], dtype=int32)
E             ?        ^
E             + array([1, 2], dtype=int32)
E             ?        ^.all
@reuterbal reuterbal added the bug Something isn't working label Jul 27, 2024
reuterbal added a commit that referenced this issue Jul 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant