I have a fortran subroutine (getmem.F) that uses a C program (memalloc.c) for dynamic memory allocation. The following subroutine and functions are a part of a very old and large code that was used for research purposes. I am compiling on a 64 bit machine and I am using a PGI compiler 2020.4 version. The following is the fortran code.
subroutine getmem(ptr, size)
c-----get pointered memory
cdir$ nolist
include 'common.h'
include 'inputcom.h'
cdir$ list
integer memalloc, memfree
integer ptr, size, ierr0
c-----allocate 'size' words of memory and send back pointer in 'ptr'
print *, "Value of ptr and size before memory allocation"
print *, "ptr:", ptr ! The value of ptr is 0
print *, "size:", size ! The value of size is 1138280
if (size .lt. 0) then
ierr0 = memfree (ptr)
else
ierr0 = memalloc (ptr, size)
endif
print *, "Value of ptr and size after memory allocation"
print *, "ptr:", ptr ! The value of ptr is -1431465968 (This is incorrect
! value which is the decimal from signed 2's complement for 2863501328)
print *, "size:", size ! The value of size is 1138280
if (ierr0 .ne. 0) then
call writemsg ('Unable to get memory.')
write (buffer, 100) size
100 format ('GETMEM: size is ', i15, '.')
call writemsg (buffer)
stop 'getmem'
endif
return
end
Here is the C code memalloc.c
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h> /* Added by Surya */
int memalloc_ (int *nextptr, int *size)
{
void *ptr;
printf("Address of nextptr:%p \nValue of nextptr: %d \n", nextptr, *nextptr);
/*Output: Address of nextptr: 0x1687ad0
Value of nextptr: 0 */
/* Before Memory Allocation */
printf("Address pointed by ptr (Value stored in ptr): %p \n", (void*)ptr);
/*Output: Address pointed by ptr (Value stored in ptr): 0x7fffffff8b40 */
if (*nextptr == NULL) {
if ((ptr = (void *) malloc (*size)) == NULL) {
return(-1);
}
}
else {
if ((ptr = (void *) realloc (*nextptr, *size)) == NULL) {
return(-1);
}
}
/* After memory allocation using malloc() */
printf("Address pointed by ptr (Value stored in ptr): %p \nValue when printed as a long integer %ld \n", (void*)ptr, (int*)ptr);
/* Output: Address pointed by ptr (Value stored in ptr): 0x2aaaaaad9010
Value when printed as a long integer: 46912496308240 */
*nextptr = (int) ptr;
printf("Address of nextptr:%p \nValue of nextptr: %d \n", nextptr, *nextptr);
/* Output: Address of nextptr: 0x1687ad0
Value of nextptr: -1431465968 */
printf("Value of nextptr in long format: %ld \n", *nextptr);
/* Output: Value of nextptr in long format: 2863501328 */
return (0);
}
When I do hexadecimal to decimal conversions and vice versa (https://www.rapidtables.com/convert/number/hex-to-decimal.html), I notice what the issue is. When we do (int) ptr. The hexadecimal value of ptr = 0x2aaaaaad9010 (decimal value is 46912496308240) is truncated to aaad9010 (decimal value is 2863501328). When this gets passed back into the fortran77 code as ptr, the ptr which is later used as pointer to point to memory is unable to find the variable and its value. How do I fix this issue so that the truncation does not happen in the C program?
P.S. This is very old style of coding but it is part of a much larger code (Validated with experiments) of my research.
(int) ptrcast is non-portable and fairly obviously the culprit of your narrowing conversion.ptrbefore assigning it to point somewhere. You can't print the contents pointed at bynextptrbefore assigning a value. You cannot print the value of a null pointer.sizeas a pointer since you don't change it inside the function.malloctovoid*is pointless.void*tovoid*is pointless.reallocbehaves likemallocif passed a NULL pointer. Since your function apparently assumes that the passed pointer is always initialized as a null pointer during the first call, you can utilize that to simplify the code.reallocwith an uninitialized pointer as parameter.With all the bugs and clutter removed, your code might look something like this:
This should compile even in old C90.