NO

Author Topic: Variable changes in between functions (out of bounds?)  (Read 13121 times)

PaulM.

  • Guest
Variable changes in between functions (out of bounds?)
« on: March 28, 2012, 02:20:50 PM »
Hi,

I have a function called Verlet_integration(), that requires a counter as an input variable, along with some other variables. This counter is an integer called 'count_nodes' and the value of it is 96.
Within that function, I call for five other functions in this order: Positions(), Int_velocities(), Forces(), Accelerations() and Velocities(). All of these functions, except for Forces(), require the counter as an input argument.

However, in between the functions Forces() and Accelerations(), the variable 'count_nodes' for some reason becomes 1178657792 - always the same number.
If I disable Forces() everything works fine, so it has to be somewhere within that function. But the weird thing is if I print the value at the end of Forces(), just before its return, the counter is still 96 - see code below.
I cannot find the mistake I have made. I tried comparing the current version with an older but working version using UltraCompare, but I could not find the mistake and I don't know how to find the problem.

Hopefully someone can give me some directions to track down the problem.


Code: [Select]
/*******************************************************************
*
* Function : Verlet_integration()
* Purpose : Output node-coördinates to XML-file
* External file : lib_time.c
*
*******************************************************************/

int Verlet_integration (
Node* Nodes ,
Link* Links ,
Head* Paul ,
int count_nodes ,
int count_links )
{
float iv_x[count_nodes];
float iv_y[count_nodes];

// Step 1 : Calculate new positions
Positions( Nodes, Paul, count_nodes );

// Step 2 : Intermediate velocities
Int_velocities( Nodes, Paul, count_nodes, iv_x, iv_y );

// Step 3 : Forces (pressure, springs, drag)
if ( Forces( Nodes, Links, Paul, count_nodes, count_links ) != 0 )
{
return 1;
}

printf("%i\n", count_nodes); // Returns 1178657792
// Step 4 : Accelerations
Accelerations( Nodes, Paul, count_nodes );

// Step 5 : Update velocities
Velocities( Nodes, Paul, count_nodes, iv_x, iv_y );

return 0;

}


