For Programmers: Free Programming Magazines  


Home > Archive > Fortran > April 2007 > How can I secure this small code ?









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author How can I secure this small code ?
Patrick Begou

2007-04-17, 7:05 pm

Hi,

I need an advice to improve the security of my application. This a small
example showing my problem. I have a module defining a new type :

MODULE mydata

TYPE mystruct
REAL:: donnee
END TYPE mystruct

END MODULE mydata

Now I am using this module in a small application in main.f. There ar a
main program and a simple subroutine.

PROGRAM ess

USE mydata

IMPLICIT NONE

TYPE(mystruct) :: val

val%donnee=17.7
CALL affiche(val%donnee)
END PROGRAM ess



SUBROUTINE affiche(v)

IMPLICIT NONE
REAL, INTENT(IN):: v
WRITE(6,*)'Value is : ',v
END SUBROUTINE affiche

My problem is that if I increase the precision at compile time for the
module to promote de REAL variable (donnee) in DOUBLE PRECISION and
forgot to add this option when compiling again main.f the error is not
detected by the compiler. How can I secure this ?

Of course, building a second module for the subroutine solve the
problem. A nice makefile also solves the problem but I'm very interested
in understanding how to make a better Fortran code solving this question.

Thanks for your advices.

Patrick
Arjen Markus

2007-04-17, 7:05 pm

On 17 apr, 15:58, Patrick Begou <Patrick.Be...@hmg.inpg.fr> wrote:
> Hi,
>
> I need an advice to improve the security of my application. This a small
> example showing my problem. I have a module defining a new type :
>
> MODULE mydata
>
> TYPE mystruct
> REAL:: donnee
> END TYPE mystruct
>
> END MODULE mydata
>
> Now I am using this module in a small application in main.f. There ar a
> main program and a simple subroutine.
>
> PROGRAM ess
>
> USE mydata
>
> IMPLICIT NONE
>
> TYPE(mystruct) :: val
>
> val%donnee=17.7
> CALL affiche(val%donnee)
> END PROGRAM ess
>
> SUBROUTINE affiche(v)
>
> IMPLICIT NONE
> REAL, INTENT(IN):: v
> WRITE(6,*)'Value is : ',v
> END SUBROUTINE affiche
>
> My problem is that if I increase the precision at compile time for the
> module to promote de REAL variable (donnee) in DOUBLE PRECISION and
> forgot to add this option when compiling again main.f the error is not
> detected by the compiler. How can I secure this ?
>
> Of course, building a second module for the subroutine solve the
> problem. A nice makefile also solves the problem but I'm very interested
> in understanding how to make a better Fortran code solving this question.
>
> Thanks for your advices.
>
> Patrick


Rather than using REAL and rely on a compile option to make it double
precision by default, use REAL(KIND=wp) where "wp" is a parameter that
you define in a separate module, like:

integer, parameter wp = kind(1.0)

Or use the real_selected_kind function (never sure of the name) to
determine the
minimum real kind that supports the given precision and range.

To guard against:

double_precision_variable = single_precision_variable

you can use the fact that your data are in a derived type:

type(mystruct) :: dd

dd = 17.7

(instead of dd.donnee = 17.7)

Then you can control via user-defined assignment whether you accept
17.7 or that it should be 17.7d00 or ...

Regards,

Arjen

Beliavsky

2007-04-17, 7:05 pm

On Apr 17, 10:26 am, Arjen Markus <arjen.mar...@wldelft.nl> wrote:
> On 17 apr, 15:58, Patrick Begou <Patrick.Be...@hmg.inpg.fr> wrote:
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> Rather than using REAL and rely on a compile option to make it double
> precision by default, use REAL(KIND=wp) where "wp" is a parameter that
> you define in a separate module, like:
>
> integer, parameter wp = kind(1.0)


Don't forget the "::". It should be

integer, parameter :: wp = kind(1.0)

>
> Or use the real_selected_kind function (never sure of the name) to
> determine the
> minimum real kind that supports the given precision and range.


The name of the function is selected_real_kind .

I agree with the general advice.

Arjen Markus

2007-04-17, 7:05 pm

On 17 apr, 16:34, Beliavsky <beliav...@aol.com> wrote:
> On Apr 17, 10:26 am, Arjen Markus <arjen.mar...@wldelft.nl> wrote:
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> Don't forget the "::". It should be
>
> integer, parameter :: wp = kind(1.0)
>
>
>
>
> The name of the function is selected_real_kind .
>
> I agree with the general advice.



Oops, a hasty reply - not only is the double colon "::" missing, I
also typed . instead of %

Regards,

Arjen

Richard Maine

2007-04-17, 7:05 pm

