pointer to union - Uninitialized memory read?

pointer to union - Uninitialized memory read?

Post by russian » Wed, 23 Jul 2003 18:28:31


See code segment below.
--------------------------------------------------------------------------
#include "stdafx.h"

typedef union {
double dubl;
char character;
int integer;
} SovietUnion;

void foo(SovietUnion * ptr);

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
SovietUnion test;

if (test.integer == 0 && test.character == 'a' && test.dubl == 0)
{
}

foo(&test);

return 0;
}

void foo(SovietUnion * ptr)
{
if (ptr->dubl == 0)
{
}
if (ptr->character == 'a')
{
}
if (ptr->integer == 0)
{
}
}

------------------------------------------------------------------------------

Running compiled executable through Purify results in the following:

[W] UMR: Uninitialized memory read in foo(SovietUnion *) {1
occurrence}
Reading 8 bytes from 0x0013f3e0 (4 bytes at 0x0013f3e4
uninitialized)
Address 0x0013f3e0 points into a thread's stack
Address 0x0013f3e0 is the local variable 'test' in WinMain
Thread ID: 0x968
Error location
foo(SovietUnion *) [UnionTest.cpp:33]

void foo(SovietUnion * ptr)
{
=> if (ptr->dubl == 0)
{
}


Interestingly enough, if I am to change the type of 'dubl' member of
the union to "int", the Purify warning/error goes away. Could someone
please explain to me as to why this difference in behaviour occurs? If
I understand correctly, when I'm referencing union members in
WinMain() I get no complaints from Purify because memory (8 bytes,
since largest member is of type double) was allocated to 'test'.

*confused*

Greg
 
 
 

pointer to union - Uninitialized memory read?

Post by Thad Smit » Thu, 24 Jul 2003 01:29:33


This post belongs in a newsgroup devoted to programming or your
particular tools, not the C standard.


This is true. test is uninitialized.


When you reference uninitialized memory, you get undefined behavior.
Anything can happen. Apparently your tool could detect one instance of
uninitialized memory and not another.

For strictly conforming code, only the union member type that is last
stored is considered to be defined, with exception for cases of positive
values stored in same-size signed and unsigned integer types.

Thad

 
 
 

pointer to union - Uninitialized memory read?

Post by Keith Thom » Thu, 24 Jul 2003 03:49:59

Thad Smith < XXXX@XXXXX.COM > writes:
[...]

And for arrays of unsigned char, I think.

--
Keith Thompson (The_Other_Keith) XXXX@XXXXX.COM < http://www.yqcomputer.com/ ~kst>
San Diego Supercomputer Center <*> < http://www.yqcomputer.com/ ~kst>
Schroedinger does Shakespeare: "To be *and* not to be"
 
 
 

pointer to union - Uninitialized memory read?

Post by kuype » Thu, 24 Jul 2003 10:35:47


Your question has nothing to do with stdafx.h, APIENTRY, HINSTANCE, or
LPSTR, all of which are Windows-specific. If you want a
Windows-specific answer, you should post to a different newsgroup. If,
as in this case, the answer has nothing to do with windows, you should
have simplified your example code by removing them.


You haven't initialized 'test'. Therefore, you can't access an of it's
members.
If you had initialized it, you could only safely access the member you
had initialized it with. You could never safely examine all three
members the way you did above. Therefore, it's generally best to
package such a union along with a discriminator that tells you which
member has been set:

typedef struct
{
enum {DISCRIM_CHAR, DISCRIM_INT, DISCRIM_DOUBLE, DISCRIM_TYPES}
type;
union {
char character;
int integer;
double dubl;
}u;
} SovietUnion;

Note: DISCRIM_TYPES contains, automatically, the number of different
values in the enumeration, which is sometimes a useful thing, though I
make no use of it in this example.

Then, you would initialize it with code like the following:

SovietUnion test;

test.type = DISCRIM_INT;
test.u.integer = 3;

You would access it with code like the following:

void foo( SovietUnion *pdu)
{
switch(pdu->type)
{
case DISCRIM_CHAR: /* use pdu->u.character */
break;
case DISCRIM_INT: /* use pdu->u.integer */
break;
case DISCRIM_DOUBL: /* use pdu->u.dubl */
break;
default: /* Error handling */
break;
}
}