一个简单的可选参数如何导致数据损坏? [英] How could a simple optional argument lead to data corruption?

查看:105
本文介绍了一个简单的可选参数如何导致数据损坏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有例程的FORTRAN代码:

I have a FORTRAN code with a routine:

SUBROUTINE READ_NC_VALS(NCID, RECID, VARNAME, VARDATA)
integer ncid, recid
character*(*) varname
real*8 vardata
dimension vardata(15,45,75)

etc.

我想为这段代码增加一些灵活性,我想我会先添加一个可选的flag参数来做到这一点:

I want to add some flexibility to this code, and I thought I would do it by first adding an optional flag argument:

SUBROUTINE READ_NC_VALS(NCID, RECID, VARNAME, VARDATA, how_to_calculate)

! everything the same and then ...
logical, optional :: how_to_calculate

现在,在这一点上,我什至没有使用"how_to_calculate".我只是将其放入测试代码中.因此,我可以毫不费力地编译代码.然后运行它,然后在子例程中得到一个错误.具体而言,稍后代码中的某些值会从没有该可选参数的情况神奇地"更改.新值对代码的逻辑没有意义,因此会礼貌地退出并显示错误消息.让我再次强调,在这一点上,我什至没有使用这个 optional 参数.因此,不知所措,我回到了源代码中调用此例程的所有位置,即使我的新参数是可选的,我也会在所有调用中为其添加值.当我这样做时,代码可以正常运行.那么这是什么一回事?子例程中仅存在未使用的可选参数,怎么会导致其他数据损坏?以及如何为该可选参数添加输入参数来再次解决问题?顺便说一下,这是用PGI编译的.

Now, at this point, I am not even using "how_to_calculate". I am just putting it into the code for testing. So I compile the code without a hitch. Then I run it, and I get an error in the subroutine. Specifically, some of the values in the code later on are "magically" altered from what they were without that optional argument. The new values don't make sense to the logic of the code, so it exits politely with an error message. Let me stress again that at this point, I am not even using this optional argument. So then, on a lark, I go back to all the places in the source that call this routine and, even though my new argument in optional, I put in values for it in all the calls. When I do that, the code runs fine. So, what's up? How can the mere presence of an unused optional argument in a subroutine result in other data being corrupted? And how can adding input parameters for this optional argument fix things again? This is being compiled with PGI, by the way.

有什么想法吗?谢谢.

顺便说一句,对不起,您未提供更多代码.如果我那样做,我的老板可能不会对我太满意.我没有制定规则;我只是在这里工作.

BTW, sorry for not providing more code. My boss might not be too happy with me if I did that. I don't make the rules; I just work here.

推荐答案

Fortran中的可选参数是通过为调用子例程没有提供值的每个可选参数传递0(空指针)来实现的.因此,带有可选参数的子例程必须:

Optional arguments in Fortran are implemented by passing 0 (a null pointer) for each optional argument that has no value provided by the calling subroutine. Because of this subroutines that take optional arguments have to:

  • 在调用子例程中都有明确的INTERFACE定义
  • 或者是模块级别的子例程(因为它们是自动生成的接口)

如果向子例程添加可选参数,但是该子例程在调用程序中既没有接口又不是模块级子例程,则编译器将不会生成正确的调用序列-传递的参数将少于预期的数量.在Unix系统上,这可能会引起问题,其中PGI在参数列表的末尾传递所有CHARACTER*(*)参数的长度(在Windows上,它将作为字符串地址后的下一个参数传递的长度).一个缺少的参数会改变长度参数在堆栈中的位置(或将它们放置在x64上的错误寄存器中),从而导致VARNAME字符串的长度不正确,而READ_NC_VALS会接收该字符串.这可能导致各种不良行为,包括过度写入内存和神奇地"更改不应根据程序逻辑更改的值.

If you add an optional argument to a subroutine but it neither has an interface in the caller or is not a module-level subroutine, then the compiler will not generate the right calling sequence - it will pass less arguments than expected. This could pose a problem on Unix systems, where PGI passes the length of all CHARACTER*(*) arguments at the end of the argument list (on Windows it passes the length as the next argument after the address of the string). One missing argument would shift the length arguments placement in the stack (or put them in the wrong registers on x64) leading to the incorrect length of the VARNAME string being received by READ_NC_VALS. This could lead to all sorts of ill behaviour, including overwritting memory and "magically" changing values that should not change according to the program logic.

这篇关于一个简单的可选参数如何导致数据损坏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