Crashing program compiled with O2

A

Alex Vinokur

Hi,

I compiled and run the following program
on 2 compilers - HP-UX aCC and IBM xlC,
in 2 modes - No optimiztion and O2.

Program crashed while xlC and O2.

Something wrong with the program?

Thanks.

=== test3.cpp ===

struct Foo
{
int m_l1;
};

char s_array[100];
struct Bar
{
char* m_pCh;
Foo*& m_pFoo;

Bar()
:
m_pCh (0),
m_pFoo (reinterpret_cast<Foo*&> (m_pCh))
{
}

void func()
{
m_pCh = &s_array[0];
m_pFoo->m_l1 = 123;
}
};

int main()
{
Bar bar;
bar.func();
return 0;
}

=================


========= HP-UX, aCC ==========

aCC: HP C/aC++ B3910B A.06.15 [May 16 2007]
aCC test3.cpp
./a.out
aCC -O2 test3.cpp
./a.out

================================


========= AIX, xlC ==========

IBM XL C/C++ Enterprise Edition V8.0 for AIX
Version: 08.00.0000.0014
xlC test3.cpp
./a.out
xlC -O2 test3.cpp
./a.out
Segmentation fault (core dumped)
xlC -g -O2 test3.cpp
./a.out
Segmentation fault (core dumped)
dbx a.out core
Type 'help' for help.
[using memory image in core]
reading symbolic information ...

Segmentation fault in main at line 22
22 m_pFoo->m_l1 = 123;
(dbx) where
main(), line 22 in "test3.cpp"
(dbx) dump
main(), line 22 in "test3.cpp"
libdebug assertion "(0)" failed at line 688 in
file ../../../../../../../../../../../src/bos/usr/ccs/lib/libdbx/
libdebug/modules/stackdebug/POWER/stackdb_PowerStackFrame.C
bar = warning: Unable to access address 0xf163ad60300c6670 from core
(m_pCh = warning: Unable to access address 0xffffffff from core
(invalid char ptr (0xffffffff)), warning: Unable to access address
0xffffffff from core
m_pFoo = 0xffffffff)

=============================


Alex Vinokur
 
A

Alberto 'JCN-9000' Varesio

Alex said:
Hi,

I compiled and run the following program
on 2 compilers - HP-UX aCC and IBM xlC,
in 2 modes - No optimiztion and O2.

Program crashed while xlC and O2.

Something wrong with the program?

Linux too crashes ... same location :

avi@tp-avi tmp $ gcc -O2 -Wall -pedantic test3.cpp
test3.cpp: In constructor 'Bar::Bar()':
test3.cpp:15: warning: dereferencing type-punned pointer will break
strict-aliasing rules
avi@tp-avi tmp $ ./a.out
Segmentation fault

HTH

--
* Alberto Varesio * - /IBM eServer Certified Specialist/
/S&N Competence Center Application Engineer/
* SPAZIOSYSTEM S.p.A. * - http://www.spaziosystem.com/
Tel.: +39 011 19756013 - Cell.: 335 1811324

Please consider your environmental impact before printing this e-mail
Help preserve the environment! Is printing this email necessary ?
==
(\_/)
(o_O) This is Bunny. Copy Bunny into your signature to help him
(> <) on his way to world domination.
 
R

Ron

What makes you think that Foo* has the same
respresentation as char*.

The program his hideously non-portable.
 
G

Gary R. Hook

Alex said:
I compiled and run the following program
on 2 compilers - HP-UX aCC and IBM xlC,
in 2 modes - No optimiztion and O2.

Program crashed while xlC and O2.

Something wrong with the program?
Yes.


=== test3.cpp ===

struct Foo
{
int m_l1;
};

char s_array[100];
struct Bar
{
char* m_pCh;
Foo*& m_pFoo;

Bar()
:
m_pCh (0),
m_pFoo (reinterpret_cast<Foo*&> (m_pCh))
{
}

void func()
{
m_pCh = &s_array[0];
m_pFoo->m_l1 = 123;
}
};

int main()
{
Bar bar;
bar.func();
return 0;
}

You've defined the class Foo and you've instantiated a _reference_ to
an object of type Foo (m_pFoo) but you did not instantiate any Foo
objects, nor did you point m_pFoo at any objects of type Foo (because
you have none).

Your program is incorrect.

Compiling without -O2, but with -g, and using dbx (after reformatting
your source to make it palatable) (AIX 6.1, 32-bit mode):

stopped in Bar::func() at line 21
21 m_pFoo->m_l1 = 123;
(dbx) print m_pFoo
0x20000c70
(dbx) print *m_pFoo
(m_l1 = 0)

You're not pointing to anything.

The only reason this works non-optimized on AIX is because it is not
illegal to write to page 0 on the system. (Don't ask why; some people
think this is a Good Thing.) When optimized the nil pointer above
becomes wild garbage, thus your seg-fault.

In other words, this program is incorrect for any correct compiler. Fix
the program and it should be fine.
 
P

Pavel

Gary said:
Alex said:
I compiled and run the following program
on 2 compilers - HP-UX aCC and IBM xlC,
in 2 modes - No optimiztion and O2.

Program crashed while xlC and O2.

Something wrong with the program?
Yes.


=== test3.cpp ===

struct Foo
{
int m_l1;
};

char s_array[100];
struct Bar
{
char* m_pCh;
Foo*& m_pFoo;

Bar()
:
m_pCh (0),
m_pFoo (reinterpret_cast<Foo*&> (m_pCh))
{
}

void func()
{
m_pCh = &s_array[0];
m_pFoo->m_l1 = 123;
}
};

int main()
{
Bar bar;
bar.func();
return 0;
}

