For Programmers: Free Programming Magazines  


Home > Archive > Unix Programming > December 2004 > core dump of simple test program









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author core dump of simple test program
Jaguk Ku

2004-12-23, 9:03 am

Hi there,

I made a simple test program below

=======================================
#include <stdio.h>

struct _TEST {
char s1[4];
char s2[10];
} TEST;

int main()
{
memset(&TEST, 0x00, sizeof(TEST));

*(int*)TEST.s2 = 10;

printf("s2=%d\n", *(int*)TEST.s2);

exit(0);
}
=======================================
the output is normal like below
s2=10

but when i change struct _TEST little bit like below

=======================================
struct _TEST {
char s1[3];
char s2[10];
} TEST;
=======================================

it suddenly died with core dump when i executed it.
I don't know what is wrong.

Thanks in advance,

Jaguk Ku


Jens.Toerring@physik.fu-berlin.de

2004-12-23, 9:03 am

Jaguk Ku <jkku@softeleware.com> wrote:
> I made a simple test program below


> =======================================
> #include <stdio.h>


> struct _TEST {
> char s1[4];
> char s2[10];
> } TEST;


> int main()
> {
> memset(&TEST, 0x00, sizeof(TEST));


> *(int*)TEST.s2 = 10;


> printf("s2=%d\n", *(int*)TEST.s2);


> exit(0);
> }
> =======================================
> the output is normal like below
> s2=10


> but when i change struct _TEST little bit like below


> =======================================
> struct _TEST {
> char s1[3];
> char s2[10];
> } TEST;
> =======================================[
/color]
[color=darkred]
> it suddenly died with core dump when i executed it.
> I don't know what is wrong.


What you get here is a "bus error" and that is due to an alignment
problem. You seem to be using a processor that has certain restric-
tions when accessing multi-byte quantities (like an int) at once -
they must start on even addresses (or even addresses that start on
addresses that can be divided by 4 etc). That's because an access
like

* ( int * ) TEST.s2 = 10;

will be translated to machine code that uses instructions that move
2, 4 or 8 bytes (depending on the sizeof(int) on your machine) a
once, but expect a properly aligned address to work with.

When you have a structure like

> struct _TEST {
> char s1[4];
> char s2[10];
> } TEST;


's2' is going to be at an address that can be devided by 4, so if
you try to use 's2' as an int pointer it my still work since, by
luck, it's at an acceptable address. But when you change the
structure to

> struct _TEST {
> char s1[3];
> char s2[10];
> } TEST;


's2' is now at an odd address and trying to treat that as an int
pointer won't work with your processor (actually, even on CPUs
where you don't get a bus error with this it will probably still
be a significantly slower than a well-aligned access).

That's also the reason why the compiler is allowed to insert as
many "padding" bytes between the elements of a structure. If you
would change your structure to

> struct _TEST {
> char s1[3];
> int s2;
> } TEST;


and would check the offset of 's2' from the start of the structure
you will find that it isn't 3 (as one may expect by just counting
bytes) but 4 to take care of the alignment requirements on your
machine - to do that the compiler inserts an extra byte between 's1'
and 's2'. So never assume that sizeof(TEST) is equal to the sum of
the sizes of its components!

For that reason you should be very careful with casting between
pointers to different types - they can have different alignment
requirements, thus using what's really a char pointer as an int
pointer might get you in lots of trouble. The most evil thing
is that it might even work on a certain type of CPU but break the
program when you try to port it to a different architecture. So,
if you have to assign e.g. the data from an int to what's pointed
to by a char pointer, always make sure to use memcpy() - that
guarantees that you won't get problems with alignment requirements.

Finally, just for your information, the use of identifiers starting
with an underscore is not allowed in normal C programs - identifiers
starting with a leading underscore are reserved for the implementa-
tion, i.e. for use by the compiler and system header files etc. In
your case correcting this isn't a problems since

struct TEST {
char s1[3];
char s2[10];
} TEST;

will also do perfectly well, as will do

struct {
char s1[3];
char s2[10];
} TEST;

