After Segfault: Is There a Way, to Check If Pointer Is Still Valid

After Segfault: Is there a way, to check if pointer is still valid?

Of course if the stack or other memory that you rely upon has been corrupted then there could be problems, but that is true for any code.

Assuming that that there is no problem with the stack or other memory that you rely upon, and assuming that you do not call any functions like malloc() that are not async-signal safe, and assuming that you do not attempt to return from your signal handler, then there should be no problem reading or writing your buffer from within your signal handler.

If you are trying to test whether a particular address is valid, you could use a system call such as mincore() and check for an error result.

Checking if pointer is NULL gives segmentation fault

you do

while(traverse->next!=NULL && alternate->next!=NULL)
traverse->next = alternate->next;
traverse = traverse->next;
alternate = traverse->next;
if((alternate->next)==NULL) //presence of this if statement causes segmentation fault

so in fact

while(traverse->next!=NULL && alternate->next!=NULL)
traverse = alternate->next;
alternate = traverse->next;
if((alternate->next)==NULL) //presence of this if statement causes segmentation fault

so in fact

while(traverse->next!=NULL && alternate->next!=NULL)
alternate = alternate->next->next;
if((alternate->next)==NULL) //presence of this if statement causes segmentation fault

so in fact

while(traverse->next!=NULL && alternate->next!=NULL)
if((alternate->next->next->next)==NULL) //presence of this if statement causes segmentation fault

when alternate->next->next is NULL (not checked by the while) alternate->next->next->next causes your segmentation fault


A solution is :

void deleteAlt(struct Node * head)
{
if (head != NULL) {
while (head->next != NULL) {
Node * d = head->next;

head->next = head->next->next;
free(d);
head = head->next;
}
}
}

A complete program to prove :

#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
int v;
struct Node * next;
} Node;

Node * make(int v, Node * n)
{
Node * r = malloc(sizeof(Node));

r->v = v;
r->next = n;

return r;
}

void pr(Node * l)
{
while (l != NULL) {
printf("%d ", l->v);
l = l->next;
}
putchar('\n');
}

void deleteAlt(struct Node * head)
{
if (head != NULL) {
while (head->next != NULL) {
Node * d = head->next;

head->next = head->next->next;
free(d);
head = head->next;
}
}
}

int main()
{
Node * l = make(1, make(2, make(3, make(4, make(5, NULL)))));

pr(l);
deleteAlt(l);
pr(l);

/* free rest of list */
while (l != NULL) {
Node * n = l->next;

free(l);
l = n;
}
}

Compilation and execution:

pi@raspberrypi:/tmp $ gcc -pedantc -Wextra l.c
pi@raspberrypi:/tmp $ ./a.out
1 2 3 4 5
1 3 5
pi@raspberrypi:/tmp $

Execution under valgrind to check memory accesses/leaks

pi@raspberrypi:/tmp $ valgrind ./a.out
==2479== Memcheck, a memory error detector
==2479== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2479== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==2479== Command: ./a.out
==2479==
1 2 3 4 5
1 3 5
==2479==
==2479== HEAP SUMMARY:
==2479== in use at exit: 0 bytes in 0 blocks
==2479== total heap usage: 6 allocs, 6 frees, 1,064 bytes allocated
==2479==
==2479== All heap blocks were freed -- no leaks are possible
==2479==
==2479== For counts of detected and suppressed errors, rerun with: -v
==2479== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)

(edit) In case the length of the list can be even the definition must be changed to :

void deleteAlt(struct Node * head)
{
while ((head != NULL) && (head->next != NULL)) {
Node * d = head->next;

head->next = head->next->next;
free(d);
head = head->next;
}
}

modifying main to check :

int main()
{
{
Node * l = make(1, make(2, make(3, make(4, make(5, NULL)))));

pr(l);
deleteAlt(l);
pr(l);

/* free rest of list */
while (l != NULL) {
Node * n = l->next;

free(l);
l = n;
}
}
{
Node * l = make(1, make(2, make(3, make(4, NULL))));

pr(l);
deleteAlt(l);
pr(l);

/* free rest of list */
while (l != NULL) {
Node * n = l->next;

free(l);
l = n;
}
}
}

Compilation and execution :

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra l.c
pi@raspberrypi:/tmp $ ./a.out
1 2 3 4 5
1 3 5
1 2 3 4
1 3

and under valgrind :

pi@raspberrypi:/tmp $ valgrind ./a.out
==3450== Memcheck, a memory error detector
==3450== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3450== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==3450== Command: ./a.out
==3450==
1 2 3 4 5
1 3 5
1 2 3 4
1 3
==3450==
==3450== HEAP SUMMARY:
==3450== in use at exit: 0 bytes in 0 blocks
==3450== total heap usage: 10 allocs, 10 frees, 1,096 bytes allocated
==3450==
==3450== All heap blocks were freed -- no leaks are possible
==3450==
==3450== For counts of detected and suppressed errors, rerun with: -v
==3450== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)

C - Segmentation fault when checking if a pointer is NULL

In your add function, the variable n is an uninitialized pointer. So it is not the problem of checking it->head.

Segmentation Fault on Pointer null check

Found the Problem: Change the loop condition to while(!currStack.empty()) {}

C program pointer not holding valid address still not giving segmentation fault

It depends on the value of "cantcatch" - which is undefined (random value).
If the value is out of the memory scope of your program - then the program will segfault.

If it's within the scope of your program then the program will not crash but potentially cause corruption to memory.

These invalid read/writes can easily be caught by memory profiling tools such as "Valgrind".

How to judge whether the incoming buffer is valid in C++?

Don't. Just don't.

Even if you could find a way to check whether the pointer can safely be dereferenced, that doesn't mean it points where you think it does! It might point into your call stack, into your read-only code segment, into the static variables of some library that you're using, or any other place in memory that your program happens to have access to.

The responsibility of passing a valid pointer should be with the caller of the function. To make it harder for the caller to do something stupid, consider passing a std::vector & or std::vector const & instead.



Related Topics



Leave a reply



Submit