Code: [Select]
/*******************************************************************
*
* Function : Forces
* Purpose : Forces on nodes
*
*******************************************************************/
int Forces (
Node* Nodes ,
Link* Links ,
Head* Paul ,
int count_nodes ,
int count_links )
{

float rho    = RHO;
float vsound = V_SOUND;

int node1;
int node2;
float k; // Stiffness
float perm; // Permeability
float length; // Length of link
float strain; // Strain
float rx; // Length-vector
float ry;
float tx; // Tangential vector
float ty;
float nx; // Normal vector
float ny;
float fp_x; // Force-vector due to pressure
float fp_y;
float fs_x; // Springforce vector
float fs_y;
float avx; // Average velocity of link
float avy;
float fd_x; // Drag force due to pressure drag
float fd_y;
float sum_x1; // Sumvector for Node 1
float sum_y1;
float sum_x2; // Sumvector for Node 2
float sum_y2;
Force Fc[count_nodes+1]; // Forces due to impact

int j;


Fc[count_nodes+1].x = 12345; // Set check-number


// Turn this off for testing
CheckImpact(Nodes, Paul, Fc, count_nodes);

// Safety check
if ( Fc[count_nodes+1].x != 12345 )
{
printf("Bounds exceeded for Fc.\n");
return 1;
}


for ( j = 0; j < count_links; j++ )
{

node1 = Links[j].node1;
node2 = Links[j].node2;
k = Links[j].k;
perm = Links[j].perm;

rx = Nodes[node2].r_x - Nodes[node1].r_x; // Vector in link-direction
ry = Nodes[node2].r_y - Nodes[node1].r_y;
length = sqrt( pow(rx,2) + pow(ry,2) ); // Length of link

tx = rx / length; // Tangential vector
ty = ry / length;
nx = ty; // Normal vector n = R * t with R = [0 1; -1 0]
ny = -tx;


// Return 1 if vectors > 1 (impossible)
if ( sqrt( pow(tx,2) + pow(ty, 2) ) > 1.001 || sqrt( pow(nx,2) + pow(ny, 2) ) > 1.001)
{
printf("[%f %f]  [%f %f]\n", tx, ty, nx, ny);
printf("%f %f\n", sqrt( pow(tx,2) + pow(ty, 2) ), sqrt( pow(nx,2) + pow(ny, 2) ) );
return 1;
}


// Pressure
fp_x = 0.5 * 4000 * length * nx;
fp_y = 0.5 * 4000 * length * ny;
//fp_x = 0;
//fp_y = 0;


// Springs
// F = k * strain * t
strain = ( length / Links[j].l0 ) - 1;
fs_x = k * strain * tx;
fs_y = k * strain * ty;
//fs_x = 0;
//fs_y = 0;


// Drag forces
// Fd = rho * vsound * v * L * n
// Turn off for testing
avx = 0.5 * (Nodes[node1].v_x + Nodes[node2].v_x) * nx;
avy = 0.5 * (Nodes[node1].v_y + Nodes[node2].v_y) * ny;

fd_x = - 0.5 * rho * vsound * length * avx * nx;
fd_y = - 0.5 * rho * vsound * length * avy * ny;

//fd_x = 0;
//fd_y = 0;

// Sum of forces
sum_x1 = (1 - perm)*(fp_x + fd_x) + fs_x + Fc[node1].x;
sum_y1 = (1 - perm)*(fp_y + fd_y) + fs_y + Fc[node1].y;

sum_x2 = (1 - perm)*(fp_x + fd_x) - fs_x + Fc[node2].x;
sum_y2 = (1 - perm)*(fp_y + fd_y) - fs_y + Fc[node2].y;


// Store sum of forces to linked nodes
Nodes[node1].f_x = Nodes[node1].f_x + sum_x1;
Nodes[node1].f_y = Nodes[node1].f_y + sum_y1;

Nodes[node2].f_x = Nodes[node2].f_x + sum_x2;
Nodes[node2].f_y = Nodes[node2].f_y + sum_y2;

}
printf("%i\n", count_nodes); // Returns 96, as it is supposed to
return 0;
}

CommonTater

  • Guest
Re: Variable changes in between functions (out of bounds?)
« Reply #1 on: March 28, 2012, 04:24:14 PM »
Try a little experiment...  Go into your project options and try recompiling with Optimizations set to "None".

Also, set your Warning level to 2 and  be sure to clear out any non-referenced variables you may have... the compiler's report at the bottom should warn you about it.

This may or may not fix the problem, but there is a known bug in the new register-allocator (added at ver 6.0) that does cause problems similar to this.  (Look in the bug reports forum.)



Offline Bitbeisser

  • Global Moderator
  • Member
  • *****
  • Posts: 772
Re: Variable changes in between functions (out of bounds?)
« Reply #2 on: March 28, 2012, 04:44:22 PM »
Also for an other little experiment, change the variable name for the argument from count_nodes to c_n for example...

Ralf

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2096
Re: Variable changes in between functions (out of bounds?)
« Reply #3 on: March 28, 2012, 06:26:05 PM »
Paul make a check on compilation switches. The only possible cause that I can think of, looking at the code, is that Forces is compiloed as __stdcall and clean the calling stack from himself, but it is called as __cdecl implying another stack cleaning. In this way you remove your original arguments and stack relative addressing reads somewhere else in memory. Anyway if this is the issue also the other parameters should be wrong unless the previous calling function have the same stack parametres again.
It is better to be hated for what you are than to be loved for what you are not. - Andre Gide

PaulM.

  • Guest
Re: Variable changes in between functions (out of bounds?)
« Reply #4 on: March 29, 2012, 12:10:59 AM »
Try a little experiment...  Go into your project options and try recompiling with Optimizations set to "None".

Also, set your Warning level to 2 and  be sure to clear out any non-referenced variables you may have... the compiler's report at the bottom should warn you about it.

