I am trying to understanding devm_kzalloc() function implementation. It is allocating more than the requested memory(sizeof(struct devres) + size) to manage resources.
struct devres is defined as follows, the second member is an incomplete array.
struct devres {
struct devres_node node;
/* -- 3 pointers */
unsigned long long data[]; /* guarantee ull alignment */
};
Following is the source to allocate memory.
size_t tot_size = sizeof(struct devres) + size;
struct devres *dr;
dr = kmalloc_track_caller(tot_size, gfp);
if (unlikely(!dr))
return NULL;
memset(dr, 0, tot_size);
INIT_LIST_HEAD(&dr->node.entry);
dr->node.release = release;
return dr;
I have following doubhts.
. It is caliculating the tot_size, but in struct devres the array is imcomplete.
. The devm_kzalloc() function(shown below) is returning dr->data as the starting of the requested memory. If we understand that array name contains the startig address of that array then we are allocating more than the requested memory. i.e size of unsigned long long + size.
void * devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)
{
struct devres *dr;
/* use raw alloc_dr for kmalloc caller tracing */
dr = alloc_dr(devm_kzalloc_release, size, gfp);
if (unlikely(!dr))
return NULL;
set_node_dbginfo(&dr->node, "devm_kzalloc_release", size);
devres_add(dev, dr->data);
return dr->data;
}
Could you please help me to understand this.
Thanks
I have understood now.
Its flexible array member feature of C99 used in "struct devres" structure definition.
Related
I am learning linux wifi drivers, and was exploring the code in cfg80211 subsytem for a scan request.
I can't understand why the following struct is allocated more memory than required.
Or, I can't understand the way the size of memory to be allocated is calculated in this way.
The struct is defined in include/net/cfg80211.h:
struct cfg80211_scan_request {
struct cfg80211_ssid *ssids;
int n_ssids;
u32 n_channels;
enum nl80211_bss_scan_width scan_width;
const u8 *ie;
size_t ie_len;
u16 duration;
bool duration_mandatory;
u32 flags;
u32 rates[NUM_NL80211_BANDS];
struct wireless_dev *wdev;
u8 mac_addr[ETH_ALEN] __aligned(2);
u8 mac_addr_mask[ETH_ALEN] __aligned(2);
u8 bssid[ETH_ALEN] __aligned(2);
/* internal */
struct wiphy *wiphy;
unsigned long scan_start;
struct cfg80211_scan_info info;
bool notified;
bool no_cck;
/* keep last */
struct ieee80211_channel *channels[0];
};
In file /net/wireless/nl80211.c, memory is being allocated to the struct as follows:
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
{
// ...
struct cfg80211_scan_request *request;
// ...
request = kzalloc(sizeof(*request)
+ sizeof(*request->ssids) * n_ssids
+ sizeof(*request->channels) * n_channels
+ ie_len, GFP_KERNEL);
// ...
}
I have a doubt that more memory is being allocated than required. Or, the way size is calculated in kzalloc doesn't make sense to me.
This is what I expect the code to be like:
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
{
// ...
struct cfg80211_scan_request *request;
// ...
request = kzalloc(sizeof(*request)
+ sizeof(*request->channels) * n_channels,
GFP_KERNEL);
// ...
}
Why that much size of memory is allocated then?
What I'm understanding is kzalloc(struct + flexible_array_member + extra_len_but_why).
Presumably the code after the kzalloc sets the values of the pointers requests->ssids and requests->ie so that they point into the newly allocated memory, just after the struct.
That way, only one block of memory needs to be allocated for the three arrays.
EDIT: I found the function in question, and indeed, just after the kzalloc call shown in the OP, we find the following, which sets up the ssids and ie pointers:
if (n_ssids)
request->ssids = (void *)&request->channels[n_channels];
request->n_ssids = n_ssids;
if (ie_len) {
if (n_ssids)
request->ie = (void *)(request->ssids + n_ssids);
else
request->ie = (void *)(request->channels + n_channels);
}
I'm writing an Arena Allocator and it works, but I feel like it violates strict aliasing rules. I want to know if I'm right or wrong. Here's the relevant part of the code:
typedef struct ArenaNode ArenaNode;
struct ArenaNode {
ArenaNode *next;
size_t dataSize;
u8 data[];
};
typedef struct {
ArenaNode *head;
ArenaNode *current;
size_t currentIndex;
} Arena;
static ArenaNode *ArenaNodeNew(size_t dataSize, ArenaNode *next)
{
ArenaNode *n = malloc(sizeof(ArenaNode) + dataSize);
n->next = NULL;
n->dataSize = dataSize;
return n;
}
void *ArenaAlloc(Arena *a, size_t size)
{
const size_t maxAlign = alignof(max_align_t);
size_t offset = nextHigherMultiplePow2(offsetof(ArenaNode, data), maxAlign) - offsetof(ArenaNode, data);
size_t dataSize = offset + max(size, ARENA_SIZE);
// first time
void *ptr;
if (a->head == NULL) {
ArenaNode *n = ArenaNodeNew(dataSize, NULL);
a->head = n;
a->current = n;
ptr = n->data + offset;
a->currentIndex = nextHigherMultiplePow2(offset + size, maxAlign);
} else {
// enough space
if (a->currentIndex + size <= a->current->dataSize) {
ptr = &a->current->data[a->currentIndex];
a->currentIndex = nextHigherMultiplePow2(a->currentIndex + size, maxAlign);
} else {
ArenaNode *n = ArenaNodeNew(dataSize, NULL);
a->current->next = n;
a->current = n;
ptr = n->data + offset;
a->currentIndex = nextHigherMultiplePow2(offset + size, maxAlign);
}
}
return ptr;
}
The Arena is a linked list of Nodes and a Node is a header followed by data u8 data[]. u8 is unsigned char.
I maintain the next available index (currentIndex) and advance data by this index and return it as void * (ptr = &a->current->data[a->currentIndex]). Does this violate strict aliasing rule because I'm converting a pointer to u8 to something else and using that?
My confusion comes from the fact that memory returned by malloc has no effective type. But since I'm casting the malloc'd pointer to ArenaNode * and setting its data members (next and dataSize) after allocating it (in ArenaNodeNew), the effective type becomes ArenaNode. Or does it? I didn't set data field of that.
Basically, I think the question can be simplified to this: If I malloc a memory region of say, size 10, cast the pointer to struct {int a;} * (assume 4 bytes int), set it a to something, what happens to the rest of the 6 bytes? Does it have any effective type? Does the presence of flexible array member affect this in any way?
The extra bytes that are part of the flexible array member will have the effective type of that member as you write to them.
You can safely declare ptr as u8 * and define your function to return that type as well.
In your example of allocating 10 bytes and treating the first 4 as a struct of the given type, the remaining bytes have no effective type yet. You can use those for any type, assuming the pointer you use is aligned correctly, i.e. you can point a int * to the following bytes but not a long long *. due to alignment.
Does this violate strict aliasing rule because I'm converting a pointer to u8 to something else and using that?
No, you are not violating strict aliasing, but your code might violate the constraints imposed by 7.22.3 Memory management functions, paragraph 1:
The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated ...
You don't appear to be making sure the memory you use for any object is "suitably aligned" for any object. Given 6.3.2.3 Pointers, paragraph 7's statement:
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined.
you appear to be risking undefined behavior.
"Suitably aligned" is extremely platform-dependent.
I'm recently working on a project in C. I have a requirement to allocate an array inside a struct and its size need to be obtained from the user. But because of specific requirements, I cannot use pointers and then allocate memory using malloc.
My code is as follows:
#define arraySize size
typedef struct sample{
int keys[arraySize]
int pointers[arraySize + 1]
} sample;
int main(){
//size should be obtained from user input
size = 15;
}
If the struct is defined inside main, it works fine but the issue is then the struct won't be global. If I declare the struct as mentioned in the code it gives the error message stating that the array size needs to be constant. Can anyone help me with this issue?
(Just giving examples for the comments.)
I think there are a few typical ways of handling your scenario:
Method 1: Global pointer to resources allocated on main's stack (already suggested in other comments):
This variant uses the C99 feature / GCC extension (w.r.t C89) for variably-modified types / variably modified arrays, per Jonathan Leffler's comment.
struct sample *globalSample = NULL;
int main(){
//size should be obtained from user input
size = 15;
struct sample{
int keys[size];
int pointers[size + 1];
} mySample;
globalSample = &mySample;
}
This variant uses alloca and "flexible array member". Per Jonathan Leffler's comment below note the change of officially defined syntax for this between C89 and later revisions of the C spec.
struct inner {
int key;
int pointer;
};
struct sample {
unsigned int num_allocated;
struct inner members[1]; // struct hack
};
struct sample *globalSample = NULL;
int main(){
//size should be obtained from user input
size = 15;
globalSample = alloca((size+1) * sizeof(struct sample));
globalSample->num_allocated = size; /*just for book-keeping*/
globalSample->members[0].key = /*...*/;
globalSample->members[0].pointer = /*...*/;
globalSample->members[1].key = /*... reaching past declared size */
globalSample->members[1].pointer = /*...*/;
}
Method 2: Define a max size, and validate user input against it.
#define MAX_ENTRIES 4096
struct sample{
int keys[MAX_ENTRIES];
int pointers[MAX_ENTRIES + 1];
} globalSample;
int main(){
//size should be obtained from user input
size = 15;
if(MAX_ENTRIES < size) { /* error case */ }
}
I've read some of the pages regarding how to ask questions, so I hope this is up to standard.
Our professor wants us to build a custom malloc and free, one that uses buddy allocation. Instead of messing with the heap, he wants us to just use mmap to request 1 GiB of space from the OS:
MAX_MEM = 1 << 30.
void * base = mmap(NULL, MAX_MEM, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, 0, 0);
Each chunk of memory should have a header, and if the memory is empty, pointers to the next and previous free chunks via linked list.
I don't know how to say "I want to put this specific data in this specific place." I would imagine a free chunk to look like this in the memory:
[Occupancy (1 bit)][Size (7 bits)][prev pointer (8 bytes)][next pointer (8bytes)][junk]
So let's say that the whole 1 GiB is free. Pseudo Code:
Occupancy = 0; // 0 if empty, 1 if allocated
Size = 0011110; // where size in bytes = 2^Size
next = NULL;
prev = NULL; //note that these are part of a struct called mallocList
How would I create these variables at the address I want them in?
I tried this,
int MAX_MEM = 1 << 30;
base = mmap(NULL, MAX_MEM, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, 0, 0);
*((unsigned char*) base) = 0x1E;
struct mallocList* temp;
temp->prev = NULL;
temp->next = NULL;
void* tempaddr = base + 1;
*((struct mallocList*) tempaddr) = *temp;
munmap(base, 1 <<30);
which compiled and ran without issue, but I realized trying to access the values,
printf("%c", *base); //line 37
struct mallocList* two;
two->prev = NULL;
two->next = NULL;
tempaddr->next = *two; //line 41
the compiler says,
3.c:37: warning: dereferencing ‘void *’ pointer
3.c:37: error: invalid use of void expression
3.c:41: warning: dereferencing ‘void *’ pointer
3.c:41: error: request for member ‘next’ in something not a structure or union
So I figure something's either wrong with my method of storing the data or retrieving it, and I'd greatly appreciate any help that could be offered.
Here's a header file mymalloc.h:
void *my_buddy_malloc(int size);
void my_free(void *ptr);
struct mallocList
{
struct mallocList *prev;
struct mallocList *next;
} mallocList;
Your compiler error explains the main problem: you can't dereference a void*. Cast the pointer to char* and store whatever bytes you want, or cast it to a struct yourstruct * and store to struct fields with p->field.
/* You need to tell gcc to pack the struct without padding,
* because you want the pointers stored starting with the second byte, i.e. unaligned.
* That's actually fine in *this* case, since they won't cross a cache-line boundary.
* They'll be at the beginning of a page, from mmap, and thus the beginning of a cache line.
* Modern CPUs are fast at handling misaligned loads within a cache line.
*/
struct __attribute__ ((__packed__)) mem_block {
unsigned int occupied:1;
unsigned int size:7; // bitfields. Not necessarily a good idea. Just using a signed int yourself might be better. positive for allocated, negative for free.
struct mallocList { // nested definition. You can do this differently
struct mallocList *prev, *next;
} pointers;
}; // don't need the type-name here. That would declare a variable of the struct type.
int MAX_MEM = 1 << 30;
void *base = mmap(NULL, MAX_MEM, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, 0, 0);
char *cp = base;
cp[0] = size << 1 | 1; // pack the size and occupied bits into a byte
struct mallocList *mlp = (struct mallocList*)(cp+1); // This avoids needing a compiler-specific way to pack your struct.
// or
struct mem_block *mbp = base;
mbp->occupied = 1;
mbp->size=whatever;
mbp->pointers.prev = NULL;
mbp->pointers.next = NULL;
This might not compile, sorry, but the basic idea about casting pointers is solid.
I am using ANSI C code, generated from a code generator that produces several layers of nested struct as well as function prototypes with argument lists that use pointers to the top layer struct for passing or accessing data located in the inner mmost struct.
Because the function prototypes pass pointers to struct, the application must allocate memory to access or write data to the inner most struct members. I am seeing the problem when attempting to allocate memory for the pointer to the second nested struct.
The actual error message I get is a non-fatal, run-time:
"Not enough space for casting expression to 'pointer to struct data'."
I am not explicitly casting anything, so I suspect the implementation of malloc() may have an assert that generates the message when it sees some condition. The wording of this error may be specific to my environment (I am using LabWindows/CVI) but I would be interested in hearing of results of other ANSI C compilers as well.
Here is a simplified, complete, code snippet that should compile, build and run (up to the error location, which is commented in-line)
I would appreciate comments on the cause of my error, and suggestions on how to fix it.
#include <ansi_c.h> //specific to LabWindows/CVI - change as needed for your environment
struct request
{
struct data *pData;
};
struct data
{
char *wsDate;
char *wsDuration;
char *wsFailures;
int __sizeM_Details;
struct details *M_Details;
};
struct details
{
char *wsStep;
char *wsTestDesc;
char *wsLowLim;
};
typedef struct request REQUEST; // from mtdf function prototype request argument (4)
typedef struct details DETAILS; // member of REQUEST - _ns1__MTDFData_MTDFDetail
void allocate(REQUEST *a, int numRecords);
void freemem(REQUEST *c, int numRecords);
int main(void)
{
REQUEST b, *pB;
pB = &b;
allocate(pB, 10);
freemem(pB, 10);
return 0;
}
void allocate(REQUEST *c, int numRecords)
{
DETAILS m_Param;
REQUEST b;
struct data d;
size_t size_c = sizeof(c);
c = malloc(size_c); //4 bytes
size_t size_c_data = sizeof(c->pData);
c->pData = malloc(size_c_data); //Breaks here - this is just a pointer,
//should it not just allocate 4 bytes
//and continue?
// Actual error message:
// "Not enough space for casting expression to 'pointer to struct data'."
c->pData->wsDate = calloc(80, sizeof(char));
c->pData->__sizeM_Details = numRecords;
c->pData->M_Details = calloc((numRecords + 1) , sizeof(m_Param));
}
void freemem(REQUEST *c, int numRecords)
{
free(c->pData->M_Details);
free(c->pData->wsDate);
free(c->pData);
free(c);
}
There's several fundamental problems, here:
In allocate(), all that memory you're malloc()ing is being lost at the end of your function, because you're assigning it to a local variable, c, which gets destroyed at the end of your function. You never use the address of the struct with automatic storage duration that you pass into the function. If you're passing the address of an object with automatic storage duration, then you should malloc() memory for the members, but not for the struct itself, since it obviously already has memory.
Then, in freemem(), you attempt to free() the memory associated with b, which is a struct with automatic storage duration. You can only free() memory that you've dynamically allocated.
You have a curious comment in allocate(), "this is just a pointer, should it not just allocate 4 bytes and continue?". If you're on a system with 32 bit pointers, then that is indeed what you allocated, but c->pData is a pointer to struct data which looks like it needs 28 bytes on a 32 bit machine, so you should be allocating a lot more than 4 bytes for it. Lines like c->pData->wsDate = ... seem to indicate that you're well aware it's a pointer to a struct data, so it's really unclear why you think you should only be allocating 4 bytes. When you allocate memory for an ANYTHING * to point to, then you need to allocate enough memory for an ANYTHING, not for an ANYTHING *, i.e. enough memory for the thing it's going to point to. The fact that you're trying to assign the memory to your pointer in the first place proves that you already have the memory for your pointer, otherwise you wouldn't be able to do that (providing that you haven't messed up some previous allocation, of course).
You never check the return from malloc() and calloc(), and you should.
Names beginning with a double underscore are always reserved for the implementation, so you should call __sizeM_Details something else.
sizeof(char) is 1 by definition, so there's never any need to use it.
It's unclear why you're allocating memory for numRecords + 1 of your struct details, rather than just numRecords as would seem intuitive. Perhaps you're looking to set that last one to NULL as a sentinel value, but if you're already storing the number of records in your struct, then this isn't really necessary.
Here's what your code ought to look like:
#include <stdio.h>
#include <stdlib.h>
struct request {
struct data * pData;
};
struct data {
char * wsDate;
char * wsDuration;
char * wsFailures;
int sizeM_Details;
struct details * M_Details;
};
struct details {
char * wsStep;
char * wsTestDesc;
char * wsLowLim;
};
typedef struct request REQUEST;
typedef struct details DETAILS;
void allocate(REQUEST * c, const int numRecords);
void freemem(REQUEST * c);
int main(void)
{
REQUEST b;
allocate(&b, 10);
freemem(&b);
return 0;
}
void allocate(REQUEST * c, const int numRecords)
{
if ( !(c->pData = malloc(sizeof *c->pData)) ) {
perror("couldn't allocate memory for c->pData");
exit(EXIT_FAILURE);
}
if ( !(c->pData->wsDate = calloc(80, 1)) ) {
perror("couldn't allocate memory for c->pData->wsDate");
exit(EXIT_FAILURE);
}
if ( !(c->pData->M_Details = calloc(numRecords + 1,
sizeof(*c->pData->M_Details))) ) {
perror("couldn't allocate memory for c->pData->M_Details");
exit(EXIT_FAILURE);
}
c->pData->sizeM_Details = numRecords;
}
void freemem(REQUEST * c)
{
free(c->pData->M_Details);
free(c->pData->wsDate);
free(c->pData);
}
If allocating automatic storage for b was a mistake, and you really do want to dynamically allocate everything, including your struct request, then it should look like this:
#include <stdio.h>
#include <stdlib.h>
struct request {
struct data * pData;
};
struct data {
char * wsDate;
char * wsDuration;
char * wsFailures;
int sizeM_Details;
struct details * M_Details;
};
struct details {
char * wsStep;
char * wsTestDesc;
char * wsLowLim;
};
typedef struct request REQUEST;
typedef struct details DETAILS;
REQUEST * allocate(const int numRecords);
void freemem(REQUEST * c);
int main(void)
{
REQUEST * b = allocate(10);
freemem(b);
return 0;
}
REQUEST * allocate(const int numRecords)
{
REQUEST * c = malloc(sizeof *c);
if ( !c ) {
perror("couldn't allocate memory for c");
exit(EXIT_FAILURE);
}
if ( !(c->pData = malloc(sizeof *c->pData)) ) {
perror("couldn't allocate memory for c->pData");
exit(EXIT_FAILURE);
}
if ( !(c->pData->wsDate = calloc(80, 1)) ) {
perror("couldn't allocate memory for c->pData->wsDate");
exit(EXIT_FAILURE);
}
if ( !(c->pData->M_Details = calloc(numRecords + 1,
sizeof(*c->pData->M_Details))) ) {
perror("couldn't allocate memory for c->pData->M_Details");
exit(EXIT_FAILURE);
}
c->pData->sizeM_Details = numRecords;
return c;
}
void freemem(REQUEST * c)
{
free(c->pData->M_Details);
free(c->pData->wsDate);
free(c->pData);
free(c);
}