Code should result in segmentation fault because due to shallow copy node at head of list1 gets deleted but list2 head still points there - c++14

The code should result in segmentation fault due to shallow copy but instead it allows printing the address of the the head node for list2 when printAll() is called for list2 in main().What should be done to get the expected behaviour ?Also please explain why is it happening ? I am a beginner.Thanks in advance.
>>>> when tried with #pragma pack(1) it resuted in the first output
>>>> Without #pragma pack(1) it resulted in the second output
Here is the code i wrote.
The code is for creating an object (list1) of SLL class(singly linked list) and copying it to another object(list2) of SLL class.
#include <iostream>
using namespace std;
//#pragma pack(1)
class Node{
public:
char letter;
Node *next;
};
class SLL{
private:
Node *head, *tail;
public:
SLL(){
head = NULL;
tail = NULL;
}
void printAll();// for printing the list
void insertNewNode(char item);// for insertion at head
//function for deletion at head
void deleteAtHead(){
Node *tmp;
tmp = this->head;
this->head = this->head->next;
free(tmp);
}
};
//it is for printing a singly linked list
void SLL::printAll(){
Node *p;
p = head;
cout<<"VALUE "<<" "<<" ADDRESS"<<endl;
while(p!=NULL){
cout <<p->letter << "--------------- "<<p<<endl;
p = p->next;
}
}
void SLL::insertNewNode(char item){
Node* temp;
temp = (Node *)malloc(sizeof(Node));
temp->letter = item;
temp->next = head;
head = temp;
}
int main(){
SLL list1;
list1.insertNewNode('D');
list1.insertNewNode('C');
list1.insertNewNode('B');
list1.insertNewNode('A');
cout<<"PRINTING LIST1"<<endl;
list1.printAll();
cout<<""<<endl;
cout<<"SHALLOW COPY INVOKED"<<endl;
SLL list2 = list1;
cout<<""<<endl;
cout<<"PRINTING LIST2"<<endl;
list2.printAll();
list1.deleteAtHead();
cout<<""<<endl;
cout<<" LIST1 AFTER ITS HEAD DELETION"<<endl;
list1.printAll();
cout<<""<<endl;
cout<<" LIST2"<<endl;
list2.printAll(); // as soon as this is executed it should result in runtime error
return 0;
}
>>>>>>> Output1:
PRINTING LIST1
VALUE ADDRESS
A ------------- 0x5578d6f872e0
B ------------- 0x5578d6f872c0
C ------------- 0x5578d6f872a0
D ------------- 0x5578d6f87280
SHALLOW COPY INVOKED
PRINTING LIST2
VALUE ADDRESS
A ------------- 0x5578d6f872e0
B ------------- 0x5578d6f872c0
C ------------- 0x5578d6f872a0
D ------------- 0x5578d6f87280
LIST1 AFTER ITS HEAD DELETION
VALUE ADDRESS
B ------------- 0x5578d6f872c0
C ------------- 0x5578d6f872a0
D ------------- 0x5578d6f87280
LIST2
VALUE ADDRESS
--------------- 0x5578d6f872e0
>>>>>> Output2:
PRINTING LIST1
VALUE ADDRESS
A ------------- 0x55baac1032e0
B ------------- 0x55baac1032c0
C ------------- 0x55baac1032a0
D ------------- 0x55baac103280
SHALLOW COPY INVOKED
PRINTING LIST2
VALUE ADDRESS
A ------------- 0x55baac1032e0
B ------------- 0x55baac1032c0
C ------------- 0x55baac1032a0
D ------------- 0x55baac103280
LIST1 AFTER ITS HEAD DELETION
VALUE ADDRESS
B ------------- 0x55baac1032c0
C ------------- 0x55baac1032a0
D ------------- 0x55baac103280
LIST2
VALUE ADDRESS
--------------- 0x55baac1032e0
B--------------- 0x55baac1032c0
C--------------- 0x55baac1032a0
D--------------- 0x55baac103280

Pointers point into some region of memory. Any region of memory.
Programs get their memory from the operating system, which usually gives it in large chunks ('Pages') that the program runtime then subdivides. The routines that are called by malloc, new and free, delete do this, but also the mechanisms to call and return from subroutines.
Trying to use a place in memory that has not been allocated to the program results in a Segmentation Fault. But using memory that was allocated to the program does not result in faults.
Programs do not usually give back pages that were allocated to them. Instead, the memory is just re-used, e.g. to store different variables. This is an optimisation, as it costs a lot of effort for the OS to allocate memory. It also reduces the amount of cache a program uses.
That is why the so-called 'dangling pointer' is so dangerous. When you use it, it returns data. Only close inspection will show that the data makes no sense. It may even return correct data for a long time, until the memory region is recycled and overwritten by something else. Then your program suddenly shows 'undefined behaviour'...