This may or may not fix the problem, but there is a known bug in the new register-allocator (added at ver 6.0) that does cause problems similar to this.  (Look in the bug reports forum.)
I did this and it worked again! To check, I re-set the options to default and the program crashed again. Could this be the only cause of this? If it is I can tell my tutors that the bug is causing this, otherwise I will have to find the real cause. (I use version 6.50.8 by the way).

Also for an other little experiment, change the variable name for the argument from count_nodes to c_n for example...
I changed the input argument to "c_n" for all the functions within the Verlet_integration(), and in Verlet_integration() itself, but no succes.

Paul make a check on compilation switches. The only possible cause that I can think of, looking at the code, is that Forces is compiloed as __stdcall and clean the calling stack from himself, but it is called as __cdecl implying another stack cleaning. In this way you remove your original arguments and stack relative addressing reads somewhere else in memory. Anyway if this is the issue also the other parameters should be wrong unless the previous calling function have the same stack parametres again.
If I get it right, I have to check how my functions are called because Forces() might be called for wrongly? How do I check this?


Thanks for the help so far!
« Last Edit: March 29, 2012, 12:13:36 AM by PaulM. »

CommonTater

  • Guest
Re: Variable changes in between functions (out of bounds?)
« Reply #5 on: March 29, 2012, 05:08:59 AM »
I did this and it worked again! To check, I re-set the options to default and the program crashed again. Could this be the only cause of this? If it is I can tell my tutors that the bug is causing this, otherwise I will have to find the real cause. (I use version 6.50.8 by the way).

I suspected as much... What Pelle is doing (as far as I understand it) is using extra CPU registers to hold some variables but in some cases (certainly not all) the registers are being corrupted and we end up with "magic numbers" because of it.  Setting optimizations to "none" disables the register allocator and stops the problem.  There is a slight performance hit... but when the alternative is that it doesn't work at all...
 
(I'm hoping Pelle will have it fixed in the next version...)
 
Quote
If I get it right, I have to check how my functions are called because Forces() might be called for wrongly? How do I check this?

It's on the project settings -> compiler page, along with the optimizations setting.  The thing is to be consistent ... You can read up on the various calling conventions in the apendix to the help file.  (Just push F1, inside the IDE...)  Generally... if you are working console mode with no Windows libraries _cdecl makes the most sense.  If you are using Windows API calls or external libraries, _stdcall will probably make more sense.  If you are working 64 bit code, the only available convention is _fastcall.
 
Main always has to be _cdecl ... so you can write this:
Code: [Select]
int _cdecl main (void)
  {
    // stuff
    return 0; }
... if you are setting your calls to _stdcall
 
Frankie is much more knowledgeable about calling conventions than I... so I'll defer to him for the finer points.
 
 
 
 
 

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2096
Re: Variable changes in between functions (out of bounds?)
« Reply #6 on: March 29, 2012, 12:41:11 PM »
The default calling convention for a project is set in project->project_options than compiler tab. It applies to all functions that do not have an explicit calling convention declaration. If your modules (.c files) are compiled together using an IDE project it is not probable that they are compiled with different conventions, but not impossible (wrong declaration in header files that are not included in the respective source files so the compiler cannot make any compliance check). More easy to happen if you compiled each module from command line with different switches.
What I suggest to restrict the problem investigation is:
Try to remove (convert to comment) as much as possible of the problematic function so to live only the minimum code that trigger the problem and post a simplified project that permit us to reproduce it. Unless you are able to check the generated assembler by yourself and find the wrong.
About the calling conventions the standard __cdecl push all function parameters on the stack, the caller function have to clean the stack after the called function returned. This mechanism is required for variable parameters functions available with C language (the called function don't know at the compile time how many parameters has been passed while the caller knows). The disadvantage is that the compiler cannot use more efficient machine code instruction (like retn where you can specify how much stack remove on return) that clean stack faster. M$ invented than the __stdcall specifically for Win programs, using it the first two 32 bits arguments (integers, pointer, etc) are passed via registers (eax and edx) the others by stack, on return the stack is cleaned by retn instruction.
__stdcall convention doesn't allow variable number of aguments (if you try the compiler will give you a warning and automatically convert it to __cdecl).
« Last Edit: March 29, 2012, 12:45:55 PM by frankie »
It is better to be hated for what you are than to be loved for what you are not. - Andre Gide

PaulM.

  • Guest
Re: Variable changes in between functions (out of bounds?)
« Reply #7 on: March 29, 2012, 01:53:48 PM »
Thanks for the explanation, Frankie. The calling convention in the project is by default set to "__cdecl". However going into the aspect of the calling conventions goes way beyond the scope of the assignment.
Setting the Optimizations to "None" has solved the problem, so we're going to stick with that.

Thanks for the help!

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2096
Re: Variable changes in between functions (out of bounds?)
« Reply #8 on: March 29, 2012, 02:34:50 PM »
I'm happy to know that this solved your assignement, but doesn't helped us to find and correct compiler bug.
We will be gratefuls if you'll contribute with what asked for the sake of compiler improvement.
It is better to be hated for what you are than to be loved for what you are not. - Andre Gide

CommonTater

  • Guest
Re: Variable changes in between functions (out of bounds?)
« Reply #9 on: March 29, 2012, 06:41:59 PM »
Thanks for the explanation, Frankie. The calling convention in the project is by default set to "__cdecl". However going into the aspect of the calling conventions goes way beyond the scope of the assignment.
Setting the Optimizations to "None" has solved the problem, so we're going to stick with that.

Like Friankie, I'm very happy to see your problem is solved.  As you mentioned earlier you should advise your tutors this is a "known issue" with the POCC compiler and that setting optimizations to "None" will mask the problem.  You can refer them to this thread and the bug reports section of this forum... a fair bit is known about it.

While this is a known problem with the compiler it is not certain that all aspects of it are known... For example: Is it CPU specific? I use an AMD64 x2 processor... does it also affect Intel?
 
I would encourage you to continue on (on your own, if need be) and concoct the smallest bit from your code that demonstrates the problem and post it as a bug report so that more is known about it.  An interesting oddity in our world is that most program bugs are found by inexperienced operators... who tend to do stuff we'd never consider  ???

For now, continue to compile your projects with Optimizations off and you should do fine.

Good luck on your course....  The world needs more people who C.
 

PaulM.

  • Guest
Re: Variable changes in between functions (out of bounds?)
« Reply #10 on: March 29, 2012, 06:56:51 PM »
I will post the project later tonight.

I would encourage you to continue on (on your own, if need be) and concoct the smallest bit from your code that demonstrates the problem and post it as a bug report so that more is known about it.  An interesting oddity in our world is that most program bugs are found by inexperienced operators... who tend to do stuff we'd never consider  ???

Isn't that Murphy's Law? ;)

CommonTater

  • Guest
Re: Variable changes in between functions (out of bounds?)
« Reply #11 on: March 29, 2012, 07:37:23 PM »
Isn't that Murphy's Law? ;)

Yep, sure is :D .... "Anything that can go wrong, will go wrong."
 
And don't forget Erzats law: "When given the opportunity to do something stupid, most people will."
 
Ours is probably the only profession that counts on this kind of stuff to produce a better product.
« Last Edit: March 29, 2012, 07:39:16 PM by CommonTater »

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2096
Re: Variable changes in between functions (out of bounds?)
« Reply #12 on: March 29, 2012, 07:55:15 PM »
To write foolproof code we need some to to certify the product.......  ;)
It is better to be hated for what you are than to be loved for what you are not. - Andre Gide

CommonTater

  • Guest
Re: Variable changes in between functions (out of bounds?)
« Reply #13 on: March 29, 2012, 08:04:01 PM »
:D  Good one Frankie! :D

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2096
Re: Variable changes in between functions (out of bounds?)
« Reply #14 on: March 29, 2012, 08:14:52 PM »
And I can add:
more seriously they take their job ..... most apt they are at it  ;)
« Last Edit: March 29, 2012, 08:22:12 PM by frankie »
It is better to be hated for what you are than to be loved for what you are not. - Andre Gide