Ignore re-entrant form calls during passive FFI callbacks Passive FFI callbacks (e.g. FFI_OutputSelectedRect, FFI_Invalidate) are notifications invoked during internal operations such as painting. Embedders must not re-entrantly execute form actions or load/close pages during these callbacks. Track passive callbacks using CPDFSDK_FormFillEnvironment's in_passive_ffi_callback_ flag, and early-return from entry points such as FORM_OnAfterLoadPage, FORM_OnBeforeClosePage, and FORM_Do*Action when invoked re-entrantly. Active retrieval callbacks such as FFI_GetPage remain unflagged, as page loading is expected in those paths. TAG=agy CONV=9e87637a-cb01-4106-9c04-ad4da437fc61 Bug: 556535630 Change-Id: Id892141ce082cc8895b4ed5dc66af3edaf5ef740 Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/156913 Reviewed-by: Lei Zhang <thestig@chromium.org> Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/fpdfsdk/cpdfsdk_formfillenvironment.cpp b/fpdfsdk/cpdfsdk_formfillenvironment.cpp index 6c9b796..1568fc9 100644 --- a/fpdfsdk/cpdfsdk_formfillenvironment.cpp +++ b/fpdfsdk/cpdfsdk_formfillenvironment.cpp
@@ -16,6 +16,7 @@ #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfdoc/cpdf_nametree.h" +#include "core/fxcrt/autorestorer.h" #include "core/fxcrt/check.h" #include "core/fxcrt/containers/contains.h" #include "core/fxcrt/data_vector.h" @@ -120,6 +121,9 @@ CFX_PointF ptA = pFormField->PWLtoFFL(CFX_PointF(rect.left, rect.bottom)); CFX_PointF ptB = pFormField->PWLtoFFL(CFX_PointF(rect.right, rect.top)); + + AutoRestorer<bool> ffi_restorer(&in_passive_ffi_callback_); + in_passive_ffi_callback_ = true; info_->FFI_OutputSelectedRect(info_, pPage, ptA.x, ptB.y, ptB.x, ptA.y); } @@ -366,6 +370,8 @@ void CPDFSDK_FormFillEnvironment::Invalidate(IPDF_Page* page, const FX_RECT& rect) { if (info_ && info_->FFI_Invalidate) { + AutoRestorer<bool> ffi_restorer(&in_passive_ffi_callback_); + in_passive_ffi_callback_ = true; info_->FFI_Invalidate(info_, FPDFPageFromIPDFPage(page), rect.left, rect.top, rect.right, rect.bottom); } @@ -374,6 +380,8 @@ void CPDFSDK_FormFillEnvironment::SetCursor( IPWL_FillerNotify::CursorStyle nCursorType) { if (info_ && info_->FFI_SetCursor) { + AutoRestorer<bool> ffi_restorer(&in_passive_ffi_callback_); + in_passive_ffi_callback_ = true; info_->FFI_SetCursor(info_, static_cast<int>(nCursorType)); } } @@ -394,6 +402,8 @@ void CPDFSDK_FormFillEnvironment::OnChange() { if (info_ && info_->FFI_OnChange) { + AutoRestorer<bool> ffi_restorer(&in_passive_ffi_callback_); + in_passive_ffi_callback_ = true; info_->FFI_OnChange(info_); } } @@ -416,6 +426,8 @@ size_t nCharacters = text.GetLength(); ByteString bsUTFText = text.ToUTF16LE(); auto* pBuffer = reinterpret_cast<const unsigned short*>(bsUTFText.c_str()); + AutoRestorer<bool> ffi_restorer(&in_passive_ffi_callback_); + in_passive_ffi_callback_ = true; info_->FFI_SetTextFieldFocus( info_, pBuffer, pdfium::checked_cast<FPDF_DWORD>(nCharacters), bFocus); } @@ -484,6 +496,8 @@ double right, double bottom) { if (info_ && info_->version >= 2 && info_->FFI_DisplayCaret) { + AutoRestorer<bool> ffi_restorer(&in_passive_ffi_callback_); + in_passive_ffi_callback_ = true; info_->FFI_DisplayCaret(info_, FPDFPageFromIPDFPage(page), bVisible, left, top, right, bottom); } @@ -901,6 +915,8 @@ FPDF_ANNOTATION fpdf_annot = FPDFAnnotationFromCPDFAnnotContext(focused_annot.get()); + AutoRestorer<bool> ffi_restorer(&in_passive_ffi_callback_); + in_passive_ffi_callback_ = true; info_->FFI_OnFocusChange(info_, fpdf_annot, pPageView->GetPageIndex()); }
diff --git a/fpdfsdk/cpdfsdk_formfillenvironment.h b/fpdfsdk/cpdfsdk_formfillenvironment.h index 56613dc..74efbd8 100644 --- a/fpdfsdk/cpdfsdk_formfillenvironment.h +++ b/fpdfsdk/cpdfsdk_formfillenvironment.h
@@ -85,6 +85,8 @@ bool HasPermissions(uint32_t flags) const override; void OnChange() override; + bool InPassiveFFICallback() const { return in_passive_ffi_callback_; } + CPDFSDK_PageView* GetPageViewAtIndex(int nIndex); void RemovePageView(IPDF_Page* pUnderlyingPage); void UpdateAllViews(CPDFSDK_Annot* pAnnot); @@ -287,6 +289,7 @@ std::unique_ptr<CFFL_InteractiveFormFiller> interactive_form_filler_; bool change_mask_ = false; bool being_destroyed_ = false; + bool in_passive_ffi_callback_ = false; // Holds the list of focusable annot types. // Annotations of type WIDGET are by default focusable.
diff --git a/fpdfsdk/fpdf_formfill.cpp b/fpdfsdk/fpdf_formfill.cpp index 451cdd5..d05882b 100644 --- a/fpdfsdk/fpdf_formfill.cpp +++ b/fpdfsdk/fpdf_formfill.cpp
@@ -850,6 +850,12 @@ FPDF_EXPORT void FPDF_CALLCONV FORM_OnAfterLoadPage(FPDF_PAGE page, FPDF_FORMHANDLE hHandle) { + CPDFSDK_FormFillEnvironment* pFormFillEnv = + CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle); + if (!pFormFillEnv || pFormFillEnv->InPassiveFFICallback()) { + return; + } + if (CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page)) { pPageView->SetValid(true); } @@ -859,7 +865,7 @@ FPDF_FORMHANDLE hHandle) { CPDFSDK_FormFillEnvironment* pFormFillEnv = CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle); - if (!pFormFillEnv) { + if (!pFormFillEnv || pFormFillEnv->InPassiveFFICallback()) { return; } @@ -880,7 +886,11 @@ FORM_DoDocumentJSAction(FPDF_FORMHANDLE hHandle) { CPDFSDK_FormFillEnvironment* pFormFillEnv = CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle); - if (pFormFillEnv && pFormFillEnv->IsJSPlatformPresent()) { + if (!pFormFillEnv || pFormFillEnv->InPassiveFFICallback()) { + return; + } + + if (pFormFillEnv->IsJSPlatformPresent()) { pFormFillEnv->ProcJavascriptAction(); } } @@ -889,16 +899,18 @@ FORM_DoDocumentOpenAction(FPDF_FORMHANDLE hHandle) { CPDFSDK_FormFillEnvironment* pFormFillEnv = CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle); - if (pFormFillEnv) { - pFormFillEnv->ProcOpenAction(); + if (!pFormFillEnv || pFormFillEnv->InPassiveFFICallback()) { + return; } + + pFormFillEnv->ProcOpenAction(); } FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentAAction(FPDF_FORMHANDLE hHandle, int aaType) { CPDFSDK_FormFillEnvironment* pFormFillEnv = CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle); - if (!pFormFillEnv) { + if (!pFormFillEnv || pFormFillEnv->InPassiveFFICallback()) { return; } @@ -920,7 +932,7 @@ int aaType) { CPDFSDK_FormFillEnvironment* pFormFillEnv = CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle); - if (!pFormFillEnv) { + if (!pFormFillEnv || pFormFillEnv->InPassiveFFICallback()) { return; }