Move setjmp() calls from .cpp to .c files.

Avoid issue where C++ objects may be in an inconsistent state
following the duplicate return from a corresponding longjmp().
Doesn't fix the underlying issue in the referenced bug.

-- rename functions in jpeg_common.c for consistency.

Bug: 379259821
Change-Id: I9c9eff840ad336b9dd5ce5364c7fc68920bc184a
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/126254
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
diff --git a/core/fxcodec/jpeg/jpeg_common.c b/core/fxcodec/jpeg/jpeg_common.c
index a021761..7ea70bf 100644
--- a/core/fxcodec/jpeg/jpeg_common.c
+++ b/core/fxcodec/jpeg/jpeg_common.c
@@ -6,19 +6,56 @@
 
 #include "core/fxcodec/jpeg/jpeg_common.h"
 
-void src_do_nothing(j_decompress_ptr cinfo) {}
+// This is a thin C wrapper around the JPEG API to avoid calling setjmp() from
+// C++ code.
 
-boolean src_fill_buffer(j_decompress_ptr cinfo) {
+boolean jpeg_common_create_decompress(JpegCommon* jpeg_common) {
+  if (setjmp(jpeg_common->jmpbuf) == -1) {
+    return FALSE;
+  }
+  jpeg_create_decompress(&jpeg_common->cinfo);
+  return TRUE;
+}
+
+void jpeg_common_destroy_decompress(JpegCommon* jpeg_common) {
+  jpeg_destroy_decompress(&jpeg_common->cinfo);
+}
+
+boolean jpeg_common_start_decompress(JpegCommon* jpeg_common) {
+  if (setjmp(jpeg_common->jmpbuf) == -1) {
+    return FALSE;
+  }
+  return jpeg_start_decompress(&jpeg_common->cinfo);
+}
+
+int jpeg_common_read_header(JpegCommon* jpeg_common, boolean flag) {
+  if (setjmp(jpeg_common->jmpbuf) == -1) {
+    return -1;
+  }
+  return jpeg_read_header(&jpeg_common->cinfo, flag);
+}
+
+int jpeg_common_read_scanlines(JpegCommon* jpeg_common,
+                               void* buf,
+                               unsigned int count) {
+  if (setjmp(jpeg_common->jmpbuf) == -1) {
+    return -1;
+  }
+  return jpeg_read_scanlines(&jpeg_common->cinfo, buf, count);
+}
+
+void jpeg_common_src_do_nothing(j_decompress_ptr cinfo) {}
+
+boolean jpeg_common_src_fill_buffer(j_decompress_ptr cinfo) {
   return FALSE;
 }
 
-boolean src_resync(j_decompress_ptr cinfo, int desired) {
+boolean jpeg_common_src_resync(j_decompress_ptr cinfo, int desired) {
   return FALSE;
 }
 
-void error_do_nothing(j_common_ptr cinfo) {}
+void jpeg_common_error_do_nothing(j_common_ptr cinfo) {}
 
-void error_do_nothing_int(j_common_ptr cinfo, int arg) {}
+void jpeg_common_error_do_nothing_int(j_common_ptr cinfo, int arg) {}
 
-void error_do_nothing_char(j_common_ptr cinfo, char* arg) {}
-
+void jpeg_common_error_do_nothing_char(j_common_ptr cinfo, char* arg) {}
diff --git a/core/fxcodec/jpeg/jpeg_common.h b/core/fxcodec/jpeg/jpeg_common.h
index 4d8e986..677e44d 100644
--- a/core/fxcodec/jpeg/jpeg_common.h
+++ b/core/fxcodec/jpeg/jpeg_common.h
@@ -44,12 +44,21 @@
 };
 typedef struct JpegCommon JpegCommon;
 
-void src_do_nothing(j_decompress_ptr cinfo);
-boolean src_fill_buffer(j_decompress_ptr cinfo);
-boolean src_resync(j_decompress_ptr cinfo, int desired);
-void error_do_nothing(j_common_ptr cinfo);
-void error_do_nothing_int(j_common_ptr cinfo, int arg);
-void error_do_nothing_char(j_common_ptr cinfo, char* arg);
+boolean jpeg_common_create_decompress(JpegCommon* jpeg_common);
+void jpeg_common_destroy_decompress(JpegCommon* jpeg_common);
+boolean jpeg_common_start_decompress(JpegCommon* jpeg_common);
+int jpeg_common_read_header(JpegCommon* jpeg_common, boolean flag);
+int jpeg_common_read_scanlines(JpegCommon* jpeg_common,
+                               void* buf,
+                               unsigned int count);
+
+//  Callbacks.
+void jpeg_common_src_do_nothing(j_decompress_ptr cinfo);
+boolean jpeg_common_src_fill_buffer(j_decompress_ptr cinfo);
+boolean jpeg_common_src_resync(j_decompress_ptr cinfo, int desired);
+void jpeg_common_error_do_nothing(j_common_ptr cinfo);
+void jpeg_common_error_do_nothing_int(j_common_ptr cinfo, int arg);
+void jpeg_common_error_do_nothing_char(j_common_ptr cinfo, char* arg);
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/core/fxcodec/jpeg/jpeg_progressive_decoder.cpp b/core/fxcodec/jpeg/jpeg_progressive_decoder.cpp
index ab0581c..9f6072a 100644
--- a/core/fxcodec/jpeg/jpeg_progressive_decoder.cpp
+++ b/core/fxcodec/jpeg/jpeg_progressive_decoder.cpp
@@ -16,7 +16,6 @@
 #include "core/fxcrt/check.h"
 #include "core/fxcrt/compiler_specific.h"
 #include "core/fxcrt/fx_safe_types.h"
-#include "core/fxcrt/ptr_util.h"
 #include "core/fxge/dib/cfx_dibbase.h"
 #include "core/fxge/dib/fx_dib.h"
 
@@ -65,16 +64,16 @@
   m_Common.cinfo.err = &m_Common.error_mgr;
 
   m_Common.error_mgr.error_exit = error_fatal;
-  m_Common.error_mgr.emit_message = error_do_nothing_int;
-  m_Common.error_mgr.output_message = error_do_nothing;
-  m_Common.error_mgr.format_message = error_do_nothing_char;
-  m_Common.error_mgr.reset_error_mgr = error_do_nothing;
+  m_Common.error_mgr.emit_message = jpeg_common_error_do_nothing_int;
+  m_Common.error_mgr.output_message = jpeg_common_error_do_nothing;
+  m_Common.error_mgr.format_message = jpeg_common_error_do_nothing_char;
+  m_Common.error_mgr.reset_error_mgr = jpeg_common_error_do_nothing;
 
-  m_Common.source_mgr.init_source = src_do_nothing;
-  m_Common.source_mgr.term_source = src_do_nothing;
+  m_Common.source_mgr.init_source = jpeg_common_src_do_nothing;
+  m_Common.source_mgr.term_source = jpeg_common_src_do_nothing;
   m_Common.source_mgr.skip_input_data = src_skip_data;
-  m_Common.source_mgr.fill_input_buffer = src_fill_buffer;
-  m_Common.source_mgr.resync_to_restart = src_resync;
+  m_Common.source_mgr.fill_input_buffer = jpeg_common_src_fill_buffer;
+  m_Common.source_mgr.resync_to_restart = jpeg_common_src_resync;
 }
 
 CJpegContext::~CJpegContext() {
@@ -109,17 +108,13 @@
 // static
 std::unique_ptr<ProgressiveDecoderIface::Context>
 JpegProgressiveDecoder::Start() {
-  // Use ordinary pointer until past the possibility of a longjump.
-  auto* pContext = new CJpegContext();
-  if (setjmp(pContext->m_Common.jmpbuf) == -1) {
-    delete pContext;
+  auto pContext = std::make_unique<CJpegContext>();
+  if (!jpeg_common_create_decompress(&pContext->m_Common)) {
     return nullptr;
   }
-
-  jpeg_create_decompress(&pContext->m_Common.cinfo);
   pContext->m_Common.cinfo.src = &pContext->m_Common.source_mgr;
   pContext->m_SkipSize = 0;
-  return pdfium::WrapUnique(pContext);
+  return pContext;
 }
 
 // static
diff --git a/core/fxcodec/jpeg/jpegmodule.cpp b/core/fxcodec/jpeg/jpegmodule.cpp
index 6d97e0e..5d30070 100644
--- a/core/fxcodec/jpeg/jpegmodule.cpp
+++ b/core/fxcodec/jpeg/jpegmodule.cpp
@@ -6,8 +6,6 @@
 
 #include "core/fxcodec/jpeg/jpegmodule.h"
 
-#include <setjmp.h>
-
 #include <memory>
 #include <optional>
 #include <type_traits>
@@ -65,35 +63,30 @@
 static bool JpegLoadInfo(pdfium::span<const uint8_t> src_span,
                          JpegModule::ImageInfo* pInfo) {
   src_span = JpegScanSOI(src_span);
+
   JpegCommon jpeg_common = {};
   jpeg_common.error_mgr.error_exit = error_fatal;
-  jpeg_common.error_mgr.emit_message = error_do_nothing_int;
-  jpeg_common.error_mgr.output_message = error_do_nothing;
-  jpeg_common.error_mgr.format_message = error_do_nothing_char;
-  jpeg_common.error_mgr.reset_error_mgr = error_do_nothing;
+  jpeg_common.error_mgr.emit_message = jpeg_common_error_do_nothing_int;
+  jpeg_common.error_mgr.output_message = jpeg_common_error_do_nothing;
+  jpeg_common.error_mgr.format_message = jpeg_common_error_do_nothing_char;
+  jpeg_common.error_mgr.reset_error_mgr = jpeg_common_error_do_nothing;
   jpeg_common.error_mgr.trace_level = 0;
   jpeg_common.cinfo.err = &jpeg_common.error_mgr;
   jpeg_common.cinfo.client_data = &jpeg_common.jmpbuf;
-  if (setjmp(jpeg_common.jmpbuf) == -1) {
+  if (!jpeg_common_create_decompress(&jpeg_common)) {
     return false;
   }
 
-  jpeg_create_decompress(&jpeg_common.cinfo);
-  jpeg_common.source_mgr.init_source = src_do_nothing;
-  jpeg_common.source_mgr.term_source = src_do_nothing;
+  jpeg_common.source_mgr.init_source = jpeg_common_src_do_nothing;
+  jpeg_common.source_mgr.term_source = jpeg_common_src_do_nothing;
   jpeg_common.source_mgr.skip_input_data = src_skip_data;
-  jpeg_common.source_mgr.fill_input_buffer = src_fill_buffer;
-  jpeg_common.source_mgr.resync_to_restart = src_resync;
+  jpeg_common.source_mgr.fill_input_buffer = jpeg_common_src_fill_buffer;
+  jpeg_common.source_mgr.resync_to_restart = jpeg_common_src_resync;
   jpeg_common.source_mgr.bytes_in_buffer = src_span.size();
   jpeg_common.source_mgr.next_input_byte = src_span.data();
   jpeg_common.cinfo.src = &jpeg_common.source_mgr;
-  if (setjmp(jpeg_common.jmpbuf) == -1) {
-    jpeg_destroy_decompress(&jpeg_common.cinfo);
-    return false;
-  }
-  int ret = jpeg_read_header(&jpeg_common.cinfo, TRUE);
-  if (ret != JPEG_HEADER_OK) {
-    jpeg_destroy_decompress(&jpeg_common.cinfo);
+  if (jpeg_common_read_header(&jpeg_common, TRUE) != JPEG_HEADER_OK) {
+    jpeg_common_destroy_decompress(&jpeg_common);
     return false;
   }
   pInfo->width = jpeg_common.cinfo.image_width;
@@ -102,7 +95,7 @@
   pInfo->color_transform = jpeg_common.cinfo.jpeg_color_space == JCS_YCbCr ||
                            jpeg_common.cinfo.jpeg_color_space == JCS_YCCK;
   pInfo->bits_per_components = jpeg_common.cinfo.data_precision;
-  jpeg_destroy_decompress(&jpeg_common.cinfo);
+  jpeg_common_destroy_decompress(&jpeg_common);
   return true;
 }
 
@@ -134,7 +127,7 @@
   void CalcPitch();
   void InitDecompressSrc();
 
-  // Can only be called inside a jpeg_read_header() setjmp handler.
+  // Only called when initial jpeg_read_header() fails.
   bool HasKnownBadHeaderWithInvalidHeight(size_t dimension_offset) const;
 
   // Is a JPEG SOFn marker, which is defined as 0xff, 0xc[0-9a-f].
@@ -165,8 +158,9 @@
 JpegDecoder::JpegDecoder() = default;
 
 JpegDecoder::~JpegDecoder() {
-  if (m_bInited)
-    jpeg_destroy_decompress(&m_Common.cinfo);
+  if (m_bInited) {
+    jpeg_common_destroy_decompress(&m_Common);
+  }
 
   // Span in superclass can't outlive our buffer.
   m_pLastScanline = pdfium::span<uint8_t>();
@@ -175,15 +169,14 @@
 bool JpegDecoder::InitDecode(bool bAcceptKnownBadHeader) {
   m_Common.cinfo.err = &m_Common.error_mgr;
   m_Common.cinfo.client_data = &m_Common.jmpbuf;
-  if (setjmp(m_Common.jmpbuf) == -1) {
+  if (!jpeg_common_create_decompress(&m_Common)) {
     return false;
   }
-
-  jpeg_create_decompress(&m_Common.cinfo);
   InitDecompressSrc();
   m_bInited = true;
-
-  if (setjmp(m_Common.jmpbuf) == -1) {
+  m_Common.cinfo.image_width = m_OrigWidth;
+  m_Common.cinfo.image_height = m_OrigHeight;
+  if (jpeg_common_read_header(&m_Common, TRUE) != JPEG_HEADER_OK) {
     std::optional<size_t> known_bad_header_offset;
     if (bAcceptKnownBadHeader) {
       for (size_t offset : kKnownBadHeaderWithInvalidHeightByteOffsetStarts) {
@@ -193,23 +186,23 @@
         }
       }
     }
-    jpeg_destroy_decompress(&m_Common.cinfo);
+    jpeg_common_destroy_decompress(&m_Common);
     if (!known_bad_header_offset.has_value()) {
       m_bInited = false;
       return false;
     }
-
     PatchUpKnownBadHeaderWithInvalidHeight(known_bad_header_offset.value());
-
-    jpeg_create_decompress(&m_Common.cinfo);
+    if (!jpeg_common_create_decompress(&m_Common)) {
+      return false;
+    }
     InitDecompressSrc();
+    m_Common.cinfo.image_width = m_OrigWidth;
+    m_Common.cinfo.image_height = m_OrigHeight;
+    if (jpeg_common_read_header(&m_Common, TRUE) != JPEG_HEADER_OK) {
+      jpeg_common_destroy_decompress(&m_Common);
+      return false;
+    }
   }
-  m_Common.cinfo.image_width = m_OrigWidth;
-  m_Common.cinfo.image_height = m_OrigHeight;
-  int ret = jpeg_read_header(&m_Common.cinfo, TRUE);
-  if (ret != JPEG_HEADER_OK)
-    return false;
-
   if (m_Common.cinfo.saw_Adobe_marker) {
     m_bJpegTransform = true;
   }
@@ -238,15 +231,15 @@
   PatchUpTrailer();
 
   m_Common.error_mgr.error_exit = error_fatal;
-  m_Common.error_mgr.emit_message = error_do_nothing_int;
-  m_Common.error_mgr.output_message = error_do_nothing;
-  m_Common.error_mgr.format_message = error_do_nothing_char;
-  m_Common.error_mgr.reset_error_mgr = error_do_nothing;
-  m_Common.source_mgr.init_source = src_do_nothing;
-  m_Common.source_mgr.term_source = src_do_nothing;
+  m_Common.error_mgr.emit_message = jpeg_common_error_do_nothing_int;
+  m_Common.error_mgr.output_message = jpeg_common_error_do_nothing;
+  m_Common.error_mgr.format_message = jpeg_common_error_do_nothing_char;
+  m_Common.error_mgr.reset_error_mgr = jpeg_common_error_do_nothing;
+  m_Common.source_mgr.init_source = jpeg_common_src_do_nothing;
+  m_Common.source_mgr.term_source = jpeg_common_src_do_nothing;
   m_Common.source_mgr.skip_input_data = src_skip_data;
-  m_Common.source_mgr.fill_input_buffer = src_fill_buffer;
-  m_Common.source_mgr.resync_to_restart = src_resync;
+  m_Common.source_mgr.fill_input_buffer = jpeg_common_src_fill_buffer;
+  m_Common.source_mgr.resync_to_restart = jpeg_common_src_resync;
   m_bJpegTransform = ColorTransform;
   m_OutputWidth = m_OrigWidth = width;
   m_OutputHeight = m_OrigHeight = height;
@@ -271,19 +264,16 @@
 
 bool JpegDecoder::Rewind() {
   if (m_bStarted) {
-    jpeg_destroy_decompress(&m_Common.cinfo);
+    jpeg_common_destroy_decompress(&m_Common);
     if (!InitDecode(/*bAcceptKnownBadHeader=*/false)) {
       return false;
     }
   }
-  if (setjmp(m_Common.jmpbuf) == -1) {
-    return false;
-  }
   m_Common.cinfo.scale_denom = m_nDefaultScaleDenom;
   m_OutputWidth = m_OrigWidth;
   m_OutputHeight = m_OrigHeight;
-  if (!jpeg_start_decompress(&m_Common.cinfo)) {
-    jpeg_destroy_decompress(&m_Common.cinfo);
+  if (!jpeg_common_start_decompress(&m_Common)) {
+    jpeg_common_destroy_decompress(&m_Common);
     return false;
   }
   CHECK_LE(static_cast<int>(m_Common.cinfo.output_width), m_OrigWidth);
@@ -292,15 +282,11 @@
 }
 
 pdfium::span<uint8_t> JpegDecoder::GetNextLine() {
-  if (setjmp(m_Common.jmpbuf) == -1) {
+  uint8_t* row_array[] = {m_ScanlineBuf.data()};
+  int nlines = jpeg_common_read_scanlines(&m_Common, row_array, 1u);
+  if (nlines <= 0) {
     return pdfium::span<uint8_t>();
   }
-
-  uint8_t* row_array[] = {m_ScanlineBuf.data()};
-  int nlines = jpeg_read_scanlines(&m_Common.cinfo, row_array, 1);
-  if (nlines <= 0)
-    return pdfium::span<uint8_t>();
-
   return m_ScanlineBuf;
 }
 
@@ -410,11 +396,11 @@
                             uint8_t** dest_buf,
                             size_t* dest_size) {
   jpeg_error_mgr jerr;
-  jerr.error_exit = error_do_nothing;
-  jerr.emit_message = error_do_nothing_int;
-  jerr.output_message = error_do_nothing;
-  jerr.format_message = error_do_nothing_char;
-  jerr.reset_error_mgr = error_do_nothing;
+  jerr.error_exit = jpeg_common_error_do_nothing;
+  jerr.emit_message = jpeg_common_error_do_nothing_int;
+  jerr.output_message = jpeg_common_error_do_nothing;
+  jerr.format_message = jpeg_common_error_do_nothing_char;
+  jerr.reset_error_mgr = jpeg_common_error_do_nothing;
 
   jpeg_compress_struct cinfo = {};  // Aggregate initialization.
   static_assert(std::is_aggregate_v<decltype(cinfo)>);