How could a simple optional argument lead to data corruption? - fortran90

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.
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
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.
Any ideas? Thanks.
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.

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:
either have an explicit INTERFACE definition inside the calling subroutine
or be a module-level subroutine (for them interfaces are generated automatically)
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.

Obviously, just adding a dummy argument to a subroutine, with or without the optional attribute, shouldn't cause any problems. What might happen, though, is that the change exposes some other problem with the code, which was already there, but didn't cause any visible bad effects.
Without any more code, all we can do is guess, which usually isn't really useful.
One thing that pops into mind is the necessity of an explicit interface, when using optional arguments. Is the code organized into modules?

Related

How to avoid not used function to be wiped out by optimizer

While compiling and Xcode swift project for MacOS, not used functions are removed from the binary (removed by the optimizer I guess). Is there a way to tell the compiler to not remove unused functions, perhaps with a compiler option (--force-attribute?) so that even with optimization enabled those functions remain in the binary?
I know that if a global function is declared as public (public func test()) then it's not removed even if not used (Since it can be used by other modules), but I can't use public since that would export the symbol for that function.
Any suggestion?
If this is indeed removed by the optimiser, then the answer is two-fold.
The optimiser removes only things that it can prove are safely removable. So to make it not remove something, you remove something that the optimiser uses to prove removability.
For example, you can change the visibility of a function in the .bc file by running a pass that makes the functions externally callable. When a function is private to the .bc file (also called module) and not used, then the compiler can prove that nothing will ever call it. If it's visible beyong the .bc file, then the compiler must assume that something can come along later and call it, so the function has to be left alive.
This is really the generic answer to how to prevent an optimisation: Prevent the compiler from inferring that the optimisation is safe.
Writing and invoking a suitable pass is left as an exercise for the reader. Writing should be perhaps 20 lines of code, invoking… might be simple, or not, it depends on your setting. Quite often you can add a call to opt to your build system.
As I discovered, the solution here is to use a magic compiler flag -enable-private-imports (described here: "...Allows this module's internal and private API to be accessed") which basically add the function name to the list #llvm.used that you can see in the bitcode, the purpose of the list is:
If a symbol appears in the #llvm.used list, then the compiler,
assembler, and linker are required to treat the symbol as if there is
a reference to the symbol that it cannot see (which is why they have
to be named)
(cit.) As described here.
This solves my original problem as the private function even if not used anywhere and not being public, during compilation is not stripped out by the optimiser.

Change value of import parameter function module abap

I have a FM with structure in importing. When I try to change field value (wa_str-data = '31129999' for example), the change works, but when I get out of the FM, the field value is reset.
Is it possible to change the field value of a Function Module importing parameter which is of structured type?
Thanks to all.
No, you can't change the value of an IMPORTING parameter (unless it happens to be a TYPE REF TO, in which case you can change the value of the referenced object/data). You can only change values of CHANGING parameters. However, there is a dirty trick you might be able to use here. If you want to access the variable foo in the calling program Z_BAR, then you can do this:
FIELD-SYMBOLS <foo>.
ASSIGN ('(Z_BAR)FOO-DATA') TO <foo>.
IF sy-subrc = 0.
<foo> = newValue.
ENDIF.
(By the way, Z_BAR does not even need to be the direct caller of the function module. It just needs to be somewhere in the call stack.)
Why am I calling this a "dirty" trick?
It creates "spooky effects at a distance". Anyone examining Z_BAR would never expect a function module to change foo when it's not in its parameter list.
The variable name gets resolved at runtime, so there is no syntax check when you misspell it.
It breaks when the variable in the calling program gets renamed, and you won't know until it fails at runtime.
You need to know the name of the calling program in advance. When the function module gets called from another program, then it's not going to work anymore.
So I would only recommend this as a last resort measure.

"Undefined function 'function_name' for input arguments of type 'double'."

