-
Notifications
You must be signed in to change notification settings - Fork 80
Description
addAfterVmCallAction and doAfterVmCallActions are used by the context to execute functions after vm calls, such as onRequestHeaders:
proxy-wasm-cpp-host/src/context.cc
Lines 312 to 324 in 72ce32f
| FilterHeadersStatus ContextBase::onRequestHeaders(uint32_t headers, bool end_of_stream) { | |
| CHECK_FAIL_HTTP(FilterHeadersStatus::Continue, FilterHeadersStatus::StopAllIterationAndWatermark); | |
| if (!wasm_->on_request_headers_abi_01_ && !wasm_->on_request_headers_abi_02_) { | |
| return FilterHeadersStatus::Continue; | |
| } | |
| DeferAfterCallActions actions(this); | |
| const auto result = wasm_->on_request_headers_abi_01_ | |
| ? wasm_->on_request_headers_abi_01_(this, id_, headers) | |
| : wasm_->on_request_headers_abi_02_(this, id_, headers, | |
| static_cast<uint32_t>(end_of_stream)); | |
| CHECK_FAIL_HTTP(FilterHeadersStatus::Continue, FilterHeadersStatus::StopAllIterationAndWatermark); | |
| return convertVmCallResultToFilterHeadersStatus(result); | |
| } |
If sendLocalReply has been added to after_vm_call_actions_ via addAfterVmCallAction:
https://github.com/envoyproxy/envoy/blob/main/source/extensions/common/wasm/context.cc#L1635-L1645
Here f() will execute sendLocalReply:
proxy-wasm-cpp-host/include/proxy-wasm/wasm.h
Line 154 in 72ce32f
| f(); |
It will call encodeHeaders() which triggers the vm to call onResponseHeaders as follows:
proxy-wasm-cpp-host/src/context.cc
Lines 374 to 384 in 72ce32f
| FilterDataStatus ContextBase::onResponseBody(uint32_t body_length, bool end_of_stream) { | |
| CHECK_FAIL_HTTP(FilterDataStatus::Continue, FilterDataStatus::StopIterationNoBuffer); | |
| if (!wasm_->on_response_body_) { | |
| return FilterDataStatus::Continue; | |
| } | |
| DeferAfterCallActions actions(this); | |
| const auto result = | |
| wasm_->on_response_body_(this, id_, body_length, static_cast<uint32_t>(end_of_stream)); | |
| CHECK_FAIL_HTTP(FilterDataStatus::Continue, FilterDataStatus::StopIterationNoBuffer); | |
| return convertVmCallResultToFilterDataStatus(result); | |
| } |
Then call doAfterVmCallActions again, that is, the function is re-entered, and the functions in after_vm_call_actions_ left in the onRequestHeaders stage will be executed in the onResonseHeaders stage, which may cause unexpected problems.
The following code compiled to wasm crashes Envoy:
func (ctx *httpHeaders) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
proxywasm.DispatchHttpCall("xxxxx", headers, nil, nil, 500, func(numHeaders, bodySize, numTrailers int) {
proxywasm.SendHttpResponse(200, nil, nil, -1)
proxywasm.ResumeHttpRequest()
})
return types.ActionPause
}ResumeHttpRequest will call continueStream and add the decoder_callbacks_->continueDecoding() function to after_vm_call_actions_, which will be executed during the onResonseHeaders stage triggered by sendLocalReply.
This resolved issue was also caused by this mechanism.