Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Memory allocation

cdetech
Beginner
834 Views

I have a project that I have recently moved from Visual Fortran 6.5 to Intel Fortran 8.1. The code has the following data structure.

pointer (ptr_desired_stations, desired_stations)
structure /STATION_LIST/
integer id
integer ichan
character city*20
character state*2
character sta_type*1
character fill*1
logical*2 class_a
character offset*1
end structure
record /STATION_LIST/ desired_stations(*)
I allocated memory for the object as follows.
if (ptr_desired_stations .ne. 0)
& call report_mem_error_1(routine, pointer_name)
c
c Allocate memory
c
ptr_desired_stations = malloc(n_des_sta * 35)
if (ptr_desired_stations .eq. 0)
& call report_mem_error(routine, pointer_name, n_des_sta)
return
The problem happens when I try to free the memory.

if

(ptr_desired_stations .eq. 0)

& call report_mem_error_2(routine, pointer_name)

call free(ptr_desired_stations)

ptr_desired_stations = 0

return

I get a "Microsoft Visual C++ Debug library" error that says "DAMAGE: after Normal block(#104659) at 0x06F2B648.

This error does not come up when I compile the program using Visual Fortran 6.5, only with the Intel Fortran 8.1?

Can someone please tell me why it is coming up(though I believe the size isn't right for the memory allocation, but I've

tried changing the variabl e sizes and that didn't work) and why it only comes up in the new compiler(is it a problem that the

old compiler misses it)?

0 Kudos
7 Replies
cdetech
Beginner
834 Views

I just noticed that the "logical*2 class_a" should be "logical class_a", which is how it is in the original code. The same error occurred when I

tried "logical*2 class_a".

0 Kudos
Steven_L_Intel1
Employee
834 Views
Is this in a subroutine that is called multiple times and the intent is that the pointer to the allocated memory is remembered across the calls? If so, add a SAVE statement for the pointer variable. Otherwise the pointer becomes undefined on exit from the routine.
0 Kudos
cdetech
Beginner
834 Views
The problem, it seems, is that I needed to allocate to change the 35 to 37 in the statement "ptr_desired_stations = malloc(n_des_sta * 35)". This makes sense because 37 is the total you get if you add up the default sizess for variables in the structure STATION_LIST. The problem came up only after I compiled in Intel Fortan 8.1. The code always compiled in Compaq Fortran 6.5. Does anyone know if Compaq Fortran 6.5 has default sizes different from Intel Fortran 8.1(I've looked but haven't seen anything)? Or could it be non-rigorous bounds checking?
0 Kudos
Steven_L_Intel1
Employee
834 Views
The sizes haven't changed. You should use SIZEOF() rather than a hardcoded number. My guess is that in the CVF version you were silently corrupting memory and that a different order of memory revealed the problem in Intel Fortran. I don't see how bounds checking is involved.

Version 10.1 is current.
0 Kudos
cdetech
Beginner
834 Views
Sorry, I was using the wrong terminology. By "bounds checking" I meant that the newer version was checking to make sure memory wasn't corrupted while the older version didn't care as much(basically what you said).

I have tried to adjust the code so use SIZEOF(). The problem is, SIZEOF() keeps returning the value 4, and I know that is not right. Here is the code again(original post formatting wasn't good).

     pointer (ptr_desired_stations, desired_stations)
structure /STATION_LIST/
integer id
integer ichan
character city*20
character state*2
character sta_type*1
character fill*1
logical class_a
character offset*1
end structure
record /STATION_LIST/ desired_stations(*)

I changed the earlier code to

tmp_size = sizeof(STATION_LIST)
ptr_desired_stations = malloc(n_des_sta * tmp_size)


As I said earlier, when I do this I get "tmp_size = 4". This causes an unrelated error(at least, an error not immediately connected to "ptr_desired_stations"). The line that causes the error is

write(time_string, 1000) int(hours),
& int(60*mod(hours, 1.0)),
& int(60*mod(60*mod(hours, 1.0), 1.0))


The error message is

Insufficient memory to allocate Fortran RTL message buffer, message #41.

This seems to be a memory corruption error. Does SIZEOF() need an instance of STATION_LIST?
0 Kudos
Steven_L_Intel1
Employee
834 Views
Yes, SIZEOF needs a variable. You caused it to ask for the size of an undeclared variable.

The compiler does no memory range checking other than array and string bounds.
0 Kudos
Jugoslav_Dujic
Valued Contributor II
834 Views
The said error message is [relatively] new in Microsoft's C run time library. The RTL checks whether the "guard" block of memory after the (m)allocated blocks is in the original state and reports the debug message if not.

The problem is indeed in your hard-coded size of the structure (35 or 37, whichever). In reality, it would be 40 -- and that would be returned by SIZEOF(tempStationList). The value of 40 comes as consequence of the "natural alignment" feature of computer architecture -- by default, the processor "likes" that n-byte variables are aligned on an address divisible by n. As consequence, the "real" size of structure is a multiply of size of its greatest (non-character) member; that means that you will have 3 "unused" bytes after each member of desired_stations array. Now, you malloc() less memory that you actually use, overwriting its tail in the process.

SEQUENCE keyword (or !DEC$PACK metacommand, I'm not sure if the former applies to STRUCTUREs) should prevent the "natural alignment" to occur, i.e. will "densely pack" the structure members. It will also reduce performance though. As Steve said, best, use SIZEOF with a dummy variable of appropriate type to find out the size.
0 Kudos
Reply