Say, you have a function which takes one or multiple pointers as parameters. Do you have to always check if they aren't NULL before doing operations on them?
I find this a bit tedious to do but I don't know whether it's a best practice or not.
01: #include <iostream>
02:
03: class greeter
04: {
05: public:
06: void hello()
07: {
08: std::cout << "Hello world";
09: }
10: };
11:
12: int main()
13: {
14: ((greeter*)nullptr)->hello();
15: }runs with no warnings on -Weveryting -Wall on gcc, no warnings on MSVC /W4 either.
https://godbolt.org/z/779Y4Ejzz
I'm sitting with the standard open but I must admit this is taking me forever to find. Do any of you know where to look?
EDIT: So far in my own research, I've got this from 21 years ago:
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232
At one point we agreed that dereferencing a null pointer was not undefined; only using the resulting value had undefined behavior.
Videos
Just use a unique pointer in main so that no one else can issue a null pointer
std::unique_ptr<void> null_p = std::make_unique<void>(NULL);
Now you'll never accidentally dereference a NULL pointer since nothing else can be NULL, null_p has exclusive access to it!
I saw this code in A Tour of C++, but with a bit modify for illustration:
#include <iostream>
int main() {
char s = 'a';
char *p = &s;
while (*p) {
std::cout << *p;
p++;
}
p = nullptr;
//std::cout << (*p == true);
*p == true;
}
I do not know how does while (*p) { end while I do not know what happens when p is nullptr. And std::cout << (*p == true) will induce segment fault but *p == true does not.
Quick question: Dereferencing pointer-to-array is basically a no-op, so is it legit even if the pointer is null?
int main(void)
{ int *ptr = 0 , printf(const char *, ...);
printf("%p\n", (void *)*(int (*)[1])ptr);
printf("wasn't actually dereferenced\n");
}
We first cast ptr to int (*)[1] and then dereference it (the void * cast is only meant for "%p").
The pedant in me says this is still undefined behavior, as the standard mentions:
If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.102)
102) ... Among the invalid values for dereferencing a pointer by the unary * operator are a null pointer, ...
Reference: https://port70.net/~nsz/c/c11/n1570.html#6.5.3.2p4
I'm looking for a second opinion, as I may have overlooked some part of the standard that implies my code is fine.
Motivation: Last month I posted a question to confirm if a well-known style of calling malloc works with VLA.
https://www.reddit.com/r/C_Programming/comments/1ck4azy/is_the_recommended_malloc_style_suitable_for_vla/
If the standard blesses dereference of invalid array pointer (due to no-op), then my earlier concern is also resolved.
Hello, I learn how to code with Ada. I write the following code:
Test_Node_Ptr := Pull (Test_List);
Node_Deallocation (Test_Node_Ptr);
Put_Line ("Editted List:");
Print_List (Test_List);
Put_Line ("Pulled_Value:");
-- Put (Test_Node_Ptr.Value);I think there is a null pointer dereferencing in the commented line. This is a link to the code line in repo.
It is strange that I found this error occasionally with valgrind, and before that commented code worked fine and printed the "right" value. So, why the memory wasn't cleaned and is it possible to avoid such situations in Ada? And is it possible to clean the memory for sure?
Your problem is that your Node_Deallocation takes the node to be deallocated in in mode. The consequence is that, as you found, you have to copy the node to a local variable and deallocate that; Unchecked_Deallocation requires a variable as its parameter because it sets the parameter to null.
Node_Deallocation’s parameter should have mode in out (and don’t make a local copy!)
Is it possible to avoid null pointer dereferencing in Ada?
Yes.
What you'll want to do is add a subtype [or possibly a new type, though that's likely more work] which excludes null.
type Node_Ptr is access Node;
subtype Safe_Node_Ptr is not null Node_Ptr;
Then you'll want to alter some of the data-structures and return-types:
-- Assuming you want to disallow the empty-list:
type List is record
Head: Safe_Node_Ptr;
Tail: Node_Ptr;
end record;
and:
function Pull (List_To_Change: out List) return Safe_Node_Ptr;
And is it possible to clean the memory for sure?
There's Unchecked_Deallocation and also storage-pools/-subpools.
Guys, I'm programming cortex-m4 (stm32). I tried to read flash-memory(it is possible). Flash starts from 0. I tried to dereference NULL ptr and my mcu halted: printf("I'm dereferencing NULL pointer: %lx\r\n", *(uint32_t *)0);
Then I tried to dereference value 0x04 the same way, and it worked! I see the exact word from my binary firmware file. It means this memory region is accessible. I tried to figure out this weird thing and looked at assembly with this command: arm-none-eabi-objdump -d tanenbaum.out | less .
Look at this!: Instead of loading value to register, accessing memory region and passing it to printf and actually calling printf, like it did with number 0x04, compiler decides to insert unknown to me and cortex-m4 ISA instuction udf #255. (maybe there is such an instruction, but i didn't find it in programming manual).
8002108: 2300 movs r3, #0
800210a: 681b ldr r3, [r3, #0]
800210c: deff udf #255 ; unknown instruction
800210e: bf00 nop ; instead of branching to printf
What the hell? How do I avoid such an behavior of the compiler. How did the developers of gcc come up with this brilliant solution? So many questions... WHYYYY?? Maybe it indeed makes sense?
Btw, i assigned to variable value of 0 from user input (in runtime, so compiler makes no guesses about value), AND IT WORKED!. I've read the exact first word from binary firmware!
EDIT: Conclusion if you find this thread in the future:
As of 2023-april-17, Go uses the old C approach to pointer safety: "Good programmers don't write bugs," although it is thankfully a defined (runtime) error rather than UB to read from a null pointer.
The compiler will not catch it if you write a function that reads from a pointer argument without checking for null.
Edit 2:
In response to this:
You seem unproportionately angry by this
I literally didn't believe my colleague when he complained about this earlier today, that's how incredible it is.
Null pointer dereferences have been a problem since the invention of null in 1965, a known problem since 1965+1, and remedies have been known and implemented in other languages for, at this point, literally decades.
-
C gets away with having this problem because it is too old.
-
Rust can do it because you have to specifically wrap code with unchecked dereferences in an "unsafe" region.
-
Zig has two kinds of pointers specifically to express these semantics.
-
C++ - terrible old C++ where everything is a catastrophe - recognizes this and lets you implement gsl::not_null<T>.
So I actually am kind of angry, yes. Having this problem in a modern compiled language is amateur hour. Having it in a language that isn't even used for Hard Realtime is professional malpractice by the inventors.
Original post:
A colleague has a null ptr dereference in Go.
I advised him to do as I would do - working in other languages, I tend to crank the warning level high and turn warnings into errors.
In e.g. C#, that means I cannot compile this code:
private static string bad_deref(object? Object)
{
return Object.ToString();
}because I get
x.cs(y,z): [CS8602] Dereference of a possibly null reference.
Which, to be clear, is very good.
But he tells me Go doesn't have a warning level to crank and, googling, it would appear he is right.
So how do you solve this problem in Go? Are we back to good old C advice "good programmers don't make mistakes" and null ptr dereferences just sometimes happen if you don't work with perfect people?
Just watched this video: https://www.youtube.com/watch?v=ROJ3PdDmirY which explains how Google manages to take down the internet (or at least: many sites) through a null pointer dereference.
Given that C++ has "nullptr" and that you can initialize stuff with it, and that you can (probably) statically check that variables / class members are initialized and balk if not, why isn't derefencing nullptr an exception? That would be the missing bit towards another bit of security in C++. So, why?
i tried out some code:
fn main() {
// Create a const NULL pointer
let nullp: *const u128 = ptr::null();
println!("size of null pointer:{}",mem::size_of_val(&nullp));
unsafe{
println!("null pointer is pointing to address {:p}", nullp);
println!("value the null pointer pointed is {}", *nullp);
}
}
the output:
size of null pointer:8
null pointer is pointing to address 0x0
Segmentation fault (core dumped)
i wonder what happened when i try to deref a null pointer pointing to virtual memory address 0x0, at the low level?
and whats the actual memory layout of a null pointer?