Patrick Begou <Patrick.Begou@hmg.inpg.fr> wrote:
[code elided]
> My problem is that if I increase the precision at compile time for the
> module to promote de REAL variable (donnee) in DOUBLE PRECISION and
> forgot to add this option when compiling again main.f the error is not
> detected by the compiler. How can I secure this ?
>
> Of course, building a second module for the subroutine solve the
> problem. A nice makefile also solves the problem but I'm very interested
> in understanding how to make a better Fortran code solving this question.


Arjen suggested using a kind type parameter instead of single/double
precision. I agree with that suggestion and pretty much always do that
myself. However, I also want to ephasize the importance of explicit
interfaces in this area. I know that you said that "of course", using a
second module solves the problem, but that is so important that I think
it needs emphasis anyway.

Putting all your procedures in modules (or internal procedures) means
that you will always have explicit interfaces. That is *THE* best way to
catch errors in argument passing at compile time. It is a bit to
important to pass over with just "of course, you could do that." Any
other ways that you might improve the rebustness of the code should be
in addition to that. And yes, using kind type parameters would be one of
those other ways.

--
Richard Maine | Good judgement comes from experience;
email: last name at domain . net | experience comes from bad judgement.
domain: summertriangle | -- Mark Twain
Ron Shepard

2007-04-17, 7:05 pm

In article <f02jqf$asr$1@news.grenet.fr>,
Patrick Begou <Patrick.Begou@hmg.inpg.fr> wrote:

> Hi,
>
> I need an advice to improve the security of my application. This a small
> example showing my problem. I have a module defining a new type :
>
> MODULE mydata
>
> TYPE mystruct
> REAL:: donnee
> END TYPE mystruct
>
> END MODULE mydata
>
> Now I am using this module in a small application in main.f. There ar a
> main program and a simple subroutine.
>
> PROGRAM ess
>
> USE mydata
>
> IMPLICIT NONE
>
> TYPE(mystruct) :: val
>
> val%donnee=17.7
> CALL affiche(val%donnee)
> END PROGRAM ess
>
>
>
> SUBROUTINE affiche(v)
>
> IMPLICIT NONE
> REAL, INTENT(IN):: v
> WRITE(6,*)'Value is : ',v
> END SUBROUTINE affiche
>
> My problem is that if I increase the precision at compile time for the
> module to promote de REAL variable (donnee) in DOUBLE PRECISION and
> forgot to add this option when compiling again main.f the error is not
> detected by the compiler. How can I secure this ?
>
> Of course, building a second module for the subroutine solve the
> problem. A nice makefile also solves the problem but I'm very interested
> in understanding how to make a better Fortran code solving this question.


There are several approaches. If all of this is your own code, then
the best way is to write a separate module that defines all of the
parameters that you use for data kinds, and use that module
throughout your code to make sure everything is consistent. If you
need to change a kind at some point in the future, then you need to
change only a single parameter value, recompile, and you are done.

But if some of the code you are using is not yours, or under your
control, then you can't do that. In that case, you need to use the
kind() intrinsic to query the various data types. You should do
something like the following:

module data_mod
type mystruct
real :: areal
double precision :: adouble
end type mystruct
end module data_mod

program assign
use data_mod
type(mystruct) :: val
integer, parameter :: rk = kind(val%areal), dk=kind(val%adouble)
write(*,*) rk, dk
val%areal = 17.7_rk
val%adouble = 17.7_rk
write(*,'(f0.6,1x,f0.16)') val
val%areal = 17.7_dk
val%adouble = 17.7_dk
write(*,'(f0.6,1x,f0.16)') val
end program assign


Notice how the rk and dk parameters depend on the data types from
the module. Even if you did not have the source code to the module,
then you could still determine these values. The other part of the
solution is to use those parameters to define the appropriate
constants 17.7_rk and 17.7_dk.

Specifically, in your code you would do something like

...
integer, parameter :: donnee_kind = kind(val%donnee)
...
val%donnee = 17.7_donnee_kind
...

That way, you always have a consistent assignment with no extra
precision and no lost precision. Also, you could use that parameter
to declare your own local variables, your own derived types, and so
on that are consistent with the external module, even if you do not
have the source code to that external module.

Note that donnee_kind must be a parameter, it cannot be a variable.
All of this magic is done at compile time, not at run time.

$.02 -Ron Shepard
Patrick Begou

2007-04-17, 7:05 pm

Richard Maine wrote:
> Putting all your procedures in modules (or internal procedures) means
> that you will always have explicit interfaces. That is *THE* best way to
> catch errors in argument passing at compile time. It is a bit to
> important to pass over with just "of course, you could do that." Any
> other ways that you might improve the rebustness of the code should be
> in addition to that.


