container_of sample code in lwn.net - c

When seeing:
void my_object_release(struct kobject *kobj)
{
struct my_object *mine = container_of(kobj, struct my_object, kobj);
/* Perform any additional cleanup on this object, then... */
kfree (mine);
}
in LWN’s The zen of kobjects, it seems incorrect in the third parameter kobj. I think it should be kobject.

The given code is correct: the third argument is the name of the container structure member to which the pointer points, not its type, so kobj is right. The example is somewhat confusing since the first kobj doesn’t correspond to the same thing as the second kobj: the first is the pointer in the caller’s scope.
Here’s a diagram to hopefully clarify the parameters of container_of:
container_of(kobj, struct my_object, kobj)
| | |
| | |
\------------+----------+--------------------------------\
| | |
| | |
/-----------------/ | |
| | |
V /-------------/ |
+------------------+ | |
| struct my_object | { | |
+------------------+ V V
+------+ +------+
struct kobject | kobj |; <-- You have a pointer to this, called | kobj |
+------+ +------+
...
};
container_of allows you to pass around a kobject pointer and find the containing object (as long as you know what the containing object is) — it allows you to use your knowledge of “what” to answer “where”.
It’s worth pointing out that container_of is a macro, which is how it can do seemingly impossible things (for developers not used to meta-programming).

Related

Is there any gcc compiler warning which could have caught this memory bug?