Regards, Jens
--
\ Jens Thoms Toerring ___ Jens.Toerring@physik.fu-berlin.de
\__________________________ http://www.toerring.de
Dan Mercer

2004-12-23, 4:07 pm


<Jens.Toerring@physik.fu-berlin.de> wrote in message news:32vljgF3qu8s3U1@uni-berlin.de...
: Jaguk Ku <jkku@softeleware.com> wrote:
: > I made a simple test program below
:
: > =======================================
: > #include <stdio.h>
:
: > struct _TEST {
: > char s1[4];
: > char s2[10];
: > } TEST;
:
: > int main()
: > {
: > memset(&TEST, 0x00, sizeof(TEST));
:
: > *(int*)TEST.s2 = 10;
:
: > printf("s2=%d\n", *(int*)TEST.s2);
:
: > exit(0);
: > }
: > =======================================
: > the output is normal like below
: > s2=10
:
: > but when i change struct _TEST little bit like below
:
: > =======================================
: > struct _TEST {
: > char s1[3];
: > char s2[10];
: > } TEST;
: > =======================================
:
: > it suddenly died with core dump when i executed it.
: > I don't know what is wrong.
:
: What you get here is a "bus error" and that is due to an alignment
: problem. You seem to be using a processor that has certain restric-
: tions when accessing multi-byte quantities (like an int) at once -
: they must start on even addresses (or even addresses that start on
: addresses that can be divided by 4 etc). That's because an access
: like
:
: * ( int * ) TEST.s2 = 10;
:
: will be translated to machine code that uses instructions that move
: 2, 4 or 8 bytes (depending on the sizeof(int) on your machine) a
: once, but expect a properly aligned address to work with.
:
: When you have a structure like
:
: > struct _TEST {
: > char s1[4];
: > char s2[10];
: > } TEST;
:
: 's2' is going to be at an address that can be devided by 4, so if
: you try to use 's2' as an int pointer it my still work since, by
: luck, it's at an acceptable address. But when you change the
: structure to
:
: > struct _TEST {
: > char s1[3];
: > char s2[10];
: > } TEST;
:
: 's2' is now at an odd address and trying to treat that as an int
: pointer won't work with your processor (actually, even on CPUs
: where you don't get a bus error with this it will probably still
: be a significantly slower than a well-aligned access).
:
: That's also the reason why the compiler is allowed to insert as
: many "padding" bytes between the elements of a structure. If you
: would change your structure to
:
: > struct _TEST {
: > char s1[3];
: > int s2;
: > } TEST;
:
: and would check the offset of 's2' from the start of the structure
: you will find that it isn't 3 (as one may expect by just counting
: bytes) but 4 to take care of the alignment requirements on your
: machine - to do that the compiler inserts an extra byte between 's1'
: and 's2'. So never assume that sizeof(TEST) is equal to the sum of
: the sizes of its components!
:
: For that reason you should be very careful with casting between
: pointers to different types - they can have different alignment
: requirements, thus using what's really a char pointer as an int
: pointer might get you in lots of trouble. The most evil thing
: is that it might even work on a certain type of CPU but break the
: program when you try to port it to a different architecture. So,
: if you have to assign e.g. the data from an int to what's pointed
: to by a char pointer, always make sure to use memcpy() - that
: guarantees that you won't get problems with alignment requirements.
:
: Finally, just for your information, the use of identifiers starting
: with an underscore is not allowed in normal C programs - identifiers
: starting with a leading underscore are reserved for the implementa-
: tion, i.e. for use by the compiler and system header files etc. In
: your case correcting this isn't a problems since
:
: struct TEST {
: char s1[3];
: char s2[10];
: } TEST;
:
: will also do perfectly well, as will do
:
: struct {
: char s1[3];
: char s2[10];
: } TEST;

If you are going you use a field to hold data that you aceess with two
different data types, you need to use a union. Even so, I feel what
you are trying to do may not be portable.

Dan Mercer

:
: Regards, Jens
: --
: \ Jens Thoms Toerring ___ Jens.Toerring@physik.fu-berlin.de
: \__________________________ http://www.toerring.de


Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com