'static' : strange behavior

Discussion in 'C Programming' started by Mark, Dec 28, 2010.

  1. Mark

    Mark Guest

    I'm working with a code (not mine) on embedded MIPS platform and ran across
    a weird behavior. I have a function:

    int nvram_init(void *si)
    {
    static int nvram_status = -1;
    ...
    }

    This function gets called only at one place of the firmware, what really
    strange is that output value of 'nvram_status' at the very beginning of the
    'nvram_init()' is always 0.

    As per my knowledge, a variable declared 'static' withing a function's body
    must maintain it value between the function's calls, but it doesn't seem to
    be the case here! Should I be looking for some hardware/compiler specific
    trick, or I'm missing something more trivial?

    --
    Mark
     
    Mark, Dec 28, 2010
    #1
    1. Advertising

  2. Mark

    Ian Collins Guest

    On 12/28/10 02:57 PM, Mark wrote:
    > I'm working with a code (not mine) on embedded MIPS platform and ran
    > across a weird behavior. I have a function:
    >
    > int nvram_init(void *si)
    > {
    > static int nvram_status = -1;
    > ...
    > }
    >
    > This function gets called only at one place of the firmware, what really
    > strange is that output value of 'nvram_status' at the very beginning of
    > the 'nvram_init()' is always 0.


    Two questions, what do you mean by "at the very beginning" and how do
    you know?

    > As per my knowledge, a variable declared 'static' withing a function's
    > body must maintain it value between the function's calls, but it doesn't
    > seem to be the case here! Should I be looking for some hardware/compiler
    > specific trick, or I'm missing something more trivial?


    It should.

    --
    Ian Collins
     
    Ian Collins, Dec 28, 2010
    #2
    1. Advertising

  3. Mark

    Eric Sosman Guest

    On 12/27/2010 8:57 PM, Mark wrote:
    > I'm working with a code (not mine) on embedded MIPS platform and ran
    > across a weird behavior. I have a function:
    >
    > int nvram_init(void *si)
    > {
    > static int nvram_status = -1;
    > ...
    > }
    >
    > This function gets called only at one place of the firmware, what really
    > strange is that output value of 'nvram_status' at the very beginning of
    > the 'nvram_init()' is always 0.


    How do you know this? (See below.)

    > As per my knowledge, a variable declared 'static' withing a function's
    > body must maintain it value between the function's calls, but it doesn't
    > seem to be the case here! Should I be looking for some hardware/compiler
    > specific trick, or I'm missing something more trivial?


    Yes, a `static' variable retains its last-stored[*] value from
    one function call to the next, or more generally from one assignment
    to the next. If there has been no assignment, the `static' variable
    holds it initialization value, or "the right kind of zero" if there
    is no initializer. Based on what you've shown, `nvram_status' should
    have the value minus one the first time nvram_init() is called. I
    therefore suspect that you have not shown everything that's relevant.
    In particular, you haven't shown how you determine the original value
    of `nvram_status' -- and it's possible that the determination itself
    might be at fault.

    [*] For a `volatile' variable, "last-stored" might not be a visible
    action of the program: a hardware clock or some such might "store" a
    new value in the variable without an explicit assignment by the program.
    However, `nvram_status' is not `volatile', so we need not consider that
    potential complication.


    --
    Eric Sosman
    lid
     
    Eric Sosman, Dec 28, 2010
    #3
  4. Mark

    Mark Guest

    Eric Sosman wrote:
    > Yes, a `static' variable retains its last-stored[*] value from
    > one function call to the next, or more generally from one assignment
    > to the next. If there has been no assignment, the `static' variable
    > holds it initialization value, or "the right kind of zero" if there
    > is no initializer. Based on what you've shown, `nvram_status' should
    > have the value minus one the first time nvram_init() is called. I
    > therefore suspect that you have not shown everything that's relevant.
    > In particular, you haven't shown how you determine the original value
    > of `nvram_status' -- and it's possible that the determination itself
    > might be at fault.


    I print the value of 'nvram_status', below is more complete snippet:

    int nvram_init (void *si)
    {
    int ret;
    static int nvram_status = -1;

    printf("%s : nvram_status=%d\n", __FUNCTION__, nvram_status); /* my
    line */

    if (nvram_status == 1) /* the very first statement in the original code
    */
    return 1;

    /* low-level initializations of NVRAM */
    /* nvram_status can be altered down here */
    ...
    }

    > [*] For a `volatile' variable, "last-stored" might not be a
    > visible action of the program: a hardware clock or some such might
    > "store" a new value in the variable without an explicit assignment by
    > the program. However, `nvram_status' is not `volatile', so we need
    > not consider that potential complication.



    --
    Mark
     
    Mark, Dec 28, 2010
    #4
  5. Mark

    Mark Guest

    Ian Collins wrote:
    >> This function gets called only at one place of the firmware, what
    >> really strange is that output value of 'nvram_status' at the very
    >> beginning of the 'nvram_init()' is always 0.

    >
    > Two questions, what do you mean by "at the very beginning" and how do
    > you know?


    See my reply to Eric Sosman.

    --
    Mark
     
    Mark, Dec 28, 2010
    #5
  6. Mark

    Ian Collins Guest

    On 12/28/10 03:24 PM, Mark wrote:
    > Eric Sosman wrote:
    >> Yes, a `static' variable retains its last-stored[*] value from
    >> one function call to the next, or more generally from one assignment
    >> to the next. If there has been no assignment, the `static' variable
    >> holds it initialization value, or "the right kind of zero" if there
    >> is no initializer. Based on what you've shown, `nvram_status' should
    >> have the value minus one the first time nvram_init() is called. I
    >> therefore suspect that you have not shown everything that's relevant.
    >> In particular, you haven't shown how you determine the original value
    >> of `nvram_status' -- and it's possible that the determination itself
    >> might be at fault.

    >
    > I print the value of 'nvram_status', below is more complete snippet:
    >
    > int nvram_init (void *si)
    > {
    > int ret;
    > static int nvram_status = -1;
    >
    > printf("%s : nvram_status=%d\n", __FUNCTION__, nvram_status); /* my line */
    >
    > if (nvram_status == 1) /* the very first statement in the original code */
    > return 1;


    Why do you set the value to -1 and test for 1?

    --
    Ian Collins
     
    Ian Collins, Dec 28, 2010
    #6
  7. Mark

    Mark Guest

    Ian Collins wrote:
    >> int nvram_init (void *si)
    >> {
    >> int ret;
    >> static int nvram_status = -1;
    >>
    >> printf("%s : nvram_status=%d\n", __FUNCTION__, nvram_status); /* my
    >> line */
    >>
    >> if (nvram_status == 1) /* the very first statement in the original
    >> code */ return 1;

    >
    > Why do you set the value to -1 and test for 1?


    I don't; as I mentioned earlier this is not my code.

    --
    Mark
     
    Mark, Dec 28, 2010
    #7
  8. Mark

    Eric Sosman Guest

    On 12/27/2010 9:24 PM, Mark wrote:
    > Eric Sosman wrote:
    >> Yes, a `static' variable retains its last-stored[*] value from
    >> one function call to the next, or more generally from one assignment
    >> to the next. If there has been no assignment, the `static' variable
    >> holds it initialization value, or "the right kind of zero" if there
    >> is no initializer. Based on what you've shown, `nvram_status' should
    >> have the value minus one the first time nvram_init() is called. I
    >> therefore suspect that you have not shown everything that's relevant.
    >> In particular, you haven't shown how you determine the original value
    >> of `nvram_status' -- and it's possible that the determination itself
    >> might be at fault.

    >
    > I print the value of 'nvram_status', below is more complete snippet:
    >
    > int nvram_init (void *si)
    > {
    > int ret;
    > static int nvram_status = -1;
    >
    > printf("%s : nvram_status=%d\n", __FUNCTION__, nvram_status); /* my line */
    >
    > if (nvram_status == 1) /* the very first statement in the original code */
    > return 1;
    >
    > /* low-level initializations of NVRAM */
    > /* nvram_status can be altered down here */
    > ...
    > }


    It seems you like to dispense information drop by precious drop,
    one tiny tidbit at a time. If the information is so very private that
    you dare not share it except in meaningless driblets -- well, I have
    never been known as a patient man, and I think I've got better things
    to do than spend time wheedling details from a coy Twenty Questions
    player.

    If and when you want help from me, provide sufficient information
    to get my analysis started. Until then, I've got more pressing matters
    to attend to -- it's been *ages* since I last plucked my eyebrows.

    --
    Eric Sosman
    lid
     
    Eric Sosman, Dec 28, 2010
    #8
  9. Re: 'static' : strange behavior

    On Dec 28, 7:24 am, "Mark" <> wrote:
    > Eric Sosman wrote:
    > >     Yes, a `static' variable retains its last-stored[*] value from
    > > one function call to the next, or more generally from one assignment
    > > to the next.  If there has been no assignment, the `static' variable
    > > holds it initialization value, or "the right kind of zero" if there
    > > is no initializer.  Based on what you've shown, `nvram_status' should
    > > have the value minus one the first time nvram_init() is called.  I
    > > therefore suspect that you have not shown everything that's relevant.
    > > In particular, you haven't shown how you determine the original value
    > > of `nvram_status' -- and it's possible that the determination itself
    > > might be at fault.

    >
    > I print the value of 'nvram_status', below is more complete snippet:
    >
    > int nvram_init (void *si)
    > {
    >     int ret;
    >     static int nvram_status = -1;
    >
    >     printf("%s : nvram_status=%d\n", __FUNCTION__, nvram_status);  /* my
    > line */
    >
    >     if (nvram_status == 1)  /* the very first statement in the original code
    > */
    >         return 1;
    >
    >     /* low-level initializations of NVRAM */
    >     /* nvram_status can be altered down here */
    >     ...
    >
    > }
    > >     [*] For a `volatile' variable, "last-stored" might not be a
    > > visible action of the program: a hardware clock or some such might
    > > "store" a new value in the variable without an explicit assignment by
    > > the program. However, `nvram_status' is not `volatile', so we need
    > > not consider that potential complication.

    >
    > --
    > Mark


    I tried the same program i got -1 as output for all try. i have seen
    no weird behavior.

    nvram_init : nvram_status=-1
    nvram_init : nvram_status=-1
    nvram_init : nvram_status=-1
    nvram_init : nvram_status=-1
    nvram_init : nvram_status=-1
    nvram_init : nvram_status=-1
    nvram_init : nvram_status=-1
    nvram_init : nvram_status=-1
    nvram_init : nvram_status=-1
    nvram_init : nvram_status=-1

    Mark you can give some more information like compiler and may be
    optimization that you are trying So that some people can better
    analyze the problem
     
    Shivanand Kadwadkar, Dec 28, 2010
    #9
  10. Mark

    Mark Guest

    Eric Sosman wrote:
    > It seems you like to dispense information drop by precious drop,
    > one tiny tidbit at a time. If the information is so very private that
    > you dare not share it except in meaningless driblets -- well, I have
    > never been known as a patient man, and I think I've got better things
    > to do than spend time wheedling details from a coy Twenty Questions
    > player.


    :)
    Appreciate your delightful sense of humour, it indeed cheered me up. The
    information isn't private at all, at first I thought the function is pretty
    lengthy to be posted here, therefore I provided just a snippet as you asked.
    I've posted the source of the routine under question at
    http://clc.pastebin.com/f4FRqgit

    --
    Mark
     
    Mark, Dec 28, 2010
    #10
  11. Mark

    Ike Naar Guest

    On 2010-12-28, Mark <> wrote:
    > I've posted the source of the routine under question at
    > http://clc.pastebin.com/f4FRqgit


    Unfortunately that code is uncompilable. It needs types (e.g. si_t)
    that you haven't provided. Also, you don't show how the nvram_init
    function is called from its environment.
    Given the behaviour that you're seeing, it's not unlikely that there
    is an error elsewhere in your program (outside the nvram_init function).
    Please provide a minimal, but complete program that exhibits the
    problematic behaviour, that we can compile and run.
     
    Ike Naar, Dec 28, 2010
    #11
  12. On 28/12/2010 03:24, Mark wrote:
    > Eric Sosman wrote:
    >> Yes, a `static' variable retains its last-stored[*] value from
    >> one function call to the next, or more generally from one assignment
    >> to the next. If there has been no assignment, the `static' variable
    >> holds it initialization value, or "the right kind of zero" if there
    >> is no initializer. Based on what you've shown, `nvram_status' should
    >> have the value minus one the first time nvram_init() is called. I
    >> therefore suspect that you have not shown everything that's relevant.
    >> In particular, you haven't shown how you determine the original value
    >> of `nvram_status' -- and it's possible that the determination itself
    >> might be at fault.

    >
    > I print the value of 'nvram_status', below is more complete snippet:
    >
    > int nvram_init (void *si)
    > {
    > int ret;
    > static int nvram_status = -1;
    >
    > printf("%s : nvram_status=%d\n", __FUNCTION__, nvram_status); /* my line */
    >
    > if (nvram_status == 1) /* the very first statement in the original code */
    > return 1;
    >
    > /* low-level initializations of NVRAM */
    > /* nvram_status can be altered down here */
    > ...
    > }
    >
    >> [*] For a `volatile' variable, "last-stored" might not be a
    >> visible action of the program: a hardware clock or some such might
    >> "store" a new value in the variable without an explicit assignment by
    >> the program. However, `nvram_status' is not `volatile', so we need
    >> not consider that potential complication.


    In some embedded environments, initialization of static and global
    variables can be disabled or enabled depending on linking options
    or input. One good reason is to be able to perform things quickly
    enough before main() [hardware setup, RAM test, unamit]. Sometime,
    this initialization is replaced or superseded by a "zero all RAM"
    procedure. That would explain the behavior.

    As an alternative, could it be the case that the debugging with
    printf works only after a while, or not in the context where the
    first nvram_init happens, so that first call is missed?

    Francois Grieu
     
    Francois Grieu, Dec 28, 2010
    #12
  13. Mark

    Nick Guest

    "Mark" <> writes:

    > Eric Sosman wrote:
    >> Yes, a `static' variable retains its last-stored[*] value from
    >> one function call to the next, or more generally from one assignment
    >> to the next. If there has been no assignment, the `static' variable
    >> holds it initialization value, or "the right kind of zero" if there
    >> is no initializer. Based on what you've shown, `nvram_status' should
    >> have the value minus one the first time nvram_init() is called. I
    >> therefore suspect that you have not shown everything that's relevant.
    >> In particular, you haven't shown how you determine the original value
    >> of `nvram_status' -- and it's possible that the determination itself
    >> might be at fault.

    >
    > I print the value of 'nvram_status', below is more complete snippet:
    >
    > int nvram_init (void *si)
    > {
    > int ret;
    > static int nvram_status = -1;
    >
    > printf("%s : nvram_status=%d\n", __FUNCTION__, nvram_status); /*
    > my line */
    >
    > if (nvram_status == 1) /* the very first statement in the original
    > code */
    > return 1;
    >
    > /* low-level initializations of NVRAM */
    > /* nvram_status can be altered down here */


    I'd place a small bet that something somewhere else, that is executed
    before nvram_init is called, has overwriten the space where nvram_status
    is stored.

    Because it's a static variable the compiler will have most likely
    allocated it space as though it was a "global" variable - it just
    restricts the scope the name is known in.

    So if elsewhere you have something like:

    char *fred;
    ....
    int main(void) {
    ....
    strcpy(fred,"test");

    that could well be blowing you your nvram_status
    --
    Online waterways route planner | http://canalplan.eu
    Plan trips, see photos, check facilities | http://canalplan.org.uk
     
    Nick, Dec 28, 2010
    #13
  14. Mark

    BartC Guest

    "Mark" <> wrote in message
    news:ifbo5s$bnb$...
    > Eric Sosman wrote:
    >> It seems you like to dispense information drop by precious drop,
    >> one tiny tidbit at a time. If the information is so very private that
    >> you dare not share it except in meaningless driblets -- well, I have
    >> never been known as a patient man, and I think I've got better things
    >> to do than spend time wheedling details from a coy Twenty Questions
    >> player.

    >
    > :)
    > Appreciate your delightful sense of humour, it indeed cheered me up. The
    > information isn't private at all, at first I thought the function is
    > pretty lengthy to be posted here, therefore I provided just a snippet as
    > you asked. I've posted the source of the routine under question at
    > http://clc.pastebin.com/f4FRqgit


    Since your printf statement also shows the address of nvram_status, and
    assuming this will be consistent, try using that address to print the value
    of nvram_status outside, and before calling, nvram_init. (Or just
    temporarily move nvram_status outside the function.)

    Or add the line nvram_status=-1 just after it's declaration; normally this
    will be unnecessary. If it's value now is printed as -1, that suggests a
    problem elsewhere.

    (Or, just before it's declaration, perhaps add the line:

    static int dummy=1234;

    and try printing that in your printf() too, to see if has a similiar fate.)

    Also, nvram_init() appears to be called recursively, which is unusual for
    this sort of function. Probably not the cause of this bug, but I can see
    subtle problems creeping in because each different invocation of
    nvram_init() is modifying the same static variable.

    --
    Bartc
     
    BartC, Dec 28, 2010
    #14
  15. Mark

    James Kuyper Guest

    On 12/27/2010 11:13 PM, Mark wrote:
    > Eric Sosman wrote:
    >> It seems you like to dispense information drop by precious drop,
    >> one tiny tidbit at a time. If the information is so very private that
    >> you dare not share it except in meaningless driblets -- well, I have
    >> never been known as a patient man, and I think I've got better things
    >> to do than spend time wheedling details from a coy Twenty Questions
    >> player.

    >
    > :)
    > Appreciate your delightful sense of humour, it indeed cheered me up. The
    > information isn't private at all, at first I thought the function is
    > pretty lengthy to be posted here, therefore I provided just a snippet as
    > you asked. I've posted the source of the routine under question at
    > http://clc.pastebin.com/f4FRqgit


    Well, you've moved past dribbling, but in order to help you we still
    need more information than you've given so far. What you should give us
    is the complete actual text of a stand-alone program (preferably as
    small as possible) that can actually be compiled and executed to
    demonstrate the problem you're asking about. You should identify the
    environment where you compiled, linked, and executed the program, and
    the precise commands you used to do the compiling an linking.

    Your code is not compilable as it stands because it uses the following
    identifiers without defining or declaring them, and also without
    #including a header file that would define or declare them:

    bool
    crc_ver_init
    embedded_nvram
    magic
    nvram_exit
    nvram_do_reset
    nvram_header
    struct nvram_header
    printf
    si_t
    uint32
    FALSE
    FLASH_MIN
    KSEG1ADDR
    NVRAM_MAGIC
    NVRAM_SPACE
    SI_FLASH2
    SI_FLASH2_SZ
    TRUE

    It's possible to make reasonable guesses about what those identifiers
    might mean, based both upon their names and upon how they are used.
    However, the peculiar behavior of your program could easily depend upon
    precisely how one of those identifiers is defined. In particular, if
    you've made a mistake by using one of those identifiers in a way that's
    incompatible with the way it's defined, that might be precisely whey the
    behavior is so odd.

    The behavior is undefined because the code makes use of the following
    identifiers which are reserved to the implementation:

    _nvram_init
    _nvram_exit

    If these are routines defined by the implementation, and used by your
    program, then your program is portable only to implementations that
    provide definitions for those identifiers which work in the way you
    expect them to. You should identify where the definitions of those
    functions comes from.

    The fact that one of the two functions whose definition you have
    provided is named nvram_init() opens up the question of whether
    _nvram_init might be a typo for nvram_init (or vice versa).

    Your code fails to demonstrate the problem because it does not, in
    itself, constitute a complete program. That can easily be solved by
    adding a main() which calls nvram_init(). However, you need to provide
    us with that call; the reason why you're getting the odd results that
    you see might be due to the context from which it was called.
     
    James Kuyper, Dec 28, 2010
    #15
  16. Mark

    Willem Guest

    Re: 'static' : strange behavior

    Andrew Haley wrote:
    ) christian.bau <> wrote:
    )>
    )> void init_this (void) {
    )> static int anarray [10];
    )> int i; for (i = 0; i <= 10; ++i) anarray = 0;
    )> }
    )
    ) Ahem. Surely I cannot be the only person to have noticed this
    ) mistake, which explains everything...

    Of course you're not. The person you're replying to, who wrote this code,
    saying it was an example of undefined behaviour which could cause an effect
    similar to what the OP described, is obviously very aware of the mistake,
    as he made it on purpose for the exact purpose of creating the example.


    SaSW, Willem
    --
    Disclaimer: I am in no way responsible for any of the statements
    made in the above text. For all I know I might be
    drugged or something..
    No I'm not paranoid. You all think I'm paranoid, don't you !
    #EOT
     
    Willem, Dec 28, 2010
    #16
  17. Mark

    Geoff Guest

    On Tue, 28 Dec 2010 11:31:04 -0000, "BartC" <> wrote:

    >Also, nvram_init() appears to be called recursively, which is unusual for
    >this sort of function. Probably not the cause of this bug, but I can see
    >subtle problems creeping in because each different invocation of
    >nvram_init() is modifying the same static variable.


    Not recursive. It's calling some kind of internal, implementation
    defined _nvram_init() as suggested by the underscore. This code is
    meant to be embedded and I'd be surprised if anyone can come up with a
    scenario that can duplicate his problem. The code by itself doesn't
    suggest where his 0 is coming from and certainly nothing is visible
    between the initialization of nvram_status and his printf statement.

    The unused bool isemb variable also suggests he's got a lot of hidden
    things going on inside his target platform that he hasn't disclosed.
     
    Geoff, Dec 28, 2010
    #17
  18. Mark

    Mark Guest

    Francois Grieu wrote:
    > In some embedded environments, initialization of static and global
    > variables can be disabled or enabled depending on linking options
    > or input. One good reason is to be able to perform things quickly
    > enough before main() [hardware setup, RAM test, unamit]. Sometime,
    > this initialization is replaced or superseded by a "zero all RAM"
    > procedure. That would explain the behavior.


    The reason for the "strange behaviour" was a trivial one as expected,
    'nvram_init' was called in the very *early* stage of the firmware
    initialization, the place I've missed to check (silly me), and that altered
    'nvram_status' to zero as indication that NVRAM partition presents in the
    system.

    Thanks for some valuable insights.

    --
    Mark
     
    Mark, Dec 29, 2010
    #18
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. sstark
    Replies:
    0
    Views:
    477
    sstark
    Mar 6, 2005
  2. ryang
    Replies:
    1
    Views:
    987
    Wes Groleau
    Apr 11, 2005
  3. Apogee

    Strange Behavior with ViewState

    Apogee, Jul 3, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    338
    Apogee
    Jul 3, 2003
  4. Mantorok Redgormor
    Replies:
    70
    Views:
    1,843
    Dan Pop
    Feb 17, 2004
  5. Christopher Pisz
    Replies:
    8
    Views:
    383
    Christopher Pisz
    Mar 19, 2012
Loading...

Share This Page