Related

In the following example, from where does the pointer p gets the information?

vector& vector::operator = (const vector& a)
//make this vector a copy of a
{
double* p = new double [ a.sz ]; // allocate new space
copy(a.elem, a.elem+a.sz, elem); // copy elements
delete[] elem; // deallocate old space
elem = p; // now we can reset elem
sz = a.sz;
return *this; // return a self-reference
}
I thought that the third argument of std::copy() should be the pointer p, but the book (Programming principles and practice using C++ - 2nd edition) says:
"When implementing the assignment, you could consider simplifying the code by freeing the memory for the old elements before creating the copy, but it is usually a very good idea not to throw away information before you know that you can replace it. Also, if you did that, strange things would happen if you assigned a vector to itself" - Page 635 and 636.
So, the pointer elem must be third argument of std::copy() to not let the pointer be invalid for a moment. I think...
But from where does p gets the information to be put in the array it points to, to be able to do: elem = p ?
I already know copy and swap strategy exist, you don't have to explain that.
I want to comprehend what is above.
No, that is a typo.
std::copy(a.elem, a.elem+a.sz, p);
is what the code should read.

Unexpected value returned by use_count() of shared_ptr while retrieving from vector

The program below is outputting unexpected use_count() value when shared pointer is printed using iterator de-reference of std::vector:
#include<iostream>
#include<memory>
#include<vector>
class A;
typedef std::shared_ptr<A> sharedPtr;
typedef std::vector<sharedPtr> sharedPtrVect;
typedef sharedPtrVect::const_iterator vectItr;
class A
{
public:
A(int inp): m_Val(inp) { /*std::cout << "*** A ctor called: " << m_Val << " ***" <<std::endl;*/ }
~A() { /*std::cout << "### A dtor called: " << m_Val << " ###" <<std::endl; */}
int getVal() const { return m_Val; }
private:
int m_Val;
};
int main()
{
sharedPtrVect myVect1, myVect2;
vectItr myVectItr;
std::shared_ptr<A> tmpPtr;
for(int i = 1 ; i <= 5 ; i++ ) {
std::cout << "Pushed back: " << i << std::endl;
tmpPtr = std::make_shared<A>(i);
myVect1.push_back(tmpPtr);
}
myVectItr = myVect1.begin();
for( ; myVectItr != myVect1.end() ; ++myVectItr) {
std::cout << "-----------------------------" << std::endl;
std::cout << "Element number: " << (*myVectItr).get()->getVal() << std::endl;
std::cout << "Element use count: " << (*myVectItr).use_count() << std::endl;
std::cout << "-----------------------------" << std::endl;
}
return 0;
}
The output of the above code is:
Pushed back: 1
Pushed back: 2
Pushed back: 3
Pushed back: 4
Pushed back: 5
-----------------------------
Element number: 1
Element use count: 1
-----------------------------
-----------------------------
Element number: 2
Element use count: 1
-----------------------------
-----------------------------
Element number: 3
Element use count: 1
-----------------------------
-----------------------------
Element number: 4
Element use count: 1
-----------------------------
-----------------------------
Element number: 5
Element use count: 2 //I am not sure why or how this is 2?
-----------------------------
I don't understand how the use_count() for the last vector element is 2. Shouldn't it be 1 like others? I am not creating any copies of the shared pointer stored in the last element of the vector.
What am I missing here?
EDIT: I have good experience in C++98, but less experience in C++11.
Shouldn't it be 1 like others? I am not creating any copies of the shared pointer stored in the last element of the vector. What am I missing here?
But you are creating a copy. You push_back() from tmpPtr. push_back() puts a copy of its argument into the vector, unless you tell it to move instead. (More on that later!)
Therefore, what happens for all but the last element is this:
tmpPtr holds the only reference to the shared resource
You push_back() a copy, so the copy-constructor of shared_ptr increments the use count to 2
You then assign the next element to tmpPtr, releasing the reference to, and thereby decrementing the use count of, the previous element's resource.
But, of course, there is no subsequent assignment on the last iteration of the loop. So, at the point of printing, tmpPtr is still in scope, and it retains a reference to the last resource that was allocated. Hence the 1-higher refcount on the last element. This seems perfectly expected to me. ;)
To see the results you expected, you need to either destroy tmpPtr after you copy it but before you print, or simply avoid the copy from it in the first place. The former could be done by moving its declaration into the for loop, as SirGuy pointed out in the comments.
However, clearly, the latter is superior. How do we do that? Well, C++11 lets us move instead. So, you could emplace_back( std::move(tmpPtr) ), in which the move will cast to an rvalue and thus invoke the move-constructor of the vector element. This will cause tmpPtr to release its reference upon being moved into the vector, effectively ensuring the use count is always 1. This leaves tmpPtr (like any moved-from object) in a valid-but-unspecified state, i.e. useful only to be reassigned-to.
(Note: push_back() will achieve the same thing, but I generally prefer using emplace_back() wherever possible, as it's more efficient in other situations, so it's a better default.)
Of course, you can then combine both of these: declare tmpPtr within the scope of the for loop, and move from it. However... you don't even need tmpPtr at all! It does not appear to serve any useful purpose. So, you could just not use it, and instead directly emplace_back() the result of make_shared(). Because the return value thereof will be an rvalue, it will implicitly be moved into the vector; no cast by std::move is needed.

