Tue 13 May 2014 06:50:24 PM UTC, original submission:
(verified on default branch, revision 56bff71de2ca (11/05/2014)
The state passed to the user-functions (derivative function and
jacobian function) of lsode has a data location which is directly
written into by lsode. If the user, within the above user-functions, assigns the state to a variable, a reference to this data location is generated. This does no harm for 'automatic' user variables which go out of scope when the user-function returns. But if the user, within the above user-functions, assignes the state to a global or to a persistent variable, the following problems can occur:
1. If the user e.g. enters debug mode within a call to a user-function by lsode and examines the global (or persistent) variable with the state, he sees the new state of the current function call within the global (or persistent), even before the user code has written the state to it. This is because lsode has changed the data in the global (or persistent) variable before calling the user-function, since the global or persistent data is a reference to the state data location within lsode.
2. Since lsode (at least for states with more than 1 element) changes the data at the previous location of the state data even after the last call to the user-functions (verified with a debugger, see below), the content of a global or persistent variable containing the state is not the state of the last call of the user-function, even if the only user code which (unconditionally) sets this global or persistent variable is within the user-function.
Both these problems can occur e.g. if a users tries to debug a
user-function in cases where lsode can not complete the whole
integration. (If one tries to use a global variable to see with which state the user function had been called just before lsode gave up, and then conditionally enters debug mode within the user function to examine the computations.)
The attached files verify problems 1. and 2. above.
You should have a look into the 2 files with Octave code, they are not long. Run 'testscript.m' while 'fdot.m' (the user-function for derivatives for lsode) is in the path. First, you should see the state printed twice during a run of lsode, together with explanations why the observed difference between these printed states is a bug (this verifies problem 1. above). Then a note is printed that you have 5 seconds time to attach a debugger during the last call to 'fdot()' by lsode (which I had done). Then, you should see notes that the bug is triggered for global and persistent variables (after completion of lsode). This is the case when the state of the last call to 'fdot()'
(stored in a separate copy with a trick) is not equal to the state assigned to a global or a persistent variable within 'fdot()' (this verifies problem 2. above).
The edited protocol of a gdb session in 'edited-gdb-protocol' shows that lsode, after the last call to 'fdot()', still modifies the data in the location which was used to pass the state data to 'fdot()' (and which also contains the data of the referencing global and persistent variables).
The problem could be solved in two ways:
- make global and persistent variables always copies of data, not references.
or
- modify Octaves lsode-related code to call user functions with copies of the state. Possibly code related to other solvers than lsode has to be changed, too.
I'd suggest the latter way. I'll request a discussion on the
maintainers list (to possibly reach more maintainers than with the bug tracker).
|