'static' : strange behavior

M

Mark

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?
 
I

Ian Collins

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.
 
E

Eric Sosman

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.
 
M

Mark

Eric said:
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.
 
I

Ian Collins

Eric said:
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?
 
E

Eric Sosman

Eric said:
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.
 
S

Shivanand Kadwadkar

Eric said:
    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.

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
 
M

Mark

Eric said:
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
 
I

Ike Naar

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.
 
F

Francois Grieu

Eric said:
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
 
N

Nick

Mark said:
Eric said:
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
 
B

BartC

Mark said:
:)
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.
 
J

James Kuyper

:)
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.
 
W

Willem

Andrew Haley 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
 
G

Geoff

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.
 
M

Mark

Francois said:
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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top