how do I allocate memory for some of the structure elements

I want to allocate memory for some elements of a structure, which are pointers to other small structs.How do I allocate and de-allocate memory in best way?
Ex:
typedef struct _SOME_STRUCT {
PDATATYPE1 PDatatype1;
PDATATYPE2 PDatatype2;
PDATATYPE3 PDatatype3;
.......
PDATATYPE12 PDatatype12;
} SOME_STRUCT, *PSOME_STRUCT;
I want to allocate memory for PDatatype1,3,4,6,7,9,11.Can I allocate memory with single malloc? or what is the best way to allocate memory for only these elements and how to free the whole memory allocated?
There is a trick that allows a single malloc, but that also has to weighed against doing a more standard multiple malloc approach.
If [and only if], once the DatatypeN elements of SOME_STRUCT are allocated, they do not need to be reallocated in any way, nor does any other code do a free on any of them, you can do the following [the assumption that PDATATYPEn points to DATATYPEn]:
PSOME_STRUCT
alloc_some_struct(void)
{
size_t siz;
void *vptr;
PSOME_STRUCT sptr;
// NOTE: this optimizes down to a single assignment
siz = 0;
siz += sizeof(DATATYPE1);
siz += sizeof(DATATYPE2);
siz += sizeof(DATATYPE3);
...
siz += sizeof(DATATYPE12);
sptr = malloc(sizeof(SOME_STRUCT) + siz);
vptr = sptr;
vptr += sizeof(SOME_STRUCT);
sptr->Pdatatype1 = vptr;
// either initialize the struct pointed to by sptr->Pdatatype1 here or
// caller should do it -- likewise for the others ...
vptr += sizeof(DATATYPE1);
sptr->Pdatatype2 = vptr;
vptr += sizeof(DATATYPE2);
sptr->Pdatatype3 = vptr;
vptr += sizeof(DATATYPE3);
...
sptr->Pdatatype12 = vptr;
vptr += sizeof(DATATYPE12);
return sptr;
}
Then, the when you're done, just do free(sptr).
The sizeof above should be sufficient to provide proper alignment for the sub-structs. If not, you'll have to replace them with a macro (e.g. SIZEOF) that provides the necessary alignment. (e.g.) for 8 byte alignment, something like:
#define SIZEOF(_siz) (((_siz) + 7) & ~0x07)
Note: While it is possible to do all this, and it is more common for things like variable length string structs like:
struct mystring {
int my_strlen;
char my_strbuf[0];
};
struct mystring {
int my_strlen;
char *my_strbuf;
};
It is debatable whether it's worth the [potential] fragility (i.e. somebody forgets and does the realloc/free on the individual elements). The cleaner way would be to embed the actual structs rather than the pointers to them if the single malloc is a high priority for you.
Otherwise, just do the the [more] standard way and do the 12 individual malloc calls and, later, the 12 free calls.
Still, it is a viable technique, particularly on small memory constrained systems.
Here is the [more] usual way involving per-element allocations:
PSOME_STRUCT
alloc_some_struct(void)
{
void *vptr;
PSOME_STRUCT sptr;
sptr = malloc(sizeof(SOME_STRUCT));
// either initialize the struct pointed to by sptr->Pdatatype1 here or
// caller should do it -- likewise for the others ...
sptr->Pdatatype1 = malloc(sizeof(DATATYPE1));
sptr->Pdatatype2 = malloc(sizeof(DATATYPE2));
sptr->Pdatatype3 = malloc(sizeof(DATATYPE3));
...
sptr->Pdatatype12 = malloc(sizeof(DATATYPE12));
return sptr;
}
void
free_some_struct(PSOME_STRUCT sptr)
{
free(sptr->Pdatatype1);
free(sptr->Pdatatype2);
free(sptr->Pdatatype3);
...
free(sptr->Pdatatype12);
free(sptr);
}
If your structure contains the others structures as elements instead of pointers, you can allocate memory for the combined structure in one shot:
typedef struct _SOME_STRUCT {
DATATYPE1 Datatype1;
DATATYPE2 Datatype2;
DATATYPE3 Datatype3;
.......
DATATYPE12 Datatype12;
} SOME_STRUCT, *PSOME_STRUCT;
PSOME_STRUCT p = (PSOME_STRUCT)malloc(sizeof(SOME_STRUCT));
// Or without malloc:
PSOME_STRUCT p = new SOME_STRUCT();