You've defined the class Foo and you've instantiated a _reference_ to
an object of type Foo (m_pFoo) but you did not instantiate any Foo
objects, nor did you point m_pFoo at any objects of type Foo (because
you have none).
m_pFoo is not a reference to an object of type Foo, it is a reference to
a pointer to an object of class Foo. It is a pointer that is never
created and, instead of a pointer, the beginning of s_array is used
(reinterpret_cast there in fact assumes that the reference is internally
represented by a pointer which is often true although certainly not
guaranteed). Even though the object is never created, either, the memory
for it is allocated so it would not usually coredump if it were the only
issue (of course, it would be non-portable and the program would not be
compliant to the Standard, but often this alone would not cause a
coredump). However, because this memory is used as a pointer and is read
and dereferenced instead of being used as an object and being written to
as it is apparently intended, the coredump happens. Whatever the
contents of s_array happens to be (in our case it is zero-initialized as
it is a global array), will define what the pointer will be. *m_pFoo
will refer to the memory addressed by that pointer co-located with
s_array (page 0, in our case).

Just my 2 cents
-Pavel
 
J

James Kanze

I compiled and run the following program
on 2 compilers - HP-UX aCC and IBM xlC,
in 2 modes - No optimiztion and O2.
Program crashed while xlC and O2.
Something wrong with the program?

Several things.
=== test3.cpp ===
struct Foo
{
int m_l1;
};
char s_array[100];
struct Bar
{
char* m_pCh;
Foo*& m_pFoo;
Bar()
:
m_pCh (0),
m_pFoo (reinterpret_cast<Foo*&> (m_pCh))

What happens if Foo* and char* have different representations.
Posix guarantees that this is not the case (so it's not the
problem here), but other systems don't. (I've worked on
machines where they had different sizes.)
void func()
{
m_pCh = &s_array[0];
m_pFoo->m_l1 = 123;

What makes you think the s_array is adequately aligned to hold
anything but a character? It may or may not be, and many (most)
systems will core dump on an unaligned access. (You'll also get
into trouble if sizeof( int ) is greater than 100, but that's
more a theoretical problem than a real one, I think.)

Note that the alignment of s_array is likely to depend on what
else you declare in the code, and could be almost random.
int main()
{
Bar bar;
bar.func();
return 0;
}
=================

Given the undefined behavior, I don't think you can judge too
much by what happens on any given machine.
 
D

Dennis Handly

Alex said:
Something wrong with the program?
char s_array[100];

> How do you know if s_array is correctly aligned?

Yes, it might be interesting to print its address.
> (dbx) print m_pFoo
> 0x20000c70
> (dbx) print *m_pFoo
> (m_l1 = 0)
> You're not pointing to anything.

I'm not sure why you said that? You are pointing into s_array.
>When optimized the nil pointer above becomes wild garbage,

What NIL pointer? m_l1 is an int.
 
A

Alex Vinokur

What makes you think the s_array is adequately aligned to hold
anything but a character?  It may or may not be, and many (most)
systems will core dump on an unaligned access.  (You'll also get
into trouble if sizeof( int ) is greater than 100, but that's
more a theoretical problem than a real one, I think.)

Note that the alignment of s_array is likely to depend on what
else you declare in the code, and could be almost random.
[snip]

The following program (char replaced by int ) produces the same
behavior

struct Foo
{
int m_l1;
};

int s_array[100];
struct Bar
{
int* m_pInt;
Foo*& m_pFoo;

Bar()
:
m_pInt (0),
m_pFoo (reinterpret_cast<Foo*&> (m_pInt))
{
}

void func()
{
m_pInt = &s_array[0];
m_pFoo->m_l1 = 123;
}
};

int main()
{
Bar bar;
bar.func();
return 0;
}


Alex Vinokur
 
P

pasa

Alex Vinokur said:
The following program (char replaced by int ) produces the same
behavior

Alberto already pointed out the most probable source:
test3.cpp:15: warning: dereferencing type-punned pointer will break
strict-aliasing rules

Your compiler setting very likely relies on it, and the generated
code
thinks your ref can not be the alias of the int pointer -- using the
old
value or something else. You can verify that looking at the assy.

while pasting the warning message to google provides good explanation
on the
background and working alternatives.
 
J

James Kanze

[snip]
What makes you think the s_array is adequately aligned to
hold anything but a character? It may or may not be, and
many (most) systems will core dump on an unaligned access.
(You'll also get into trouble if sizeof( int ) is greater
than 100, but that's more a theoretical problem than a real
one, I think.)
Note that the alignment of s_array is likely to depend on
what else you declare in the code, and could be almost
random.

The following program (char replaced by int ) produces the
same behavior

Replacing char by int in the array potentially introduces
undefined behavior. If you access elements of the int array as
anything other than an int, it is undefined behavior.

As others have pointed out, this isn't the only source of
undefined behavior in the code.
struct Foo
{
int m_l1;
};
int s_array[100];
struct Bar
{
int* m_pInt;
Foo*& m_pFoo;
Bar()
:
m_pInt (0),
m_pFoo (reinterpret_cast<Foo*&> (m_pInt))

Note that while this statement is probably legal, any use of
m_pFoo after it is undefined behavior. The type of m_pInt is
int*; accessing it through an lvalue which has any other type
(except a character type) is undefined behavior.
void func()
{
m_pInt = &s_array[0];
m_pFoo->m_l1 = 123;

Because m_pInt and m_pFoo cannot legally refer to the same thing
(at least if you're accessing through both of them), the
compiler is free to assume that you they don't refer to the same
thing here, and reorder accesses between them, i.e. read m_pFoo
before writing m_pInt.

Basically, it looks like a case of the compiler getting back at
you because you lied to it.
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top