NO

Author Topic: Need info about scopes...  (Read 24695 times)

CommonTater

  • Guest
Need info about scopes...
« on: December 17, 2012, 05:56:16 PM »
If I do this...
Code: [Select]

int testfunc(int x, int y)
  {
     printf("%d  %d", x ,y);
 
     {  // start inner scope
       
       int z;
 
       z = x * y;
 
       printf(" = %d \n", z);
 
     } // end inner scope
 
     puts("Thanks for playing!");
  }

Is there an actual stack cleanup at the end of the inner scope in Pelles C?
 
  It was my understanding that the { bracket would create a stack frame and the } would clean and remove it when done.  But, I've just looked at a couple of dissassemblies of small programs and can't see where it's being done.
« Last Edit: December 17, 2012, 06:00:40 PM by CommonTater »

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: Need info about scopes...
« Reply #1 on: December 17, 2012, 06:02:28 PM »
No Tater, it simply creates different variables, generally temporary allocated in registers or using alloca function.
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

CommonTater

  • Guest
Re: Need info about scopes...
« Reply #2 on: December 17, 2012, 06:09:46 PM »
No Tater, it simply creates different variables, generally temporary allocated in registers or using alloca function.

EDIT....  Well that explains the crash.
 
I just went through a small sample with OllyDbg... it's simply ignoring the braces, far as I can see... It simply allocates everything on function entry and restores the stack on exit.  Although it does follow rules of scope in that the variable is not available outside the braces.
 
 
« Last Edit: December 17, 2012, 07:21:30 PM by CommonTater »

Offline Bitbeisser

  • Global Moderator
  • Member
  • *****
  • Posts: 772
Re: Need info about scopes...
« Reply #3 on: December 17, 2012, 07:33:17 PM »
No Tater, it simply creates different variables, generally temporary allocated in registers or using alloca function.

EDIT....  Well that explains the crash.
 
I just went through a small sample with OllyDbg... it's simply ignoring the braces, far as I can see... It simply allocates everything on function entry and restores the stack on exit.  Although it does follow rules of scope in that the variable is not available outside the braces.
That is what I would have expected in the first place...  ;)

The "scope" is a compiler (logic/parsing) thing only, any stack cleanup will only happen on the exit of the function (testfunc in this case) for all local variables declared within, on any level of "scope".
Kind of logical when you look at it from a CPU/assembler point of view, as it would mean to constantly mess with the stack registers/pointers back and forth, in order to ensure proper access to variables on the stack allocated outside of any deeper level scope but used at any level of scope...

Ralf

CommonTater

  • Guest
Re: Need info about scopes...
« Reply #4 on: December 17, 2012, 08:18:15 PM »
The "scope" is a compiler (logic/parsing) thing only, any stack cleanup will only happen on the exit of the function (testfunc in this case) for all local variables declared within, on any level of "scope".
Kind of logical when you look at it from a CPU/assembler point of view, as it would mean to constantly mess with the stack registers/pointers back and forth, in order to ensure proper access to variables on the stack allocated outside of any deeper level scope but used at any level of scope...

Stack frames are extremely easy to make and break... I believe it's 3 assembler instructions each.  The overhead, on modern computers, would be in nanoseconds and the benefit of cleaning the stack at the end of each scope would be enormous.
 
The image below shows the creation and destruction of a stack frame... It's a total of 4 instructions.

Since at some level all C variables are pointers to memory locations, access beyond current scope is unaffected.  Only the variables in the current stack frame would be deleted when the scope closes... which is fine because the compiler blocks access to them anyway.

But like you say... it's not done, so now I have to review every program I've written since 2004 with this in mind.
« Last Edit: December 17, 2012, 08:40:29 PM by CommonTater »

CommonTater

  • Guest
Re: Need info about scopes...
« Reply #5 on: December 18, 2012, 02:41:11 AM »
Ok... still trying to get a handle on this mess...

This code ....
Code: [Select]
#include <stdio.h>
typedef struct t_test
  {
    char str[256];
    int x;
  } test;
 
typedef struct t_test2
  {
    char str[256];
    int x[2];
  } test2;
 

