I’m trying to use the memory allocated beyond the size of a struct to mimic a ‘payload’
and to allow that payload contain a pointer to another struct. Can someone tell me if this is possible or if what i’m trying to do is not feasible.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define ptrsize sizeof(char*)
typedef struct s{
int i;
short j;
long k;
}S;
S *salloc(int sz,int i,short j,long k){
S *m=malloc(sizeof(S)+sz);
m->i=i;m->j=j;m->k=k;
return m;
}
char *goToData(S *m){
char* dataloc=(char*)m+sizeof(S);
return dataloc;
}
int main(int argc,char **argv){
char a[]={"ABCDEFGHIJKLMNOPQRSTUVWXYZ"};
S *mys=salloc(26,2,3,100); // struct * to size 26+sizeof(S) & set struct vars
char *mydp=goToData(mys); // get the address of the payload
memcpy(mydp,a,sizeof(a)); // copy a into the payload
S *mysc=salloc(ptrsize,1,2,3); // allocate a container struct
char *datapw=goToData(mysc); // go to the first byte of the payload of mysc
(*(S**)datapw)=mys; // want to point at mys -- is this possible?
printf("%d\n",ptrsize);
printf("addr mys %x\n",(unsigned int)mys);
printf("addr mysc %x\n",(unsigned int)mysc);
printf("addr mysc | *datapw %x\n",(unsigned int)*datapw); // from here would like to be indirectly reference mys
return 0;
}
The
goToData()function seems to be sound. The memory allocation is sound, though you don’t record how big the space is that was allocated after the structure.There’s a buffer overflow here:
You allocated 26 bytes but you’re copying 27 (
sizeof(a) == 27becausesizeof()counts the NUL'\0'at the end). That is a recipe for disaster. Don’t use elegant variation in C; use consistency. Either use 26 in both places orsizeof(a), but not a mixture.If there’s a problem, it is with the line:
I’m not even sure I understand what you’re trying to do here, but it doesn’t look good at all.Although
datapwis aligned for use as anS *, you haven’t allocated enough space for that to be used. I’m not clear that you should be converting it to aS**before dereferencing.If you are trying to make the space after the structure pointed at by
mysccontain a pointer to the structure pointed at bymys, then you had better have a really good reason for not including the pointer in the structure. A really, really good reason.However, that code is accurate, despite my strong misgivings. But it is extremely opaque.
I think you should get the result you want with:
I hate to think what the strict-aliasing implications are, though you might be OK since there is an exemption of some sort for
char *.So, revisit that statement and work out what you are trying to do – because what you’ve written doesn’t do it, whatever it was.This has some issues. Since
datapwis achar *,*datapwis going to be a character. Probably not what you had in mind.(unsigned int)*(S **)is what you need, I think.The rest is OK-ish, though on a 64-bit system, addresses are too big for
%x. You’ll get away with on a 32-bit system, but you should use either%pwith(void *)casts, or"%" PRIXPTRfrom<inttypes.h>with a(uintptr_t)cast.I ended up with:
(I compile with
-Wmissing-prototypes; thestaticin front of the functions prevents the compiler warning me about these functions. Since you aren’t using the arguments tomain(), I replacedargcandargvwithvoidfor the same reason – to avoid compiler warnings.)When I ran it under
valgrindon a Mac (MacOS X 10.7.2, GCC 4.2.1, Valgrind 3.7.0), I got a clean run with the data output: