Operating System - HP-UX
1827243 Members
2353 Online
109716 Solutions
New Discussion

casting from character array to Structure.

 
SOLVED
Go to solution
Aditya Rekha
New Member

casting from character array to Structure.

Hi,

I have an instance where a character array is casted to structure, X.
ie char arr[50*sizeof(struct X)];
char *l=arr;
func((X *)l);

{sizeof(struct X) is 1168 }
The structure X, has stat64 as one of its field. Since the most strict alignment in stat64 is 8bytes long, I guess the address of 'l' should also be aligned at 8 multiples.
I am getting SIGBUS & core dump in func(), when X->stat field is assigned to stat structure value returned by stat64 call.
How can I ensure the character array address aligns at 8 multiples?
Or is the problem something else?

In gdb, when I load core, I get address of 'l' only aligned at 4 whenever it dumps core.
6 REPLIES 6
Mike Stroyan
Honored Contributor

Re: casting from character array to Structure.

I must ask the obvious question. Why don't you use the true data type to get the correct alignment?

struct X arr[50];
func(arr);
Aditya Rekha
New Member

Re: casting from character array to Structure.

Hi Mike,

There seem to be two reasons why this is done.

1. Our component sends this list of structures to pipe along with a 8byte pipe header. So here arr to arr+8 is a pipe header.

2. The struct X, has following fields.
struct X
{
X *next;
short filename;
short actionname;
unsigned char physicaltype;
short logical type;
int errnum;
struct stat64 stat;
........
char text[1024];
}
Here the text field concatenates filename, actionname, logicaltype, link and filelink strings. In most of the practical cases, the total length of all these fields far less than 1024. So we move pointer to the nearest 4multiple of the length of the structure we used. And the next structure starts from that point. This way we practically fit more than 50 such structures in the same space.


I missed mentioning one important point in my previous message. I face this problem only with IPF executable. This problem occurs whenever we try to assign any structure with some padded values to a casted type.A sample program which demonstrates the problem is

#include
/* Here 4bytes in between st_dev and st_size are automatically padded, as offset of long long has to start at multiples of 8 */
typedef struct sample
{ int st_dev;
long long st_size;
long st_ctime;
};

typedef struct sbuf {
struct sample s;
} ;

main(argc, argv)
int argc;
char **argv;
{
int m;
struct x
{
long long l;
int i;
char buffer[sizeof(struct sample)];
int r;
}k;
char *ptr=k.buffer;
func((struct sbuf *)ptr);
}

int func(struct sbuf *buffer)
{
struct sample st;
int result;
memset(buffer,0,sizeof(struct sample));
st.st_dev=12;
st.st_size=12342424;
st.st_ctime=234;
buffer->s=st;
}

Similar is the case with stat64 structure.It is not tightly packed& has some padding in between.

Why is this problem only with IA binary?
When we look at stat structure, it looks as if special care is taken to avoid automatic padding. But stat64 structure doesn't seem to have taken such care.



Mike Stroyan
Honored Contributor

Re: casting from character array to Structure.

Your example program also crashes on PA-RISC with a +DD64 compiler mode. I can prevent the crash by putting the buffer array in a union with an otherwise unused struct sbuf. That causes the union, (and the array), to be aligned as necessary for the struct.

main(argc, argv)
int argc;
char **argv;
{
int m;
struct x
{
long long l;
int i;
union {
char buffer[sizeof(struct sample)];
struct sbuf align;
} u;
int r;
}k;
char *ptr=k.u.buffer;
func((struct sbuf *)ptr);
}
Aditya Rekha
New Member

Re: casting from character array to Structure.

Thank you. That's a nice solution for alignment. Leaving the sample program aside, in the actual source,the 1st eight bytes of character array are used for pipe header msg and the rest are the list of structures. So, a bit sceptical if this will work out. And implementing union requires change at all other places where the character array is referenced. Can we have other alternatives?

There's one correction in the question I posted. The same program dumps core even when the address is aligned correctly at 8 multiples :-( . Now I feel the problem is due to automatic padding in stat64 structure rather than alignment of structure X.

Instead of directly assigning stat64 structure, if I use memcpy the problem goes away. But is it a good practice to use memcpy as it doesn't check for alignment or does it? I am not sure.
Instead of
l->stat = stat_buf;/* stat_buf is the stat64 structure obtained from stat64 call */
using
memcpy( &(l->stat),&stat_buf,sizeof (struct stat64 )); is able to solve the problem.

What's your opinion on using memcpy?





A. Clay Stephenson
Acclaimed Contributor
Solution

Re: casting from character array to Structure.

memcpy() should be a safe operation as long as you declare a variable for the destination. That way, the source address can fall on a byte-boundary but the destintaion (since it is a declared variable) will always fall on a word boundary. This is basically the technique used by databases when floating point values might fall on odd boundaries within the database record. Memcpy (or something very similar) is used to move variables on a column by column basis.
If it ain't broke, I can fix that.
Mike Stroyan
Honored Contributor

Re: casting from character array to Structure.

memcpy doesn't have any alignment requirements. (It does require the source and destination don't overlap.)

You should be fine using memcpy to pack the data if it will only be used for a write to a pipe. You will need to be carefull of alignment requirements if you once again use that data as a struct instead of a byte array. You will need to copy into an aligned address when unpacking data from reads of that pipe.