offa / scope-guard

Implementation of Scoped Guards and Unique Resource as proposed in P0052.
MIT License
46 stars 6 forks source link

unique_resource unexpectedly allows access to invalid memory #206

Closed JPEWdev closed 3 months ago

JPEWdev commented 4 months ago

When using unique_resource I discovered that it happily let me access memory that was invalid after calling reset(). For example:

auto p = sr::unique_resource<char*, decltype(&free)>(malloc(1), free);

*p = 1;

p.reset();

// This dereferences invalid memory
*p = 2;

// This also doesn't work
if (p.get()) {
  *p = 2;
}

// This is fine as it won't call the deleter again
p.reset();

I originally came across this because I (incorrectly) assumed that reset() was equivalent to reset(nullptr) as is the case for std::shared_ptr et. al.

I realize that unique_resource isn't necessarily a pointer so it might not be possible to return a known value (like nullptr) if the resource is no longer valid, but there doesn't actually appear to be any way to know if the resource is valid or not right now.

In the mean time, I was able to fix this by calling reset(nullptr) and making sure that my deleter correctly handles nullptr

offa commented 4 months ago

This is correct behaviour (see §7.6.5). Calling reset() on a (not yet released) resource is going to call the deleter on it.

In your example this will free the memory, thus you can't use it afterwards.

A resource can be of any type, thus there's no universally valid value. As you have mentioned already – you can pass some kind of empty or null-like value to reset(…) if type and domain allow this.

offa commented 4 months ago

Btw. depending on your compiler and settings you might get an use-after-free warning on *p = 2;.

offa commented 4 months ago

@JPEWdev Does this solve your issue?

offa commented 3 months ago

I'm closing here as the behaviour is correct. Please feel free to reopen if there's something left :-).