Is it safe to call std::memset(pointer, ch, count)
with invalid pointer (e.g., nullptr
or junk) when count
equals 0?
Asked
Active
Viewed 97 times
3

Shawn
- 47,241
- 3
- 26
- 60

user2052436
- 4,321
- 1
- 25
- 46
-
It does fall under the as-if rule (https://en.cppreference.com/w/cpp/string/byte/memset). So it seems to be safe to do so. But I can't find explicit confirmation in the standard – Pepijn Kramer Nov 09 '22 at 16:28
-
[C](https://en.cppreference.com/w/c/string/byte/memset) says UB, [C++](https://en.cppreference.com/w/cpp/string/byte/memset) doesn't so I'm not sure – NathanOliver Nov 09 '22 at 16:29
-
I believe the ISO C++ standard refers to the ISO C standard regarding the functions from the C standard library. Therefore, it may be more appropriate to make this a C question than a C++ question, unless a specific C++ rule is relevant here. – Andreas Wenzel Nov 09 '22 at 16:29
-
No, and this has been covered multiple times at Cppcon (don't have the bandwidth right now, but I think https://www.youtube.com/watch?v=yG1OZ69H_-o or https://www.youtube.com/watch?v=g7entxbQOCc will cover it). You're not allowed to pass NULL as either the source or destination, and compilers are free to optimize accordingly. See also: https://stackoverflow.com/questions/5243012/is-it-guaranteed-to-be-safe-to-perform-memcpy0-0-0 – Stephen Newell Nov 09 '22 at 16:56
-
Clang does gives a warning about size 0, MSVC/gcc do not : https://godbolt.org/z/3TzKfGT16. – Pepijn Kramer Nov 09 '22 at 17:07
-
Based on the comments, the TL;DR is: **No**, it is _not_ safe to do this. – Craig Estey Nov 09 '22 at 17:22
-
https://stackoverflow.com/q/8597034/1918193 – Marc Glisse Nov 09 '22 at 18:52
1 Answers
6
No, that causes undefined behavior. For example:
void* p = get_address(); // may return null
size_t sz = get_size(); // zero if previous returned null
memset(p, 0, sz); // Compiler may assume that p is not null
if (p) { // this null-check can be omitted since we "know" p is not null
foo(p);
}
And indeed, if you look at the code generated by GCC:
main:
push rbx
call get_address()
mov rbx, rax
call get_size()
mov rdi, rbx
xor esi, esi
mov rdx, rax
call memset
mov rdi, rbx
call foo(void*) ; <-- unconditional call
xor eax, eax
pop rbx
ret
You can see that the "if" branch is omitted.

Aykhan Hagverdili
- 28,141
- 6
- 41
- 93