I don't know how to reset the value field inside the Hello struct. It's a pointer pointed to an outside passed input argument.
typedef struct Hello {
void *value;
} Hello;
Hello* create_hello() {
Hello* hello = malloc(sizeof(Hello));
hello->value = NULL;
return hello;
}
set_value(Hello *hello, void *value) {
hello->value = value;
}
void free_hello(Hello *hello) {
/** Should I set the value to NULL before freeing the hello? */
hello->value = NULL;
/** Free the hello */
free(hello);
/** Set hello to NULL inside the free_hello()? */
hello = NULL;
}
Here is the test_function:
test_function(void* value) {
Hello *hello = create_hello();
set_value(hello, value);
free_hello(hello);
/** Set hello to NULL inside the test_function()? */
hello = NULL;
}
Should I execute
hello->value = NULL;inside thefree_helloin order to reset thehello->valueto the default NULL status?Should I execute
hello = NULL;inside thefree_hello()ortest_function()after freeing the struct withfree()?
2 Answers 2
Should I call
hello->value = NULL;inside thefree_helloin order to reset thehello->valueto the defaultNULLstatus?
There's no need because you call free(hello) on the next line, so the pointer value becomes indeterminate, effectively meaning you shouldn't read it.
Should I call
hello = NULL;inside thefree_hello()ortest_function()after freeing the struct withfree()?
Setting hello to NULL inside of free_hello has no effect because it's a local variable to the function. Whether you do so with the variable from the calling function depends on what you intend to do with it later, but is typically a good idea so you don't have a freed pointer dangling around.
Comments
Some additional thoughts to @dbush good answer.
Should I execute
hello->value = NULL;inside thefree_helloin order to reset thehello->valueto the defaultNULLstatus?
Right after free(hello);, as hello is indeterminant, attempting hello->value is undefined behavior (UB).
Debugging: Yet performing hello->value = NULL; before the free(hello) can improve debugging as it may improve the chance of detecting later invalid use of the pointer that was in hello->value. This generally improves detection yet not a certainly. The assignment hello->value = NULL; before the free(hello) may get optimized out by an intelligent compiler. One might need additional code (e.g. a cast to a volatile data) to prevent such optimization. Code could perform hello->value = NULL; only in debug mode, yet that carries a disadvantage of injecting a small change between the debug compilation and release one yet has consequences.
Security: performing hello->value = NULL; before the free(hello) might improve security by not leaving tell-tale information in the free'd memory. Again, this assignment may get optimized out as discussed above. Note that security of data is a deep subject and zeroing is only a beginner step.
I see usefulness in always performing hello->value = NULL; and little downside. Since it is not obviously needed, a comment should accompany such code to outline why it is there.
C23 offers a clean way to assign data that might otherwise get optimized out. memset_explicit() is self documenting, lessening the the needed for a comment as suggested above. As a standard library function, a good compiler can be expected to emit efficient code - perhaps just a simple assignment.
The purpose of this function is to make sensitive information stored in the object inaccessible C23dr § 7.26.6.2 2
The intention is that the memory store is always performed (i.e. never elided), regardless of optimizations. This is in contrast to calls to thememsetfunction. Footnote 367
memset_explicit(&data, 0, sizeof data);
// or in OP's case: zero entire object that `hello` points to
memset_explicit(hello, 0, sizeof hello[0]);
Should I execute
hello = NULL;inside thefree_hello()ortest_function()after freeing the struct with free()?
Again, this can improve debugging, yet may get optimized out. Likewise, if used, comment such code to explain its apparent unnecessity.
As @wohlstad suggested, a re-write of the function signature is useful to alleviate the calling code's needed to zero the pointer.
hello = NULL;intest_functionhas no effect becausehellois a local. You could changetest_functionto get avoid**(pointer to pointer), so that you'll be able to set the pointer on the caller side to NULL.