I think I will proceed like this. I was just surprised that no error was
reported as the subroutine was in the same file than the caller and was
only called in this file. This is why I wrote that "building an
additional modules was an option". But it seems is is the best solution.

Patrick
dpb

2007-04-17, 7:05 pm

On Apr 17, 11:33 am, Patrick Begou <Patrick.Be...@hmg.inpg.fr> wrote:
> Richard Maine wrote:
>
> I think I will proceed like this. I was just surprised that no error was
> reported as the subroutine was in the same file than the caller and was
> only called in this file. ...


That is a fundamental feature of Fortran -- compilation scope is not
by file but by compilation unit -- program, subroutine or function.
This is fundamental to the design of Fortran and when understood then
the surprise element should go away. The operation of the compiler in
terms of code analysis and compilation is the same for the routines as
if the two were actually in separate files and submitted
independently. The use of modules causes the necessary information to
be generated and made available via explicit interfaces.


Beliavsky

2007-04-17, 7:05 pm

On Apr 17, 1:27 pm, dpb <bozart...@gmail.com> wrote:
> On Apr 17, 11:33 am, Patrick Begou <Patrick.Be...@hmg.inpg.fr> wrote:
>
>
>
> That is a fundamental feature of Fortran -- compilation scope is not
> by file but by compilation unit -- program, subroutine or function.
> This is fundamental to the design of Fortran and when understood then
> the surprise element should go away. The operation of the compiler in
> terms of code analysis and compilation is the same for the routines as
> if the two were actually in separate files and submitted
> independently. The use of modules causes the necessary information to
> be generated and made available via explicit interfaces.


I second your recommendation to use modules.

Most Fortran 95 compilers, however, generate warning messages for
mismatched arguments when the caller and callee are in the same file
but not when they are in separate files, if the right compilation
options are used. For the code

function twice(i) result(i2)
integer, intent(in) :: i
integer :: i2
i2 = 2*i
end function twice

program main
real :: x = 1.0
print*,twice(x)
end program main

stored in a single file mismatch.f90, g95 says

g95 mismatch.f90
In file mismatch.f90:1

function twice(i) result(i2)
1
In file mismatch.f90:9

print*,twice(x)
2
Error: FUNCTION 'twice' is of type INTEGER(4) at (1) and type REAL(4)
at (2)

Lahey Source Check http://www.lahey.com/cgi-bin/check.pl says
Compiling program unit twice at line 1:
Compiling program unit main at line 6:
2603-S: "SOURCE.F90", line 9: Argument number '1' type of procedure
'twice' shall be the same between definition and reference. The
previous appearance is in 'line 1'.
2617-S: "SOURCE.F90", line 9: The type of function 'twice' result
shall be the same between definition and reference. The previous
appearance is in 'line 1'.
Encountered 2 errors, 0 warnings, 0 informations in file SOURCE.F90.
Compiling file SOURCE.F90.

Salford/Silverfrost says
NO ERRORS [<TWICE> FTN95/Win32 v5.01.0]
0009) print*,twice(x)
WARNING - In a previous call to TWICE, the first argument was of type
INTEGER(KIND=3), it is now REAL(KIND=1)
NO ERRORS, 1 WARNING [<MAIN> FTN95/Win32 v5.01.0]

NAG http://cpc.cs.qub.ac.uk/SyntaxChecker.html says
File mismatch.f90 compiled using command options -c -mdir /tmp -fpp
Error: /tmp/mismatch.003083.f90: Wrong data type for reference to
function TWICE from MAIN
Error: /tmp/mismatch.003083.f90: Argument I (no. 1) in reference to
TWICE from MAIN has the wrong data type

ifort /gen-interfaces /warn:interfaces mismatch.f90 says
Intel(R) Fortran Compiler for 32-bit applications, Version 9.1
Build 20070322Z Package ID: W_FC_C_9.1.037
Copyright (C) 1985-2007 Intel Corporation. All rights reserved.

mismatch.f90(9) : Error: The type of the function reference does not
match the type of the function definition. [TWICE]
print*,twice(x)
-------^
mismatch.f90(9) : Error: The type of the actual argument differs from
the type of the dummy argument. [X]
print*,twice(x)
-------------^
compilation aborted for mismatch.f90 (code 1)

gfortran compiles silently with -Wall -pedantic -std=f2003
mismatch.f90
but prints NaN on output. It would be nice if gfortran, like other
compilers with the right options set, checked consistency when the
caller and callee were in the same file.

Therefore, if one does not use modules or explicitly write INTERFACEs,
one crude but simple debugging technique is to put all sources to a
single file and compile with all warnings on.

Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com