not understand the mechanism of free_netdev

I study network-device-driver recently. But somehow not understand free_netdev this function.
I have read the following link:
Possible de-reference of private data using net_device
The answer says that when free the network device, the private data will also be free.
After checking this function, I found that it will call the following function:
void netdev_freemem(struct net_device *dev)
{
char *addr = (char *)dev - dev->padded;
kvfree(addr);
}
But I cannot understand why call this function will free all the net_device memory, and also the private data?
Or my understanding is wrong...
Just wondering if someone can guide me to understand the mechanism of free_netdev.
Thanks in advance.
Check out alloc_netdev() function definition in net/core/dev.c
alloc_size = sizeof(struct net_device);
if (sizeof_priv) {
/* ensure 32-byte alignment of private area */
alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);
alloc_size += sizeof_priv;
}
/* ensure 32-byte alignment of whole construct */
alloc_size += NETDEV_ALIGN - 1;
p = kzalloc(alloc_size, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
if (!p)
p = vzalloc(alloc_size);
if (!p)
return NULL;
dev = PTR_ALIGN(p, NETDEV_ALIGN);
dev->padded = (char *)dev - (char *)p;
It does a Kzalloc of sizeof(struct net_device) + sizeof_priv + padding_bytes.
So net_device private is memory immediately following struct net_device and hence kfree() of netdev frees even net_device_private memory.
Thanks #Nithin
After checking code of alloc_netdev_mqs, I think it will be clear to draw a diagram to answer my own question. So from the diagram, we can see (char *)dev - dev->padded is just want to find the p's location, And free this p variable will just free all the allocated memory.
------------------- [p = kzalloc(alloc_size, GFP_KERNEL)]
------------------- [dev = PTR_ALIGN(p, NETDEV_ALIGN)]
since p may not aligned to NETDEV_ALIGN * n
and the final added NETDEV_ALIGN - 1 is for the space
of dev - p
------------------- [size of net_device struct]
------------------- [do the size alignment of net_device struct]
------------------- [private data]
------------------- [add final NETDEV_ALIGN - 1 for padding]

Linux Kernel - Red/Black Trees

I'm trying to implement a red/black tree in Linux per task_struct using code from linux/rbtree.h. I can get a red/black tree inserting properly in a standalone space in the kernel such as a module but when I try to get the same code to function with the rb_root declared in either task_struct or task_struct->files_struct, I get a SEGFAULT everytime I try an insert.
Here's some code:
In task_struct I create a rb_root struct for my tree (not a pointer).
In init_task.h, macro INIT_TASK(tsk), I set this equal to RB_ROOT.
To do an insert, I use this code:
rb_insert(&(current->fd_tree), &rbnode);
This is where the issue occurs.
My insert command is the standard insert that is documented in all RBTree documentation for the kernel:
int my_insert(struct rb_root *root, struct mytype *data)
{
struct rb_node **new = &(root->rb_node), *parent = NULL;
/* Figure out where to put new node */
while (*new) {
struct mytype *this = container_of(*new, struct mytype, node);
int result = strcmp(data->keystring, this->keystring);
parent = *new;
if (result < 0)
new = &((*new)->rb_left);
else if (result > 0)
new = &((*new)->rb_right);
else
return FALSE;
}
/* Add new node and rebalance tree. */
rb_link_node(&data->node, parent, new);
rb_insert_color(&data->node, root);
return TRUE;
}
Is there something I'm missing?
Some reason this would work fine if I made a tree root outside of task_struct? If I make rb_root inside of a module this insert works fine. But once I put the actual tree root in the task_struct or even in the task_struct->files_struct, I get a SEGFAULT. Can a root node not be added in these structs?
Any tips are greatly appreciated. I've tried nearly everything I can think of.
Edit:
I get a SEGFAULT on the following line when trying to print and any line that accesses the tree. With this line you should get the understanding of how I'm handling the pointers. rb_entry and rb_first are methods already available in the kernel. current is a pointer to a task struct (current working process) and tree is my root node (not a pointer) which is a member of the task struct (I added). rb_first needs to pass a pointer *rb_root. I'm doing this wrong.
printk(KERN_CRIT "node=%d\n", rb_entry(rb_first(&(current->tree)), struct rb_tree_struct, node)->fd_key);
Could it be the pointer values of root and/or data aren't what you expect? It might be useful to add
printk("%s: root=%p data=%p\n", __func__, root, data);
before the while() loop.

Resources