I haven't programmed C for quite some time and my pointer-fu had degraded. I made a very elementary mistake and it took me well over an hour this morning to find what I'd done. The bug is minimally reproduced here: https://godbolt.org/z/3MdzarP67 (I am aware the program is absurd memory-management wise, just showing what happens).
The first call to realloc() breaks because of course, the pointer it's given points to stack memory, valgrind made this quite obvious.
I have a rule with myself where any time I track down a bug, if there is a warning that could have caught it I enable it on my projects. Often times this is not the case, since many bugs come from logic errors the compiler can't be expected to check.
However here I am a bit surprised. We malloc() and then immediately reassign that pointer which leaves the allocated memory inaccessible. It's obvious the returned pointer does not live outside the scope of that if block, and is never free()'d. Maybe it's too much to expect the compiler to analyze the calls and realize we're attempting to realloc() stack memory but I am surprised that I can't find anything to yell at me about the leaking of the malloc() returned pointer. Even clang's static analyzer scan-build doesn't pick up on it, I've tried various relevant options.
The best I could find was -fsanitize=address which at least prints out some cluing information during the crash instead of:
mremap_chunk(): invalid pointer
on Godbolt, or
realloc(): invalid old size
Aborted (core dumped)
on my machine, both of which are somewhat cryptic (although yes they do show plainly that there is some memory issue occurring). Still, this compiles without issues.
Since Godbolt links don't live forever here is the critical section of the code:
void add_foo_to_bar(struct Bar** b, Foo* f) {
if ((*b)->foos == NULL) {
(*b)->foos = (Foo*)malloc(sizeof(Foo));
// uncomment for correction
//(*b)->foos[(*b)->n_foos] = *f;
// obvious bug here, we leak memory by losing the returned pointer from malloc
// and assign the pointer to a stack address (&f1)
// comment below line for correction
(*b)->foos = f; // completely wrong
(*b)->n_foos++;
} else {
(*b)->foos = (Foo*)realloc((*b)->foos, ((*b)->n_foos + 1) * sizeof(Foo));
(*b)->foos[(*b)->n_foos] = *f;
(*b)->n_foos++;
}
}
the error occurs because f is a pointer to stack memory (intentional) but we obviously can't assign something that was supposed to have been malloc()'d to that.
Try -fanalyzer if your compiler is recent enough. When running it I get:
../main.c:30:28: warning: ‘realloc’ of ‘&f1’ which points to memory not on the heap [CWE-590] [-Wanalyzer-free-of-non-heap]
30 | (*b)->foos = (Foo*)realloc((*b)->foos, ((*b)->n_foos + 1) * sizeof(Foo));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
‘main’: events 1-2
|
| 37 | int main() {
| | ^~~~
| | |
| | (1) entry to ‘main’
|......
| 45 | add_foo_to_bar(&b, &f1);
| | ~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (2) calling ‘add_foo_to_bar’ from ‘main’
|
+--> ‘add_foo_to_bar’: events 3-5
|
| 19 | void add_foo_to_bar(struct Bar** b, Foo* f) {
| | ^~~~~~~~~~~~~~
| | |
| | (3) entry to ‘add_foo_to_bar’
| 20 | if ((*b)->foos == NULL) {
| | ~
| | |
| | (4) following ‘true’ branch...
| 21 | (*b)->foos = (Foo*)malloc(sizeof(Foo));
| | ~~~~
| | |
| | (5) ...to here
|
<------+
|
‘main’: events 6-7
|
| 45 | add_foo_to_bar(&b, &f1);
| | ^~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (6) returning to ‘main’ from ‘add_foo_to_bar’
| 46 | add_foo_to_bar(&b, &f2);
| | ~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (7) calling ‘add_foo_to_bar’ from ‘main’
|
+--> ‘add_foo_to_bar’: events 8-11
|
| 19 | void add_foo_to_bar(struct Bar** b, Foo* f) {
| | ^~~~~~~~~~~~~~
| | |
| | (8) entry to ‘add_foo_to_bar’
| 20 | if ((*b)->foos == NULL) {
| | ~
| | |
| | (9) following ‘false’ branch...
|......
| 30 | (*b)->foos = (Foo*)realloc((*b)->foos, ((*b)->n_foos + 1) * sizeof(Foo));
| | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | | |
| | | (10) ...to here
| | (11) call to ‘realloc’ here
|
No, but, runtime testing can save you.
If you can spare the execution overhead, I have seen many applications add an extra layer to memory allocation to track the allocations made and find leaks/errors.
Usually they replace malloc() and free() with a macros that include FILE and LINE
One example can be seen here (check the Heap.c and Heap.h files)
https://github.com/eclipse/paho.mqtt.c/tree/master/src
Googling "memory heap debugger" will probably turn up other examples. Or you could roll your own.

Confusion regarding nodes in a Linked List

I have a question about Linked Lists. I spoke to a friend and am now confused.
Suppose that there are two variables of type struct node. One is ptr and the other is the header node.
struct node
{
int data;
struct node *link;
};
struct node *ptr,*header;
What is the difference between
ptr=header
and
ptr->link=header
and
ptr->link=header->link
?
Edit:I mean semantically.
Assuming header is pointing to an allocated node initially, it will look like
+----------------+-----------+
| | |
header +-----------> | data | link+-----------> other node/NULL
| | |
+----------------+-----------+
After ptr=header, both ptr and header points to the same node
+----------------+-----------+
pointer +-----------> | | |
header +-----------> | data | link+-----------> other node/NULL
| | |
+----------------+-----------+
After ptr->link=header,
+----------------+-----------+
pointer +-----------> | | |
header +-----------> | data | link+----------+
+---> | | | |
| +----------------+-----------+ |
+-----------------------------------------+
after ptr->link=header->link, it would depend on where header and ptr are pointing
if they point to the same node then this statement will have no effect.
if they point to some different nodes then link pointer of both nodes pointed by ptr and header will point to the same node (or NULL).
+----------------+-----------+
| | |
header +-----------> | data | link+--------------+ |
| | | |
+----------------+-----------+ +------> |
|other node/NULL
+------> |
+----------------+-----------+ |
| | | |
ptr +-----------> | data | link+--------------+
| | |
+----------------+-----------+
Assuming you execute only one of these cases:
ptr=header would make a pointer to the header node. This means the data of ptr would be the same as the data in header. ptr->link would also be the same as header->link
ptr->link=header moves ptr infront of header in the list
ptr->link = header->link makes ptr parallel to header, e.g.:
ptr->data != header->data; // TRUE
a = ptr->link;
b = header->link;
a->data == b->data // TRUE
where a and b are of type struct node*
The best way to understand is to draw it out.

Association for type declaration statements in C

How are type declaration statements in C parsed (Right to Left or Left to Right)?
eg: consider the statement:
const char* const arr="hello";
How exactly is the above statement parsed?
Dear All, To those who found it difficult to understand my question:
In the above declaration statement arr is a variable. When the above statement is read by the compiler (which happens to parse the line) is arr considered a constant variable and then categorised as a character pointer or is it first recognised as a character pointer and then concluded with a constant value.
The doubt is due to the following thought:
If only const were to be declared ex: const int x; then the compiler does things behind the scene to make it a constant, and If I were to declare only a pointer ex: int* x; again compiler does things behind the scenes to categorise x as a pointer variable to distinguish it from just another integer variable. But in case the declaration is something like:
const int* const x; the behind the scenes action has to happen in some order so as x is recognised as and integer pointer variable and a const variable and then that has a constant value.
I would also be glad to hear the "behind the scenes" actions that C compiler does to separate between int variable char vaiable... pointer variable, register variable, In all how does a compiler recognise the difference.
Finally thanks for your patience to read such a long question.
Declarations aren't parsed strictly left to right or right to left. C declaration syntax is somewhat complicated.
Based on the grammar found in the online C2011 standard, section 6.7, your example parses out like so (skipping a few steps for brevity):
char const * const arr = "hello" ;
-+-- --+-- ^ --+-- -+- ^ ---+--- ^
| | | | | | | |
type type | type direct | initializer |
specifier qualifier | qualifier declarator | | |
| | | list | | | |
| | | | | | | |
| | +--+---+ | | | |
| | | | | | |
| | pointer | | | |
| | | | | | |
| | +------+------+ | | |
| | | | | |
| | declarator | | |
| | | | | |
| | +---------+----+-------+ |
| | | |
| | | |
| | | |
+---+----+ | |
| | |
declaration init-declarator-list |
specifiers | |
| | |
+-------------------------+-------+------------------------+
|
declaration
So, something to note about the pointer part of the declaration; the const following the * is part of the pointer non-terminal. That part of the grammar looks like this:
pointer:
* type-qualifier-listopt
* type-qualifier-listopt pointer
When you write T * const p, that means you are declaring p as a constant pointer; you will not be able to assign a different value to p (you can't make it point to a different object).
This also means you can declare an object like T * const * const p, or T * const restrict * volatile * p;. In each case, the list of type qualifiers is associated with the * appearing to their left.
The way to read hairy declarations is to start with the left-most identifier and work your way out, remembering the following rules:
*a[] - a is an array of pointer
(*a)[] - a is a pointer to an array
*f() - f is a function returning a pointer
(*f)() - f is a pointer to a function
* qual p - p is a qualified pointer
qual * p - p is a pointer to qualified type
where qualified may be one of const, volatile, restrict, or _Atomic. In the case of function declarations, you'll be applying these rules recursively to each function parameter.
So,
arr -- arr
* const arr -- is a const pointer to
char const * const arr -- const char
char const * const arr = "hello"; -- initialized to "hello"
This could also be written
const char * const arr = "hello";
and it will mean the same thing. The reason for this is that the declaration-specifiers non-terminal (which, in this case, covers the part of the declaration to the left of the *) is defined as
declaration-specifiers:
storage-class-specifier declaration-specifiersopt
type-specifier declaration-specifiersopt
type-qualifier declaration-specifiersopt
function-specifier declaration-specifiersopt
alignment-specifier declaration-specifiersopt
This syntax means you can have any one of a storage-class-specifier, a type-specifier, a type-qualifier, a function-specifier, or an alignment-specifier followed by zero or more additional such items (subject to certain constraints). This is how you can get declarations like
static unsigned long int x;
which parses as
static unsigned long int x ;
--+--- ----+--- --+- -+- ^ ^
| | | | | |
storage type type type direct |
class specifier specifier specifier declarator |
specifier | | | | |
| | | declaration | |
| | | specifiers | |
| | | | | |
| | +-----+----+ | |
| | | | |
| | declaration init |
| | specifiers declarator |
| | | | |
| +---------+---------+ | |
| | | |
| declaration | |
| specifiers | |
| | | |
+-----------+-------------+ init |
| declarator |
declaration-specifiers list |
| | |
+----------------------+----------------+--------+
|
declaration
The order in which static, unsigned, long, and int appear doesn't matter (although people will probably hit you if you write int long static unsigned x). Your declaration must include at least one type-specifier, and you can't write things like float char double x or double double double double y, but those rules are enforced at a different level.
In C, variables are declared the way you use them, e.g.
int * t[12];
means than *t[somevalue] is an int.
Back to your example :
const char *arr = "hello";
means you cannot change the chars inside the string
arr[0] = 'x' is forbidden
arr = "xyz" is allowed
char * const arr = "hello";
means you cannot change the value of the pointer arr
arr[0] = 'x' is allowed
arr = "xyz" is forbidden

managing a collection of structs in c

I am learning c, and have come across an issue storing and managing structs; let me explain.
I am quite familiar with Java, and I am starting to understand how to properly use pointers and references in c. My goal is to make and store hundreds of stuct:
struct creature{
int id;
char name[12];
}
In java, I am able to create an Array like:
creature c [];
and then store and manipulate objects inside that array. I want the same effect in c using a struct "creature".
My first attempt was:
creature *creatures = malloc(sizeof(creature));
I am not entirely sure what that even does. My goal was to create a block of memory that strictly held struct pointers, like the Java array.
from here, I want to create new creature structs, and store their pointers in the creatures variable, that has memory allocated from using malloc.
I hope this was enough information to explain my problem.
Thanks!
Right, so what you want is an array of pointers. Note that in Java, whenever you have something like:
String s = ...;
This translates to a pointer in c:
String *s = ...;
Let's take the easy case first of a fixed-size array of pointers. This is simply:
creature *creatures[10];
for (var i=0; i < 10; i++) {
creatures[i] = malloc(sizeof(creature));
}
Now you have an array of pointers to creatures, each malloced separately. But, if you don't know how big your array of creatures should be, then you have to malloc the array of creatures. Note that if you have, say, a malloced int array, you'd do the following:
int *ints = malloc(sizeof(int) * 10);
ints[0]; ints[1]; //etc...
That is, an array is represented as a pointer to the first element. What you want now is an array of pointers, which ends up being a pointer to a pointer:
var numCritters = 10;
creature **creatures = malloc(sizeof(creature *) * numCritters);
for (var i=0; i < numCritters; numCritters++) {
creatures[i] = malloc(sizeof(creature));
}
The first malloc creates a pointer to an array of creature * pointers. Note we use sizeof(creature *) here, not sizeof(creature), because the array is of pointers, not of creatures.
Each of the next mallocs then creates a pointer to a creature, same as in the case of a fixed-size array.
Be sure to have a free for each malloc - that is, one for each creature * and one for the creature **.
Note that this is different from what Pankrates suggested. Which solution you want to use depends on what you want to do. His creates a big block of creatures:
creature *creatures = +--------------------+
| |
| |
| Creature 0 |
| |
| |
+--------------------+
| |
| |
| Creature 1 |
| |
| |
+--------------------+
| |
| |
| Creature 2 |
| |
| |
+--------------------+
| ... |
Whereas mine creates an array of pointers, each one pointing to a creature:
+--------------------+
| |
creature *creatures = +------+ | |
| ptr0 | ----> | Creature 0 |
+--------------------+ +------+ | |
| | +-- | ptr1 | | |
| | | +------+ +--------------------+
| Creature 1 | <-+ | ptr2 | --+
| | +------+ | +--------------------+
| | | .... | | | |
+--------------------+ | | |
+-> | Creature 2 |
| |
| |
+--------------------+
You are almost there. malloc takes the number of bytes that you want to allocate as an argument, therefore you need to multiply the size of the struct times the number of structs that you want to allocate:
int number_of_creatures = 10;
creature *creatures = malloc(sizeof(creature) * number_of_creatures);
You should also always check the returned pointer from malloc() to check if the allocation was successful
if (creatures == NULL)
printf("Allocating memory failed!\n");

casting void** to 2D array of int - C

i am trying to cast a void** pointer to an int** 2D array in C
here is the code that i am trying to work with (with all the extraneous bits removed):
\*assume that i have a data structure called graph with some
*element "void** graph" in it and some element "int order" */
void initialise_graph_data(graph_t *graph)
{
void **graph_data = NULL;
int (*matrix)[graph->order];
size_t size = (graph->order * graph->order) * sizeof(int);
graph_data = safe_malloc(size); /*safe malloc works fine*/
matrix = (int(*)[graph->order])graph_data;
graph->graph = graph_data;
}
when i compile that, it works fine, but gives me a warning that variable 'matrix' is set but not used. i dont really want to have to use the interim matrix variable because the function is just supposed to initialise the array, not put anything in it; but if i try to cast graph_data directly to an int** when i am assiging it to graph->graph like so:
graph->graph = (int(*)[graph->order])graph_data;
it gives me an assignment from incompatible pointer type warning.
am i just not casting it properly? does anyone have any suggestions as to how i can make it work without the interim "matrix" variable? or if not, what i can do with that variable so that it doesnt give me the warning that it is set but not used?
thanks
The compiler is right, an array of arrays (or a pointer to an array) is not the same as a pointer to a pointer. Just think about how they would be laid out in memory:
A matrix of size MxN in the form of an array of arrays:
+--------------+--------------+-----+----------------+--------------+-----+------------------+
| matrix[0][0] | matrix[0][1] | ... | matrix[0][N-1] | matrix[1][0] | ... | matrix[M-1][N-1] |
+--------------+--------------+-----+----------------+--------------+-----+------------------+
A and the same "matrix" in the form of pointer to pointer:
+-----------+-----------+-----------+-----+
| matrix[0] | matrix[1] | matrix[2] | ... |
+-----------+-----------+-----------+-----+
| | |
| | V
| | +--------------+--------------+-----+
| | | matrix[2][0] | matrix[2][1] | ... |
| | +--------------+--------------+-----+
| |
| V
| +--------------+--------------+-----+
| | matrix[1][0] | matrix[1][1] | ... |
| +--------------+--------------+-----+
|
V
+--------------+--------------+-----+
| matrix[0][0] | matrix[0][1] | ... |
+--------------+--------------+-----+
It doesn't matter if you allocate the correct size, the two variables simply are incompatible which is what your compiler is telling you.

Resources