I have the following struct
struct NETWORK_ENDPOINT {
unsigned char Type;
unsigned char Protocol;
unsigned char IPv4[IPV4SIZE + 1];
unsigned int PortNumber;
unsigned char SocketIndex;
unsigned char RESERVED;
unsigned char *InboundData;
unsigned int InboundDataSize;
unsigned char *OutboundData;
unsigned int OutboundDataSize;
};
In the code I'm allocating with :
struct NETWORK_ENDPOINT *Endpoint = malloc(sizeof(struct NETWORK_ENDPOINT));
Then later in the code I'm allocating the OutboundData with.
Endpoint->OutboundData = malloc(20); // malloc() size may vary,
// but in the problem situation it is 20
Then I do :
memcpy(Endpoint->OutboundData, Data, 20);
Then the problem : From the debugger I can see that Endpoint is given address #0x1fd6, and the OutboundData is given address #0x1fca, so only 12 between. Shouldn't is be atleast 20 ?
The memcpy() function then will fill out in OutboundData ( can see in memory that data is correctly placed ), but once it passes 12 bytes, it will begin overwriting the start of the struct Endpoint, corrupting the Type and Protocol and half the IP, thereby making it useless afterwards.
anyone got any idea what I'm going wrong here ? Been working on this for days now, but whatever I try it does not fix this issue...
Have tried to increase the HEAP size, but it seems to stay at 12 bytes between the two memory locations no matter what I do..
OutboundData is given address #0x1fca, so only 12 between
Why you're interested in the address of OutboundData?
After malloc(), you should be checking the value of OutboundData, however, you won't be knowing the size of allocated memory thr' this.
Just to be clear, you're not copying to the address of OutboundData, rather , you are copying to the address pointed by OutboundData.
Then,
but once it passes 12 bytes, it will begin overwriting the start of the struct Endpoint, corrupting the Type and Protocol and half the IP, thereby making it useless afterwards.
No, it won't. The value and address of OutboundData are different and the value of OutboundData is used in memcpy().
IMHO, as long as
malloc() is success
Data is atleast of size 20 (for this case)
your memcpy() should work fine.
Related
So, to start off I've already looked at a few questions including this one and none of them seem to help.
I'm simply trying to write a function that extends the size of an array using realloc().
My code currently looks like this:
unsigned char *xtnd = malloc(4);
xtndc(&xtnd, 4);
// sizeof(*xtnd) should now be 8
void xtndc ( unsigned char ** bytesRef , uint8_t count ) {
*bytesRef = realloc(*bytesRef, (sizeof(**bytesRef)) + count);
}
But no matter what I do it seems that the size of xtnd is always 4. After running xtndc() on it it should now be 8 bytes long.
Any suggestions?
The type of **bytesRef is unsigned char, so sizeof(**bytesRef) is 1. sizeof doesn't keep track of dynamic allocations, it's a compile time tool that gives you the size of a type, in this case unsigned char.
You have to keep track of the array size manually to calculate the new required size.
Your program does in fact change the size of the memory block. It changes the size of your original memory block from 4 bytes to 5 bytes. It changes to 5 bytes because you are essentially doing sizeof(unsigned char) + 4 which 1 + 4 = 5. If you want to double the size instead, do count*sizeof(unsigned char) + count. There are two points to be noted here:
The sizeof function returns the size of the data type, not the size of the allocated bytes. There is no way to know the size of the dynamically allocated memory.
The function realloc (and malloc and calloc as well) is not always guaranteed to return the requested reallocation. It may or may not succeed all the time.
I fixed the problem with the following code.
typedef struct CArrPtr {
unsigned char* ptr;
size_t size;
} CArrPtr;
void xtndc ( CArrPtr *bytesRef, uint8_t count );
. . .
CArrPtr xtnd = { .ptr = malloc(4), .size = 4 };
xtndc( &xtnd, 4 );
// xtnd.size is now 8 bytes
. . .
void xtndc ( CArrPtr *bytesRef, uint8_t count ) {
unsigned char *nptr;
if((nptr = realloc(bytesRef->ptr, bytesRef->size + count)) != 0)
{
bytesRef->ptr = nptr;
bytesRef->size = bytesRef->size + count;
}
}
As I am somewhat new to C, what I learned from this is that malloc specifically creates a pointer to a memory block, but you have no direct access to information about the memory block. Instead, you must store the size of the array that you created with malloc somewhere as well.
Since in the past I'd been initializing arrays with unsigned char arr[size]; and then using sizeof on it, I was under the impression that sizeof returned the size of the array, which is of course wrong as it gives you the size of a type.
Glad I could learn something from this.
sizeof is used to calculate size of data type or array. Pointer and array are very similar, but they are different things. For int *ap, sizeof(ap) will return 4 on x86, sizeof(*ap) will return 4; for int a[10], sizeof(a) will return 40.
sizeof expression is processed at compile time, so it will be a constant written into the executable file before you run the program.
malloc and realloc don't maintain size.
If realloc succeeds, it will reallocate the requested size. So you don't need to check the size after realloc returns, but you should check the return value of realloc to ensure that realloc succeeds.
If I want to reduce malloc()s (espacially if the data is small and allocated often) I would like to allocate the pointer and pointee at once.
If you assume something like the following:
struct entry {
size_t buf_len;
char *buf;
int something;
};
I would like to allocate memory in the following way (don't care about error checking here):
size_t buf_len = 4; // size of the buffer
struct entry *e = NULL;
e = malloc( sizeof(*e) + buf_len ); // allocate struct and buffer
e->buf_len = buf_len; // set buffer size
e->buf = e + 1; // the buffer lies behind the struct
This could even be extende, so that a whole array is allocated at once.
How would you assess such a technuique with regard to:
Portability
Maintainability / Extendability
Performance
Readability
Is this reasonable? If it is ok to use, are there any ideas on how to design a possible interface for that?
You could use a flexible array member instead of a pointer:
struct entry {
size_t buf_len;
int something;
char buf[];
};
// ...
struct entry *e = malloc(sizeof *e + buf_len);
e->buf_len = buf_len;
Portability and performance are fine. Readability: not perfect but good enough.
Extendability: you can't use this for more than one member at a time, you'd have to fall back to your explicit pointer version. Also, the explicit pointer version means that you have to muck around to ensure correct alignment if you use it with a type that doesn't have an alignment of 1.
If you are seriously thinking about this I'd consider revisiting your entire data structure's design to see if there is another way of doing it. (Maybe this way is actually the best way, but have a good think about it first).
As to portability, I am unaware of any issues, as long as the sizes are found via suitable calls to sizeof(), as in your code.
Regarding maintainability, extendability and readability, you should certainly wrap allocation and de-allocation in a well-commented function. Calls to...
entry *allocate_entry_with_buffer();
void deallocate_entry_with_buffer(entry **entry_with_buffer);
...do not need to know implementation details of how the memory actually gets handled. People use stranger things like custom allocators and memory pools quite frequently.
As for speed, this is certainly faster than making lots of small allocations. I used to allocate whole 2D matrices with a similar strategy...
It should work, but in fact you are using a pointer for a useless indirection. Windows API (for example) uses another method for variable size structs : the variable size buffer is last in struct and is declared to be char buf[1].
Your struct would become :
struct entry {
size_t buf_len;
int something;
char buf[1];
};
The allocation is (still no error checking) :
size_t buf_len = 4; // size of the buffer
struct entry *e;
e = malloc( sizeof(*e) + buf_len - 1); // struct already has room for 1 char
e->buf_len = buf_len; // set buffer size
That's all e.buf is guaranteed to be a char array of size buf_len.
That way ensures that even if the variable part was not a character array but a int, long, or anything array, the alignement would be given by the last element being a array of proper type and size 1.
For starters, the line:
e->buf = e + sizeof(*e); // the buffer lies behind the struct
Should be:
e->buf = e + 1; // the buffer lies behind the struct
This is because e + 1 will be equal to the address at the end of the structure. As you have it, it will only be the number of bytes into the structure equal to the number of bytes in a pointer.
And, yes, it's reasonable. However, I prefer this approach:
struct entry {
size_t buf_len;
int something;
char buf[1];
};
This way, you don't mess with the pointers. Just append as many bytes as needed, and they will grow the size of your buf array.
Note: I wrote a text editor using an approach similar to this but used a Microsoft c++ extension that allowed me to declare the last member as char buf[]. So it was an empty array that was exactly as long as the number of extra bytes I allocated.
seems fine to me - put comments in though
Or you could do this - which is quite common
struct entry {
size_t buf_len;
int something;
char buf;
};
ie make the struct itself variable length. and do
size_t buf_len = 4; // size of the buffer
struct entry *e = NULL;
// check that it packs right
e = malloc(sizeof(size_t) + sizeof(int) + buf_len ); // allocate struct and buffer
e->buf_len = buf_len; // set buffer size
...... later
printf(&e.buf);
I'm assuming its a pointer issue again, but what I'm trying to do here is have a function search memory to see if an IP address exists, and if it doesn't then a random memory space is reserved for the IP address and zero is returned. the function takes an IP address as a string as the 1st parameter and the second parameter points to the struct. When the main() function is executed, result should equal 0 and result2 should equal 1, but instead, I get crashes, and I think it has to do with the way I'm assigning pointers?
In this fragment...
ip=(iprec*)p;
I'm trying to set the iprec structure passed into the function (and previously allocated by malloc), but I'm not sure where to add or remove stars from that statement.
Here is the rest of the code.
char *shma;
typedef struct{
unsigned char u;
unsigned char a[4];
unsigned int otherdata;
} iprec;
static int loadip(char* remoteip,iprec *ip){
char *p=shma;
int v=0;
char *ep;
unsigned char a[4];
sscanf(remoteip,"%d.%d.%d.%d",a[0],a[1],a[2],a[3]);
int i,n;int sz=5000;
int szr=sizeof(iprec);
for (i=3;i<sz;i+=szr){
ip=(iprec*)p;
if (ip->u=='Y'){
for (n=0;n<=4;n++){
if (a[n]!=ip->a[n]){break;}
}
if (n >= 3){v=1;break;}
}else{
ep=p;
}
p+=szr;
}
if (v==0){
ip=(iprec*)ep;
for (n=0;n<=3;n++){
ip->a[n]=a[n];
}
}
return v;
}
int main(){
char *shma=(char*)malloc(5000); //alloc 5000 bytes for example.
iprec *x=(iprec*)malloc(sizeof(iprec));
int result=loadip("127.0.0.1",x);
int result2=loadip("127.0.0.1",x);
}
Replace
sscanf(remoteip,"%d.%d.%d.%d",a[0],a[1],a[2],a[3]);
With
sscanf(remoteip,"%d.%d.%d.%d",&a[0],&a[1],&a[2],&a[3]);
sccanf needs pointer type arguments.
shma should be global.
I haven't done a full analysis of your code, but here is a source of your crash. At the bottom is a resolution
Analysis
At the top of your snippet, you have
char *shma;
This is a file-scope (global) object called shma that has static duration storage. It gets initialized to 0 prior to main() executing.
Then, in main, you have:
int main(){
char *shma=(char*)malloc(5000); //alloc 5000 bytes for example.
Here you declare a new object called shma. It has block scope (exists only within the context of main), with automatic storage. You assign to it a pointer from malloc(). Then you call loadip.
loadip has
char *p=shma;
Which declares a new object called p with block scope (exists in loadip) with automatic storage. You set it to shma. NOTE this is assigning the global shma, not the one in main, because the one in main only exists within main, and loadip is outside of main. The global shma was 0, so now p is also 0 (at least for your first loop).
Then, you do:
ip=(iprec*)p;
so, since p was 0, now ip is 0. In the next line:
if (ip->u=='Y'){
you are dereferencing ip to obtain member u. On most systems, this dereference will result in a segmentation fault (or similar memory access violation), because you have essentially dereferenced NULL (the 0 address).
Fix for this issue
Change
int main(){
char *shma=(char*)malloc(5000); //alloc 5000 bytes for example.
into
int main(){
shma=(char*)malloc(5000); //alloc 5000 bytes for example.
This will result in main assigning to the global shma instead of creating a new local one.
Its a while since I've done C, but a few thoughts :
char *p=shma;
but shma has not yet been initialised - and consequently the "ip=(iprec*)p;" means ip will not be a valid value.
unsigned char a[4];
sscanf(remoteip,"%d.%d.%d.%d",a[0],a[1],a[2],a[3]);
you need the address of the receiving variables (ie. &a[0], &a[1], ...).
Also, since '%d' will write 4 byte integers (the scanf doesn't know it's a char array), better to have "int a[4]"
ip=(iprec*)p;
But ip is an input parameter - so here you're overwriting (ie. throwing away) whatever value the user supplied in the second argument.
if (v==0){
ip=(iprec*)ep;
Even if v=0, it is still possible that ep has not been initialised (eg.if all ip->u == 'Y' but the a-arrays differ on the first or second values)
I am creating a linked list for a class project that stores some stock market data. I was trying to store some data onto the stack instead of mallocing to the heap. I am trying to do this using memcpy. My code is like this:
struct trade{
int a,b;
float c;
struct trade *n;
};
char stack[100];
int i = 0;
void newNode(struct trade **head, int a, int b, float c){
struct trade *node;
if(i<99){
memcpy(&a,&stack[i],4);
i = i + 4;
node = (struct lnode*) malloc(16);
}
else
node = (struct lnode*) malloc(20);
}
.....
.....
}
My newnode function is called whenever I create a new node and I need to malloc space for it.
I copy the int into the stack array if there is still space in the stack array else I malloc into the heap. I use 20 and 16 because if I am storing the int in the stack then I need to malloc space for the remaining 16 bytes in my struct else I malloc space for 20 bytes.
For some reason I get a segfault when I do this. I would appreciate it if someone could point me in the right direction.
Thanks!
You've got your memcpy arguments swapped. The destination should be the first argument:
memcpy(&stack[i],&a,4);
From the manpage:
SYNOPSIS
void * memcpy(void *restrict s1, const void *restrict s2, size_t n);
DESCRIPTION
The memcpy() function copies n bytes from memory area s2 to memory area
s1. If s1 and s2 overlap, behavior is undefined. Applications in which
s1 and s2 might overlap should use memmove(3) instead.
If you're compiling for anything but 32-bit x86, integers and pointers will not be 4 bytes, but e.g. 8 for 64-bit, which would cause problems. You should really use sizeof(int). This will also affect the 16 and 20, which you can probably replace with sizeof(lnode). These are set to the correct values at compile time, so won't affect speed.
Besides the issue with defining "stack" versus heap: why do you define your stack as a char array rather than int if you're putting ints in there? It's possible to use a char array, but it's a lot easier and less error-prone to just assign rather than memcpy to an array of the same type.
Valgrind is your friend for this kind of debugging. I find myself using it as a standard debugging tool for segfaults and memory leaks.
so I have the following enum method in c:
enum enum_type GetInfo (int socket, unsigned char *data)
{
}
and at the api I can find this:
Received data is written to pointer *data....
So if I'm doing something like this:
unsigned char *data;
enum_type enum1;
enum1 = GetInfo (int socket, data);
I got an segmentation fault.
What's my problem?
Thanks,
Simon
Your problem is that you haven't allocated space for data but try to write to it. Do
unsigned char *data = malloc(sizeof(unsigned char) * MYBUFLENGTH);
and then pass data to GetInfo. At the end do not forget to
free(data);
Alternatively you could allocate space on stack (available in C99, some compilers support it as extension even with earlier versions of the C Standard)
unsigned char data[MYBUFLENGTH];
In this case you should not worry about memory management.
you need to allocate memory to store the data in.
for instance:
unsigned char data[10000]; /* allocate 10000 bytes */
enum_type enum1;
enum1 = GetInfo(socket, data);
If you don't understand what's going on, I recommend spending time to read up on pointers.
not sure how big the info is, but try the following
unsigned char data[512] = {0};
enum_type enum1;
enum1 = GetInfo (socket, data);
this makes sure, that data points to a valid memory address on the stack.
It's maybe because GetInfo wants to write to a buffer pointed by data, and you just pass the pointer without allocating any memory space. Allocate memory and point it to data like this:
// I assume you need 1000 bytes
data = (unsigned char*)malloc(1000*sizeof(unsigned char));