int main (void)
  {
    puts("Hello");
    {
      test2 t = {0};
      printf("%p\n", &t);
    }
    {
      test u = {0};
      printf("%p\n", &u);
    }

    puts("bye");
    return 0;
  }

Produces different results based on the Optimization settings...
The first image below show us "optimaztions off" on the left and "Minimize size" (actually any optimization) on the right... 
 
It seems that with optimizations on, it does re-use stack space... so now I'm REALLY confused... The econd image shows the main function... it creates a stack frame then appears to reserve a block big enouogh to hold the largest struct and simply re-uses it?  No stack frames... Is that even close to correct?
« Last Edit: December 18, 2012, 03:06:20 AM by CommonTater »

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: Need info about scopes...
« Reply #6 on: December 18, 2012, 08:25:05 AM »
The compiler seems to realise that you are not actually using the structure. Try to assign a string to t, instead of (0).

CommonTater

  • Guest
Re: Need info about scopes...
« Reply #7 on: December 18, 2012, 09:39:08 AM »
The compiler seems to realise that you are not actually using the structure. Try to assign a string to t, instead of (0).

Same results ... 
 
If you look at the way the code is bracketed... the two structs should not exist at the same time.
It's about C's rules of scope and trying to minimize stack usage in a very large function.

 
« Last Edit: December 18, 2012, 09:56:37 AM by CommonTater »

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: Need info about scopes...
« Reply #8 on: December 18, 2012, 10:11:10 AM »
Tater, it simply depend on the optimizing strategy adopted in PellesC compiler.
Any compiler can behave differently, i.e. adding variables on local stack using alloca for dynamic allocation, reuse spaces or registers that has been detected to be mutually used in only one scope at time, and so on.
The more aggressive the optimization the more probable a problem  :o
Anyway an indepth study of PellesC strategy will only lead to a better knowledge of this compiler behaviour (maybe more usefull if want switch to asm programming), but not strictly related to the C language itself.
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: Need info about scopes...
« Reply #9 on: December 18, 2012, 12:10:11 PM »
The compiler seems to realise that you are not actually using the structure. Try to assign a string to t, instead of (0).

Same results ... 

Zip the exe and post it. I seriously doubt that the compiler can use overlapping structures for

      test2 t = {"I am the first string"};
      printf("%p\n", &t);

      test u = {"I am the second string"};
      printf("%p\n", &u);
      printf("%p\n", &t); // use the first string again

CommonTater

  • Guest
Re: Need info about scopes...
« Reply #10 on: December 18, 2012, 02:21:47 PM »
Tater, it simply depend on the optimizing strategy adopted in PellesC compiler.
Any compiler can behave differently, i.e. adding variables on local stack using alloca for dynamic allocation, reuse spaces or registers that has been detected to be mutually used in only one scope at time, and so on.
The more aggressive the optimization the more probable a problem  :o
Anyway an indepth study of PellesC strategy will only lead to a better knowledge of this compiler behaviour (maybe more usefull if want switch to asm programming), but not strictly related to the C language itself.

I hear ya.... I'm just trying to work around infrequent, unexplained crashes in two of my programs (fortunately neither is commercial).  As it turns out these are programs with a large structs, where I've used nested scopes in hope of avoiding stack overflows, believing the variables in the inner scopes were released from the stack at the closing brace.

Thing is the books I learned from both said that variables are released from memory at the end of each scope... now, years later, I'm discovering this isn't always true...  and the "Why?" question is nagging at me...

I need to understand the problem at least well enough to avoid it, hopefully well enough to fix it. 

CommonTater

  • Guest
Re: Need info about scopes...
« Reply #11 on: December 18, 2012, 02:44:39 PM »
Zip the exe and post it. I seriously doubt that the compiler can use overlapping structures for

      test2 t = {"I am the first string"};
      printf("%p\n", &t);

      test u = {"I am the second string"};
      printf("%p\n", &u);
      printf("%p\n", &t); // use the first string again


JJ... in all due respect your code is as different from mine as night and day...
 
