473,378 Members | 1,395 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,378 software developers and data experts.

Pointer hell

[posted separately to comp.unix.programmer and

Can't figure out why this code generates a SIGSEGV in
fillGlobalBuffer() (below).

globalBuffer is allocated in caller.c, then its address is passed to
a pointer of the same type inside of callee.c, and that local pointer
is used as the reference written to from within callee.c.

It doesn't appear to actually write anything there, and when I try to
read it back I get empty data (from the original calloc() call) and
then a segfault.

I increment the offset into globalBuffer to write successive bits of
data (in this case, timestamps but it's just for illustration).

I am apparently making a fundamental error with the C language and
can't actually assign and use a pointer this way, but I'm not
clear as to why.

Or, I actually can do this but I'm going about it the wrong way.

I get a zeros from the printf() call in fillGlobalBuffer() before it
crashes.

References to, or other info describing, what I'm being stupid about
would be greatly appreciated.

===== Environ

Linux, GCC.

%uname -a
Linux tmdev 2.4.20-4GB #1 Tue May 24 16:14:53 UTC 2005 i686 unknown
unknown GNU/Linux

%gcc --version
gcc (GCC) 3.3 20030226 (prerelease) (SuSE Linux)
Copyright (C) 2002 Free Software Foundation, Inc.

%ld --version
GNU ld version 2.13.90.0.18 20030121 (SuSE Linux)
Copyright 2002 Free Software Foundation, Inc.

%/lib/libc.so.6
GNU C Library stable release version 2.3.2, by Roland McGrath et al.
Copyright (C) 2003 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 3.3 20030226 (prerelease) (SuSE Linux).
Compiled on a Linux 2.4.20 system on 2003-03-13.

Can't figure out why this generates a SIGSEGV in fillGlobalBuffer()
(below).

globalBuffer is allocated in caller.c, then its address is passed to
a pointer of the same type inside of callee.c, and that local pointer
is used as the reference written to.

I increment the offset into globalBuffer to write successive bits of
data (in this case, timestamps but it's just for illustration).

I apparently can't assign and use a pointer this way, but I'm not
clear as to why. Or, I can do this but I'm going about it the wrong
way.

I get a zeros from the printf() call in fillGlobalBuffer() before it
crashes.

References to, or other info describing, what I'm being stupid about
would be greatly appreciated.

===== Compile
% gcc -g -Wall -o test caller.c callee.c -I.
===== Code
/* caller.c
*/
#include "callee.h"

unsigned char * globalBuffer ;

int
main(void)
{
int i, bytes_written ;
struct timeval tv ;

if ( (globalBuffer=calloc(1, GLOBAL_BUFSIZE)) == NULL )
{
fprintf(stderr,"calloc() failed on globalBuffer\n" );
exit(-1);
}
setGlobalBuffer( globalBuffer, GLOBAL_BUFSIZE ) ;

bytes_written = 0 ;
for ( i = 0 ; i < GLOBAL_BUFSIZE ; )
{
gettimeofday( &tv, NULL ) ;
fillGlobalBuffer(&tv, sizeof(struct timeval), &bytes_written);
i += bytes_written ;
}

// verify globalBuffer contents
for ( i = 0 ; i < GLOBAL_BUFSIZE ; i += sizeof(struct timeval) )
{
struct timeval * tv ;
tv = (struct timeval *)(globalBuffer+i) ;
// HERE
printf("Index=%d, timeval=%lu.%lu\n",i,tv->tv_sec,tv->tv_usec);
}

return 0 ;
}

/* callee.h
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <string.h>

#define GLOBAL_BUFSIZE 1024

void
setGlobalBuffer( unsigned char * gb, int gbmax ) ;

int
fillGlobalBuffer( void * data, int datalen, int * written ) ;

/* callee.c
*/
#include "callee.h"

unsigned char * bigBuf ;
int bbIndex ;
int bbMax ;

void
setGlobalBuffer( unsigned char * gb, int gbmax )
{
bigBuf = gb ;
bbIndex = 0 ;
bbMax = gbmax ;
}

int
fillGlobalBuffer( void * data, int datalen, int * written )
{
struct timeval * tv ;

if ( bbIndex + datalen > bbMax )
return -1 ;

memcpy( bigBuf+bbIndex, data, datalen ) ;

tv = (struct timeval *)bigBuf+bbIndex ;
printf("fGB(): wrote %lu.%lu to bigBuf\n",tv->tv_sec,tv->tv_usec);

bbIndex += datalen ;
*written = datalen ;
return 0 ;
}

===== Output
% ./test
fGB(): wrote 1142826382.680840 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.4833 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf

Segmentation fault (core dumped)
Mar 20 '06 #1
6 2643
Simple Simon wrote:
[posted separately to comp.unix.programmer and

Can't figure out why this code generates a SIGSEGV in
fillGlobalBuffer() (below).
[...]
It seems extraordinarily convoluted code for such a simple
task, and I confess I've run out of patience before finishing a
thorough examination. Here's at least one problem, though:
tv = (struct timeval *)bigBuf+bbIndex ;
printf("fGB(): wrote %lu.%lu to bigBuf\n",tv->tv_sec,tv->tv_usec);


First, ponder the difference between the first of these
lines and

tv = (struct timeval *)(bigBuf + bbIndex);

Second, consider that a `struct timeval' might have alignment
requirements and that a bunch of bytes at an arbitrary address
might not meet those requirements. (This doesn't happen in the
sample code you posted, since everything you put in the buffer is
a `struct timeval' -- effectively, you've got an array of them
and the array elements will all be aligned properly. But if you
start mingling `struct timeval's with strings and `struct foobar's,
all bets are off.)

Hope this helps.

--
Eric Sosman
es*****@acm-dot-org.invalid
Mar 20 '06 #2
Simple Simon wrote:
[posted separately to comp.unix.programmer and

Can't figure out why this code generates a SIGSEGV in
fillGlobalBuffer() (below).

globalBuffer is allocated in caller.c, then its address is passed to
a pointer of the same type inside of callee.c, and that local pointer
is used as the reference written to from within callee.c.

It doesn't appear to actually write anything there, and when I try to
read it back I get empty data (from the original calloc() call) and
then a segfault.

I increment the offset into globalBuffer to write successive bits of
data (in this case, timestamps but it's just for illustration).

I am apparently making a fundamental error with the C language and
can't actually assign and use a pointer this way, but I'm not
clear as to why.

Or, I actually can do this but I'm going about it the wrong way.

I get a zeros from the printf() call in fillGlobalBuffer() before it
crashes.

References to, or other info describing, what I'm being stupid about
would be greatly appreciated.

===== Environ

Linux, GCC.

%uname -a
Linux tmdev 2.4.20-4GB #1 Tue May 24 16:14:53 UTC 2005 i686 unknown
unknown GNU/Linux

%gcc --version
gcc (GCC) 3.3 20030226 (prerelease) (SuSE Linux)
Copyright (C) 2002 Free Software Foundation, Inc.

%ld --version
GNU ld version 2.13.90.0.18 20030121 (SuSE Linux)
Copyright 2002 Free Software Foundation, Inc.

%/lib/libc.so.6
GNU C Library stable release version 2.3.2, by Roland McGrath et al.
Copyright (C) 2003 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 3.3 20030226 (prerelease) (SuSE Linux).
Compiled on a Linux 2.4.20 system on 2003-03-13.

Can't figure out why this generates a SIGSEGV in fillGlobalBuffer()
(below).

globalBuffer is allocated in caller.c, then its address is passed to
a pointer of the same type inside of callee.c, and that local pointer
is used as the reference written to.

I increment the offset into globalBuffer to write successive bits of
data (in this case, timestamps but it's just for illustration).

I apparently can't assign and use a pointer this way, but I'm not
clear as to why. Or, I can do this but I'm going about it the wrong
way.

I get a zeros from the printf() call in fillGlobalBuffer() before it
crashes.

References to, or other info describing, what I'm being stupid about
would be greatly appreciated.

===== Compile
% gcc -g -Wall -o test caller.c callee.c -I.
===== Code
/* caller.c
*/
#include "callee.h"

unsigned char * globalBuffer ;

int
main(void)
{
int i, bytes_written ;
struct timeval tv ;

if ( (globalBuffer=calloc(1, GLOBAL_BUFSIZE)) == NULL )
{
fprintf(stderr,"calloc() failed on globalBuffer\n" );
exit(-1);
}
setGlobalBuffer( globalBuffer, GLOBAL_BUFSIZE ) ;

bytes_written = 0 ;
for ( i = 0 ; i < GLOBAL_BUFSIZE ; )
{
gettimeofday( &tv, NULL ) ;
fillGlobalBuffer(&tv, sizeof(struct timeval), &bytes_written);
i += bytes_written ;
}

// verify globalBuffer contents
for ( i = 0 ; i < GLOBAL_BUFSIZE ; i += sizeof(struct timeval) )
{
struct timeval * tv ;
tv = (struct timeval *)(globalBuffer+i) ;
// HERE
printf("Index=%d, timeval=%lu.%lu\n",i,tv->tv_sec,tv->tv_usec);
}

return 0 ;
}

/* callee.h
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <string.h>

#define GLOBAL_BUFSIZE 1024

void
setGlobalBuffer( unsigned char * gb, int gbmax ) ;

int
fillGlobalBuffer( void * data, int datalen, int * written ) ;

/* callee.c
*/
#include "callee.h"

unsigned char * bigBuf ;
int bbIndex ;
int bbMax ;

void
setGlobalBuffer( unsigned char * gb, int gbmax )
{
bigBuf = gb ;
bbIndex = 0 ;
bbMax = gbmax ;
}

int
fillGlobalBuffer( void * data, int datalen, int * written )
{
struct timeval * tv ;

if ( bbIndex + datalen > bbMax )
return -1 ;

memcpy( bigBuf+bbIndex, data, datalen ) ;

tv = (struct timeval *)bigBuf+bbIndex ;
printf("fGB(): wrote %lu.%lu to bigBuf\n",tv->tv_sec,tv->tv_usec);

bbIndex += datalen ;
*written = datalen ;
return 0 ;
}

===== Output
% ./test
fGB(): wrote 1142826382.680840 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.4833 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf
fGB(): wrote 0.0 to bigBuf

Segmentation fault (core dumped)

I think the problem is here ...
memcpy( bigBuf+bbIndex, data, datalen ) ;

tv = (struct timeval *)bigBuf+bbIndex ;
The second use of bigBuf+bbIndex will be interpreted as:
tv = ((struct timeval *)bigBuf) + bbIndex ;


So, you're incrementing by sizeof(struct time *) * /n/ [n == bbIndex].

Try changing this to line to ...

tv = (struct timeval *)(bigBuf + bbIndex) ;
--
==============
Not a pedant
==============
Mar 20 '06 #3
es*****@acm-dot-org.invalid wrote...
Simple Simon wrote:
[posted separately to comp.unix.programmer and

Can't figure out why this code generates a SIGSEGV in
fillGlobalBuffer() (below).
[...]
It seems extraordinarily convoluted code for such a simple
task, and I confess I've run out of patience before finishing a
thorough examination.


Yeah, I apologize for that. callee.{c,h} are actually placed in a
library, and caller.c calls that library. So it is convoluted far
beyond what is strictly necessary for the task, but since I thought
that the problem was related to the buffer reference passed into
callee.c, I thought I needed to reflect the relationship of the files
to each other.
Here's at least one problem, though:
tv = (struct timeval *)bigBuf+bbIndex ;
That was indeed the problem, although you raise another one.
printf("fGB(): wrote %lu.%lu to bigBuf\n",tv->tv_sec,tv->tv_usec);
First, ponder the difference between the first of these
lines and

tv = (struct timeval *)(bigBuf + bbIndex);

Second, consider that a `struct timeval' might have alignment
requirements and that a bunch of bytes at an arbitrary address
might not meet those requirements. (This doesn't happen in the
sample code you posted, since everything you put in the buffer is
a `struct timeval' -- effectively, you've got an array of them
and the array elements will all be aligned properly. But if you
start mingling `struct timeval's with strings and `struct foobar's,
all bets are off.)


This is a great concern, although it isn't biting me yet. Does this
type of alignment problem have a commonly referenced name, so that I
can learn more about it?

Do compilers generally support flags that address this, or are you
just hosed if a problem like this arises?

Hope this helps.


It did. THANK YOU to you and everyone else who helped me.
Mar 20 '06 #4


Simple Simon wrote On 03/20/06 17:51,:
[... concerning alignment ...]
This is a great concern, although it isn't biting me yet. Does this
type of alignment problem have a commonly referenced name, so that I
can learn more about it?
Alignment requirements are generally referred to as,
er, "alignment requirements." (Who'd have guessed?)
Do compilers generally support flags that address this, or are you
just hosed if a problem like this arises?


Some compilers are able to generate code that will
correctly access mis-aligned data, usually at a penalty
in speed. For example, they might perform four single-
byte fetches plus some shifting and or-ing instead of
just reading an `int' out of memory.

Some compilers don't bother with this kind of stuff,
presumably because the compiler writers had better things
to do than pamper poor programmers!

If a compiler doesn't make special provision for mis-
aligned data, three behaviors are common:

- The mis-aligned access causes a trap of some kind,
and your program crashes. (Some systems raise a
SIGBUS signal when this happens.)

- The mis-aligned access causes a trap that invokes
a software fixer-upper. After a bunch of single-
byte accesses and suitable bit-bashing, your program
continues to run -- or, rather, continues to crawl.

- The hardware simply ignores the offending address
bits and your program goes merrily on its way. Alas,
it has accessed some data "near" the data you were
actually trying to touch ...

From the point of view of the C language, this is not
an exhaustive list of the possible outcomes. In fact, it
is not possible to construct such a list; all C says is
that a mis-aligned access causes "undefined behavior,"
meaning that anything at all could occur. "Anything at
all" is a very large territory with very few maps, best
avoided.

When you need to slosh data with possibly strict alignment
requirements in and out of buffers with less stringent needs,
it's just not safe to pretend that the un-aligned bytes are
really an instance of the data object. Before you can treat
them as an `int' or a `struct timeval' or whatever, the only
safe course is to copy them byte-by-byte into an actual instance
of the appropriate type. Your code was something of a special
case, because (1) the buffer was obtained from calloc() and
all such buffers are aligned so as to meet the strictest of
alignment requirements, and (2) you filled the buffer with
multiple copies of the same type of struct, laid end-to-end.
In effect you've used the buffer as an array of structs, and
that will work just fine. But if you start mixing and matching
different types of data in such a buffer, alignment issues
will bite you.

--
Er*********@sun.com

Mar 20 '06 #5
Er*********@sun.com wrote...

Simple Simon wrote On 03/20/06 17:51,:
[... concerning alignment ...]
This is a great concern, although it isn't biting me yet. Does this
type of alignment problem have a commonly referenced name, so that I
can learn more about it?
Alignment requirements are generally referred to as,
er, "alignment requirements." (Who'd have guessed?)
Do compilers generally support flags that address this, or are you
just hosed if a problem like this arises?


Some compilers are able to generate code that will
correctly access mis-aligned data, usually at a penalty
in speed. For example, they might perform four single-
byte fetches plus some shifting and or-ing instead of
just reading an `int' out of memory.

Some compilers don't bother with this kind of stuff,
presumably because the compiler writers had better things
to do than pamper poor programmers!

If a compiler doesn't make special provision for mis-
aligned data, three behaviors are common:

- The mis-aligned access causes a trap of some kind,
and your program crashes. (Some systems raise a
SIGBUS signal when this happens.)

- The mis-aligned access causes a trap that invokes
a software fixer-upper. After a bunch of single-
byte accesses and suitable bit-bashing, your program
continues to run -- or, rather, continues to crawl.

- The hardware simply ignores the offending address
bits and your program goes merrily on its way. Alas,
it has accessed some data "near" the data you were
actually trying to touch ...

From the point of view of the C language, this is not
an exhaustive list of the possible outcomes. In fact, it
is not possible to construct such a list; all C says is
that a mis-aligned access causes "undefined behavior,"
meaning that anything at all could occur. "Anything at
all" is a very large territory with very few maps, best
avoided.


Your post was prescient -- the very next problem I ran into was an
alignment issue. I had an incoming data stream of the structure 7
bytes (substructure: 3 1 1 1 1 bytes) then a short int, then some
other stuff.

I used a struct like so, which reflected the structure of the data

typedef struct {
char ca[3] ;
char c1[1] ;
char c2[1] ;
char c3[1] ;
char c4[1] ;
short int i ;

// ...other stuff...

} record ;

....

record * rp = (record *)record_buffer ;

....and rp->i always contained bytes 8 and 9 of the record_buffer,
instead of bytes 7 and 8.

I dumped memory of record_buffer and the bytes 7 and 8 were the ones
I wanted, but the cast above gave me bytes 8 and 9 of record_buffer.

I figured out an undoubtably very clumsy and inelegant way of getting
what I needed, but thanks for your help overall, and for making me
sensitive to the nature of my next problem before it had even arisen.
When you need to slosh data with possibly strict alignment
requirements in and out of buffers with less stringent needs,
it's just not safe to pretend that the un-aligned bytes are
really an instance of the data object. Before you can treat
them as an `int' or a `struct timeval' or whatever, the only
safe course is to copy them byte-by-byte into an actual instance
of the appropriate type. Your code was something of a special
case, because (1) the buffer was obtained from calloc() and
all such buffers are aligned so as to meet the strictest of
alignment requirements, and (2) you filled the buffer with
multiple copies of the same type of struct, laid end-to-end.
In effect you've used the buffer as an array of structs, and
that will work just fine. But if you start mixing and matching
different types of data in such a buffer, alignment issues
will bite you.


Mar 21 '06 #6
"Simple Simon" <ss****@domain.invalid> wrote in message
news:MP************************@news.verizon.net.. .
Your post was prescient -- the very next problem I ran into was an
alignment issue. I had an incoming data stream of the structure 7
bytes (substructure: 3 1 1 1 1 bytes) then a short int, then some
other stuff.

I used a struct like so, which reflected the structure of the data

typedef struct {
char ca[3] ;
char c1[1] ;
char c2[1] ;
char c3[1] ;
char c4[1] ;
short int i ;

// ...other stuff...

} record ;

...

record * rp = (record *)record_buffer ;

...and rp->i always contained bytes 8 and 9 of the record_buffer,
instead of bytes 7 and 8.

I dumped memory of record_buffer and the bytes 7 and 8 were the ones
I wanted, but the cast above gave me bytes 8 and 9 of record_buffer.

I figured out an undoubtably very clumsy and inelegant way of getting
what I needed, but thanks for your help overall, and for making me
sensitive to the nature of my next problem before it had even arisen.


What's happening is that your compiler is inserting a padding byte before
the short so that it'll be aligned correctly. When you cast struct
pointers, this will get you into serious trouble. The only semi-portable
way around this is to use all chars (or an array of them) and handle the
extraction yourself, but that breaks too if CHAR_BIT isn't what you expect.

If you _know_ your code will only run on certain platforms, you can usually
rearrange the struct so there will be no padding inserted, but it's good
practice to add some assert()s clauses so someone trying to port the code
will be informed if there's a problem with your assumptions.

S

--
Stephen Sprunk "Stupid people surround themselves with smart
CCIE #3723 people. Smart people surround themselves with
K5SSS smart people who disagree with them." --Aaron Sorkin

*** Free account sponsored by SecureIX.com ***
*** Encrypt your Internet usage with a free VPN account from http://www.SecureIX.com ***
Mar 21 '06 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

8
by: Bob Keith | last post by:
Hello, all: I am a beginner of C++, and feel confusing about the differences of the following terms regarding pointer. int *a int* a int** a int*& a int *&a
10
by: homecurr | last post by:
Here is my code Class A; Class B; Class C : public A, public B { .... } Class D {
7
by: Fatted | last post by:
I'm trying to learn how to create arrays dynamically. But its just not happening. Have a look at code below and point and laugh where appropriate... First part of program, I'm using an array of...
5
by: Danilo Kempf | last post by:
Folks, maybe one of you could be of help with this question: I've got a relatively portable application which I'm extending with a plugin interface. While portability (from a C perspective) is...
3
by: David Mathog | last post by:
This one is driving me slightly batty. The code in question is buried deep in somebody else's massive package but it boils down to this, two pointers are declared, the first is: char **resname...
26
by: Martin Jørgensen | last post by:
Hi, I don't understand these errors I get: g++ Persort.cpp Persort.cpp: In function 'int main()': Persort.cpp:43: error: name lookup of 'j' changed for new ISO 'for' scoping Persort.cpp:37:...
51
by: Kuku | last post by:
What is the difference between a reference and a pointer?
26
by: Bill Reid | last post by:
Bear with me, as I am not a "professional" programmer, but I was working on part of program that reads parts of four text files into a buffer which I re-allocate the size as I read each file. I...
19
by: mail1779205 | last post by:
I (certainly) hope I know what this function does: char *fun(void){ char *ptr = "Hello World"; return ptr; } It returns a pointer to a string stored somewhere in the memory and is...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.