A question that pops up quite frequently in different shapes and sizes is: Why do I get the following error message:
"Undefined function 'function_name' for input arguments of type 'double'."
This post attempts to address all the different scenarios where this error message can occur, and propose solutions for how it can be resolved.
If you stumble upon this error message and don't know what it means. Take comfort in this: 90% of us have googled the same phrase.
"Undefined function 'int' for input arguments of type 'double'."
The error message is pretty self-explanatory but may still cause confusion. (I chose 'int' at random, it could just as well be 'train', 'table', 'my_function' or anything else).
There are two main cases where this error occurs:
You are trying to use a function that doesn't exist (yet)
You are trying to access an element in a variable that doesn't exist (yet)
What do you do if you get this error?
First, you might want to try which. This will tell you whether or not the function or variable you're trying to use is defined.
which int
'int' not found.
It's quite obvious, that Matlab can't find any functions or variables named int. Trying to use it is therefore futile. Let's compare it to max:
which max
built-in (C:\Program Files\MATLAB\R2014b\toolbox\matlab\datafun\#logical\max) % logical method
But, you might get the following, even if you get the "Undefined function 'x' ...". If so, see point 3 below.
which x
x is a variable.
1. But the function "int" exists! It is even documented here!?
Yes, int exists, but only if you have the Symbolic Toolbox. Since Toolboxes are additional packages that must be purchased separately (and can be quite expensive), chances are you don't have that package.
If you get the "Undefined function" error, but find the function in the documentation, have a look in the menu to the left, or simply check the address. Standard Matlab functions have addresses such as:
mathworks.com/help/matlab/ref/max.html
^^^^^^
Notice the "matlab" part. If you see this, then you are using a function that is part of the core Matlab.
If however, you see an address such as the one below, then the function you are trying to use is part of the Symbolic Toolbox:
mathworks.com/help/symbolic/int.html
^^^^^^^^
or maybe it's part of the Neural Network Toolbox:
mathworks.com/help/nnet/ref/train.html
^^^^
Solution: Find another function that isn't part of a toolbox you don't have. Chances are you'll find what you are looking for if you are a skilled googler. If you can't find it, ask for help. Explain what you have tried, and show that you have done some effort!
2. But the function is documented here, and is part of core Matlab!?
Even though a function is part of the standard Matlab installation, and is well documented, you may still get this error. The most likely cause for this error is that you are using an older version of Matlab. If you check the documentation you'll see the following at the bottom of the page:
Introduced in R2013b
So, if you are using R2012b then you can't use for instance table.
Solution: Check if the function is defined in your version of Matlab. If it's not yet implemented then you either need to update Matlab or find another way to do it. An alternative to table can for instance be to use cells or structs.
3. But the variable "my_variable" exists! I created it in the line above!
No, you didn't. Chances are you created the variable myvariable, my_Variable, my_Variable or something similar in the line above. It's also possible that you have created it, but have accidentally cleared it.
Solution: Go through the code. Look for typos, places where you have accidentally cleared the variable etc. Inside the Matlab editor you will get the following line at the bottom if you mark a variable: "3 usages of "x" found" if you have defined and used the function. You will also get an orange line underneath unused variables.
4. But I get "y is a variable" when I type which y?
If you get the error above "Undefined function 'y', but which tells you y exists, your error message contains a few more lines:
my_function(x)
Undefined function or variable 'y'.
Error in my_function (line 2)
t = x*y;
>> which y
y is a variable.
What this tells you is that you have a variable called y in your Matlab Workspace (also check this link).
The problem is that functions can't access this workspace:
Functions do not use the base workspace. Every function has its own function workspace.
If you want a function to see and use a variable, you must pass it as an argument. This way the variable will be part of the local workspace for that function. Similarly, if you want variables created inside the function to be accessible outside of the function you must have them as output from the function.
Solution: Pass the variables you want to use as input arguments to the function you use. Make sure the names inside the functions are internally consistent. I.e. it must have the same name throughout the function. Note that there is no connection between the variable names outside and inside the function.
5. But I pass the variable as an input to the function, but I still get the same error message!?
Yes, you probably use the variable as input. However, the variable names are not necessarily the same in different functions (most often they are not).
Suppose you have the function:
function output = my_function(x)
output = 2*y;
end
You'll get the same error as above if you call it from the workspace as in the code below, even though you are using y as input variable, and use y inside the function.
y = 3;
res = my_function(y)
This is because, inside the function my_function, the variable you use as input will be called x, regardless of what it was called outside the function.
Solution: Change the name of the input variable name in the function header, or change the name of the variable throughout the function.
6. But I have created x as a global variable!?
First off: Chances are, if you're reading this post, then you are better off passing variables as arguments rather than using global variables.
It's not enough to declare a variable as global in the Matlab workspace. It must be declared in every function you use it in. So, if you have a global variable x, you need to do global x in every function.
Solution: Rewrite your code and pass variables as arguments instead of using global variables. If this is not an option, add global x in all functions where you're using it.
In addition to this answer, you can refer to the official Matlab FAQ.
I also got
Undefined function '...' for input arguments of type 'double'.
error and I tried the recommendations mentioned above but they could not solve my problem. Then, I realized that there is a special character (*) in my current working directory so I solve the problem when I changed the name of the directory.
Lastly, do not forget to change the current directory after the change operation by using cd argument.
Another way of looking at the problem:
the input arguments should be in an order such that the explanation of the function can read it.

Undefined function or method for input arguments of type 'double' [duplicate]

A question that pops up quite frequently in different shapes and sizes is: Why do I get the following error message:
"Undefined function 'function_name' for input arguments of type 'double'."
This post attempts to address all the different scenarios where this error message can occur, and propose solutions for how it can be resolved.
If you stumble upon this error message and don't know what it means. Take comfort in this: 90% of us have googled the same phrase.
"Undefined function 'int' for input arguments of type 'double'."
The error message is pretty self-explanatory but may still cause confusion. (I chose 'int' at random, it could just as well be 'train', 'table', 'my_function' or anything else).
There are two main cases where this error occurs:
You are trying to use a function that doesn't exist (yet)
You are trying to access an element in a variable that doesn't exist (yet)
What do you do if you get this error?
First, you might want to try which. This will tell you whether or not the function or variable you're trying to use is defined.
which int
'int' not found.
It's quite obvious, that Matlab can't find any functions or variables named int. Trying to use it is therefore futile. Let's compare it to max:
which max
built-in (C:\Program Files\MATLAB\R2014b\toolbox\matlab\datafun\#logical\max) % logical method
But, you might get the following, even if you get the "Undefined function 'x' ...". If so, see point 3 below.
which x
x is a variable.
1. But the function "int" exists! It is even documented here!?
Yes, int exists, but only if you have the Symbolic Toolbox. Since Toolboxes are additional packages that must be purchased separately (and can be quite expensive), chances are you don't have that package.
If you get the "Undefined function" error, but find the function in the documentation, have a look in the menu to the left, or simply check the address. Standard Matlab functions have addresses such as:
mathworks.com/help/matlab/ref/max.html
^^^^^^
Notice the "matlab" part. If you see this, then you are using a function that is part of the core Matlab.
If however, you see an address such as the one below, then the function you are trying to use is part of the Symbolic Toolbox:
mathworks.com/help/symbolic/int.html
^^^^^^^^
or maybe it's part of the Neural Network Toolbox:
mathworks.com/help/nnet/ref/train.html
^^^^
Solution: Find another function that isn't part of a toolbox you don't have. Chances are you'll find what you are looking for if you are a skilled googler. If you can't find it, ask for help. Explain what you have tried, and show that you have done some effort!
2. But the function is documented here, and is part of core Matlab!?
Even though a function is part of the standard Matlab installation, and is well documented, you may still get this error. The most likely cause for this error is that you are using an older version of Matlab. If you check the documentation you'll see the following at the bottom of the page:
Introduced in R2013b
So, if you are using R2012b then you can't use for instance table.
Solution: Check if the function is defined in your version of Matlab. If it's not yet implemented then you either need to update Matlab or find another way to do it. An alternative to table can for instance be to use cells or structs.
3. But the variable "my_variable" exists! I created it in the line above!
No, you didn't. Chances are you created the variable myvariable, my_Variable, my_Variable or something similar in the line above. It's also possible that you have created it, but have accidentally cleared it.
Solution: Go through the code. Look for typos, places where you have accidentally cleared the variable etc. Inside the Matlab editor you will get the following line at the bottom if you mark a variable: "3 usages of "x" found" if you have defined and used the function. You will also get an orange line underneath unused variables.
4. But I get "y is a variable" when I type which y?
If you get the error above "Undefined function 'y', but which tells you y exists, your error message contains a few more lines:
my_function(x)
Undefined function or variable 'y'.
Error in my_function (line 2)
t = x*y;
>> which y
y is a variable.
What this tells you is that you have a variable called y in your Matlab Workspace (also check this link).
The problem is that functions can't access this workspace:
Functions do not use the base workspace. Every function has its own function workspace.
If you want a function to see and use a variable, you must pass it as an argument. This way the variable will be part of the local workspace for that function. Similarly, if you want variables created inside the function to be accessible outside of the function you must have them as output from the function.
Solution: Pass the variables you want to use as input arguments to the function you use. Make sure the names inside the functions are internally consistent. I.e. it must have the same name throughout the function. Note that there is no connection between the variable names outside and inside the function.
5. But I pass the variable as an input to the function, but I still get the same error message!?
Yes, you probably use the variable as input. However, the variable names are not necessarily the same in different functions (most often they are not).
Suppose you have the function:
function output = my_function(x)
output = 2*y;
end
You'll get the same error as above if you call it from the workspace as in the code below, even though you are using y as input variable, and use y inside the function.
y = 3;
res = my_function(y)
This is because, inside the function my_function, the variable you use as input will be called x, regardless of what it was called outside the function.
Solution: Change the name of the input variable name in the function header, or change the name of the variable throughout the function.
6. But I have created x as a global variable!?
First off: Chances are, if you're reading this post, then you are better off passing variables as arguments rather than using global variables.
It's not enough to declare a variable as global in the Matlab workspace. It must be declared in every function you use it in. So, if you have a global variable x, you need to do global x in every function.
Solution: Rewrite your code and pass variables as arguments instead of using global variables. If this is not an option, add global x in all functions where you're using it.
In addition to this answer, you can refer to the official Matlab FAQ.
I also got
Undefined function '...' for input arguments of type 'double'.
error and I tried the recommendations mentioned above but they could not solve my problem. Then, I realized that there is a special character (*) in my current working directory so I solve the problem when I changed the name of the directory.
Lastly, do not forget to change the current directory after the change operation by using cd argument.
Another way of looking at the problem:
the input arguments should be in an order such that the explanation of the function can read it.

Why can't my Perl object find its skip() method, even though I can call it as a subroutine?

I'm working on a Perl module and whenever I call the skip() method I wrote in the following way:
$cursor->skip(4);
I get:
Undefined subroutine &MyModule::Cursor::skip called at t/tester.pl line 24.
(in cleanup) invalid object at t/tester.pl line 24.
When I call it like:
MyModule::Cursor::skip($cursor, 4);
Perl finds it!
Oddly, if I name "skip" anything else ("skipper", "hello"), this syntax works:
$cursor->skipper(4);
I thought maybe skip() was a "secret" reserved key word or something, but I've also got methods named sort() and next() (which I know are reserved), and those work fine.
I'd really like to name this method "skip." Does anyone know why Perl can't find it?
skip() is exported from Test::More, which you might have loaded since your executable is named t/tester.pl.
What does ref($cursor) yield you? It should be a blessed MyModule::Cursor object, but the "invalid object" error might be suggesting the object was not constructed properly.
EDIT: perldiag gives another clue: "in cleanup" signifies that a problem was encountered by the object's destructor. Assuming you don't already have a destructor in the object, create a MyModule::Cursor::DESTROY method that Data::Dumps the object to see what it looks like at this time.
A concise snippet of example code that exhibits this behaviour would be very helpful.
Without actual code, it's difficult to debug this.
Do you use MyModule::Cursor in your test code? When you replaced skip with skipper, were you calling it in exactly the same way from your test module? Are you able to use skip from a throw-away (one-liner or very short script)?
Where I'm going with this is looking for an error in your test code, rather than the module.
UPDATE: You're not doing something like declaring methods on MyModule::Cursor in two different files, are you? The error message you're getting tells me it has a blessed reference to an object of type MyModule::Cursor, so it knows about the class; but then it can't find the definition of skip. Do you happen to declare part of MyModule::Cursor in one file, and skip in another, and your test module isn't including the second file? Or do you have a syntax error somewhere around your definition of skip -- a missing semi-colon or unpaired curly brace? (But then again, why would MyModule::Cursor::skip work where $cursor->skip does not?)