손상된 Fortran 할당 가능 어레이 재설정 (할당 해제 / 무효화)

Nov 18 2020

잘못된 포트란 오류 : 할당 가능한 배열이 이미 할당 된 경우에 설명 된 것과 같은 상황이 발생합니다. 할당을 취소 할 수없는 어레이에 대한 DEALLOCATE 포인트가 발생합니다 (손상된 메모리가 할당 된 것으로 보이지만 유효한 주소를 "가리 키지"않는 할당 가능한 어레이를 남김). Fortran 내에서이를 치료하기 위해 수행 할 수있는 작업이 있습니까 (예 : 어레이 재설정) 할당 해제 된 메모리를 할당 해제하지 않고

상황은 C 코드 조각이 할당 된 메모리를 의도적으로 손상 (쓰레기 기록)하는 Fortran / C 프로그램입니다. 이것은 일반 유형의 배열에서 잘 작동합니다. 그러나 할당 가능한 구성 요소를 포함하는 사용자 정의 유형의 할당 가능한 배열을 사용하면 할당 가능한 구성 요소에 속하는 부분에 쓰인 쓰레기가 할당되지 않았더라도 이제 구성 요소가 할당 된 것으로 나타납니다. C 코드가 무엇이 손상되어야하는지 아닌지 인식하도록하는 것보다 나중에 수정하는 것을 선호하지만 할당 가능한 구성 요소를 "무효화"하는 것이 좋습니다. 현재 가리키는 메모리에 신경 쓰지 않는다는 것을 알 때. 포인터를 사용하면의 문제 nullify이지만 할당 가능한 배열이 있습니까?

답변

3 VladimirF Nov 18 2020 at 18:03

스택 손상 / 힙 손상과 같이 메모리가 실제로 손상된 경우. 당신은 아무것도 할 수 없습니다. 매우 낮은 수준의 정보가 손실되므로 프로그램이 실패 할 수 있습니다. 이는 모든 프로그래밍 언어, 심지어 C에도 해당됩니다.

손상된 것이 Fortran 배열 설명자인 경우 Fortran에서 수정할 수 없습니다. Fortran은 이러한 구현 세부 정보를 Fortran 프로그래머에게 공개하지 않습니다. ISO_Fortran_binding.hC에서 호출 된 특수 헤더를 통해서만 사용할 수 있습니다 .

발생한 유일한 손상이 Fortran으로 인해 배열이 할당되지 않은 곳에 할당 된 경우 C에서이를 되 돌리는 것이 다소 간단해야합니다. 필요한 것은 할당 된 메모리의 주소를 변경하는 것뿐입니다. 할당 가능한 배열은 항상 연속적입니다.

실제로는 할당 가능하고 무효화 할 때 전달하는 것이 포인터라고 서브 루틴에 알리는 것과 같은 더러운 트릭을 시도 할 수도 있습니다. 많은 구현에서 작동합니다. 그러나 제어 가능한 방식으로 주소를 무효화하는 것이 훨씬 더 깔끔합니다. Fortran에서 호출하는 C 함수를 무효화하는 경우에도 마찬가지입니다.

주소를 0으로 만 변경하고 배열 범위, 스트라이드 및 기타 세부 사항으로 다른 특별한 것을 만들지 않기를 원하기 때문에 헤더 없이도 간단해야합니다.

디스크립터는 여전히 다른 변수에 말도 안되는 데이터를 포함하지만 중요하지 않습니다.


이것은 빠르고 더러운 테스트입니다.

포트란 :

  dimension A(:,:)
  allocatable A
  
  interface
    subroutine write_garbage(A) bind(C)
      dimension A(:,:)
      allocatable A
    end subroutine
      
    subroutine c_null_alloc(A) bind(C)
      dimension A(:,:)
      allocatable A
    end subroutine
      
  end interface
  
  call write_garbage(A)
  
  print *, allocated(A)
  
  call c_null_alloc(A)
  
  print *, allocated(A)
  
end

씨:

#include <stdint.h>
void write_garbage(intptr_t* A){
  *A = 999;
}

void c_null_alloc(intptr_t* A){
  *A = 0;
}

결과:

> gfortran c_allocatables.c c_allocatables.f90
> ./a.out 
 T
 F

ISO_Fortran_binding.h컴파일러에서 제공 하는 경우 적절한 버전을 사용해야 합니다. 그리고 implicit none다른 지루한 것들 ...


내가 전혀 권장하지 않는 매우 더러운 (그리고 불법적 인) 해킹 :

  dimension A(:,:)
  allocatable A
  
  interface
    subroutine write_garbage(A) bind(C)
      dimension A(:,:)
      allocatable A
    end subroutine
      
    subroutine null_alloc(A) bind(C)
      dimension A(:,:)
      allocatable A
    end subroutine
      
  end interface
  
  call write_garbage(A)
  
  print *, allocated(A)
  
  call null_alloc(A)
  
  print *, allocated(A)
  
end

subroutine null_alloc(A) bind(C)
      dimension A(:,:)
      pointer A
      
      A => null()
end subroutine
> gfortran c_allocatables.c c_allocatables.f90
c_allocatables.f90:27:21:

   10 |     subroutine null_alloc(A) bind(C)
      |                         2
......
   27 | subroutine null_alloc(A) bind(C)
      |                     1
Warning: ALLOCATABLE mismatch in argument 'a' between (1) and (2)
> ./a.out 
 T
 F