feat(ext): add exception to data in end callback#2
Conversation
| zend_object *exception = EG(exception); | ||
| if (exception != NULL) { | ||
| zval exception_zv; | ||
| ZVAL_OBJ_COPY(&exception_zv, exception); | ||
| add_assoc_zval(&event, "exception", &exception_zv); | ||
| } else { | ||
| add_assoc_null(&event, "exception"); | ||
| } |
There was a problem hiding this comment.
Bug: A reference to the original exception is decremented twice in the unwind-exit path (e.g., from die()), causing a premature free and potential use-after-free.
Severity: HIGH
Suggested Fix
The zval_ptr_dtor(&event) call in sentry_observer_end should be skipped or handled conditionally when an unwind-exit occurs. The reference to the original exception is already released within sentry_exception_isolation_end in this specific path, so the second decrement causes the object to be freed too early.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: sentry.c#L515-L522
Potential issue: In the specific case where an instrumented function triggers an
unwind-exit by calling `exit()` or `die()`, a reference counting issue leads to a
premature free of the original exception object. The code adds the exception to an
`event` array via `ZVAL_OBJ_COPY`, incrementing its reference count. The unwind-exit
path correctly releases its own reference via `OBJ_RELEASE`. However,
`sentry_observer_end` later calls `zval_ptr_dtor(&event)`, which decrements the count
again, freeing the object. The observer framework may still require this object during
stack unwinding, leading to a use-after-free.
Did we get this right? 👍 / 👎 to inform future reviews.
There was a problem hiding this comment.
Not sure this is correct. ZVAL_OBJ_COPY increases the ref-count and zval_ptr_dtor(&event) will release each element, meaning that it will just decrement the ref-count.
The extension will now add any exception that happened to the
$dataarray passed into the end callback. If no exception happened, it will benull.Having the exception available means that a span status can be properly derived from it