In C an opening bracket { signals the beginning of a scope that continues until the matching close bracket } Variables created inside that scope are "encapsulated" by the scope and are unavailable outside the scope... Variables created at larger scope are available inside the smaller scope, except where hidden by a local variable of the same name. 
 
Try this... *with the brackets exactly as I have them*...
Code: [Select]
int main (void)
  {
     {
       int y = 20;
     }
     printf("%d", y);
    return 0;
  }

Unless your compiler is seriously braindead you should get an error at the printf() line saying that y is undefined.  This is because it is encapsulated in it's own little scope...
 
Now back to my original sample:
 
Code: [Select]

#include <stdio.h>

typedef struct t_test
  {
    char str[256];
    int x;
  } test;
 
typedef struct t_test2
  {
    char str[256];
    int x[2];
  } test2;
 
int main (void)
  {
    puts("Hello");
    {                                 <-- begin scope 1
      test2 t = {0};              <-- t is encapsulated
      printf("%p\n", &t);       
    }                                  <-- end scope 1 (Is t destroyed?)
    {                                  <-- new scope 2
      test u = {0};                <-- u is encapsulated
      printf("%p\n", &u);
    }                                   <-- end scope 2 (Is u destroyed?)
    puts("bye");
    return 0;

You cannot access either t or u outside it's own scope. Moreover; since each is in it's own private scope, the two structs should not exist in memory at the same time. The only question here is whether there is a stack cleanup --releasing the space occupied by the structs-- at the end of each scope...
 
In terms of stack usuage, it should be functionally equivalent to...
Code: [Select]
int main (void)
  {
    puts("Hello");

    test2* t = calloc(1, sizeof(test2));                               
    printf("%p\n", &t);       
    free(t);
 
    test* u = calloc(1, sizeof(test));                               
    printf("%p\n", &u);       
    free(u);
 
    puts("bye");
    return 0;
And has the additional benefit of encapsulating large segments of unrelated data.
 
In the particular problem I'm having, I've written a long function (~ 200 lines) that doesn't seem to want to break up into smaller functions easily; I would have to pass a dozen or more parameters each time... The program crashes near the end of this function in an apparent stack overflow that should not happen if the variables are being removed (released, overwritten, re-used...) at the end of each of the scopes within the function as they should.
« Last Edit: December 18, 2012, 02:56:07 PM by CommonTater »

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: Need info about scopes...
« Reply #12 on: December 18, 2012, 05:04:44 PM »
Tater if you defined large structures local to scopes inside the same function they are created on the stack.
Your problem can be a stack corruption if you write beyond the structure (bad pointer), a stack overflow if data structures are too large or optimization problem.
Knowing you I am sure that you already recompiled everything with no optimization  ;D
Remains the other two options.
If you are sure that there is no pointers error, try to increase stack allocation using the switch /STACK on the linker.
It would be good to see a disassembly output of your function to analyze the problem, but if the source is 200 lines....   :P
« Last Edit: December 18, 2012, 05:06:24 PM by frankie »
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: Need info about scopes...
« Reply #13 on: December 18, 2012, 05:45:23 PM »
Variables created inside that scope are "encapsulated" by the scope and are unavailable outside the scope...
Point taken.

Quote
since each is in it's own private scope, the two structs should not exist in memory at the same time. The only question here is whether there is a stack cleanup --releasing the space occupied by the structs-- at the end of each scope...
That could be easily verified with Olly. Your screenshots seem to show that the stack is OK. However, I could imagine that the optimising compiler does not create the stack frame twice because it "knows" that a single frame for the bigger of the two strucs is enough. A strategy that saves size and cycles, and should not pose any problems under normal conditions. Can you reproduce a situation where this leads to a crash?

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: Need info about scopes...
« Reply #14 on: December 18, 2012, 05:55:50 PM »
The stack frame is created *only* for function call.
Local variables are created and destroyed inside the *current* frame.
EBP register points always to function call frame creation point, this is consistent with stack unroll of exception handler (slightly modifyied for 64bits programs).
No frame is created and never will be to avoid any mess with stack handling.
If any stack extension is required for local variables, scoped or not, is handled through use of alloca() function.
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide