Skip to content

Commit edb04b0

Browse files
authored
Merge pull request #1038 from krlmlr/b-clear-before-finalize
Clear external pointer before calling finalizer
2 parents ee2e102 + 0142938 commit edb04b0

File tree

1 file changed

+15
-8
lines changed

1 file changed

+15
-8
lines changed

inst/include/Rcpp/XPtr.h

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,19 @@ void standard_delete_finalizer(T* obj) {
3333

3434
template <typename T, void Finalizer(T*) >
3535
void finalizer_wrapper(SEXP p) {
36-
if (TYPEOF(p) == EXTPTRSXP) {
37-
T* ptr = (T*) R_ExternalPtrAddr(p);
38-
RCPP_DEBUG_3("finalizer_wrapper<%s>(SEXP p = <%p>). ptr = %p", DEMANGLE(T), p, ptr)
39-
Finalizer(ptr);
40-
}
36+
if (TYPEOF(p) != EXTPTRSXP)
37+
return;
38+
39+
T* ptr = (T*) R_ExternalPtrAddr(p);
40+
RCPP_DEBUG_3("finalizer_wrapper<%s>(SEXP p = <%p>). ptr = %p", DEMANGLE(T), p, ptr)
41+
42+
if (ptr == NULL)
43+
return;
44+
45+
// Clear before finalizing to avoid behavior like access of freed memory
46+
R_ClearExternalPtr(p);
47+
48+
Finalizer(ptr);
4149
}
4250

4351
template <
@@ -174,10 +182,9 @@ class XPtr :
174182
// Call the finalizer -- note that this implies that finalizers
175183
// need to be ready for a NULL external pointer value (our
176184
// default C++ finalizer is since delete NULL is a no-op).
185+
// This clears the external pointer just before calling the finalizer,
186+
// to avoid interesting behavior with co-dependent finalizers.
177187
finalizer_wrapper<T,Finalizer>(Storage::get__());
178-
179-
// Clear the external pointer
180-
R_ClearExternalPtr(Storage::get__());
181188
}
182189
}
183190

0 commit comments

Comments
 (0)