Fix leak inside sycc420_to_rgb(). In the process, introduce ScopedOpjImageData to help manage the memory allocated by opj_image_data_alloc(). BUG=chromium:934638 Change-Id: I796fd9ecc504b7f8d88d3fe40129cb2eabc5adfc Reviewed-on: https://pdfium-review.googlesource.com/c/51070 Reviewed-by: Nicolás Peña Moreno <npm@chromium.org> Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxcodec/codec/ccodec_jpxmodule.cpp b/core/fxcodec/codec/ccodec_jpxmodule.cpp index fbfc077..0e82b7f 100644 --- a/core/fxcodec/codec/ccodec_jpxmodule.cpp +++ b/core/fxcodec/codec/ccodec_jpxmodule.cpp
@@ -15,6 +15,7 @@ #include "core/fpdfapi/page/cpdf_colorspace.h" #include "core/fxcodec/codec/cjpx_decoder.h" #include "core/fxcrt/fx_safe_types.h" +#include "third_party/base/optional.h" #include "third_party/base/ptr_util.h" #include "third_party/base/stl_util.h" @@ -25,6 +26,19 @@ namespace { +// Used with std::unique_ptr to call opj_image_data_free on raw memory. +struct OpjImageDataDeleter { + inline void operator()(void* ptr) const { opj_image_data_free(ptr); } +}; + +using ScopedOpjImageData = std::unique_ptr<int, OpjImageDataDeleter>; + +struct OpjImageRgbData { + ScopedOpjImageData r; + ScopedOpjImageData g; + ScopedOpjImageData b; +}; + void fx_ignore_callback(const char* msg, void* client_data) {} opj_stream_t* fx_opj_stream_create_memory_stream(DecodeData* data) { @@ -44,28 +58,21 @@ return stream; } -bool alloc_rgb(int** out_r, int** out_g, int** out_b, size_t size) { - int* r = static_cast<int*>(opj_image_data_alloc(size)); - if (!r) - return false; +Optional<OpjImageRgbData> alloc_rgb(size_t size) { + OpjImageRgbData data; + data.r.reset(static_cast<int*>(opj_image_data_alloc(size))); + if (!data.r) + return {}; - int* g = static_cast<int*>(opj_image_data_alloc(size)); - if (!g) { - opj_image_data_free(r); - return false; - } + data.g.reset(static_cast<int*>(opj_image_data_alloc(size))); + if (!data.g) + return {}; - int* b = static_cast<int*>(opj_image_data_alloc(size)); - if (!b) { - opj_image_data_free(r); - opj_image_data_free(g); - return false; - } + data.b.reset(static_cast<int*>(opj_image_data_alloc(size))); + if (!data.b) + return {}; - *out_r = r; - *out_g = g; - *out_b = b; - return true; + return data; } void sycc_to_rgb(int offset, @@ -106,25 +113,23 @@ if (!y || !cb || !cr) return; - int* r; - int* g; - int* b; - if (!alloc_rgb(&r, &g, &b, max_size.ValueOrDie())) + Optional<OpjImageRgbData> data = alloc_rgb(max_size.ValueOrDie()); + if (!data.has_value()) return; - int* d0 = r; - int* d1 = g; - int* d2 = b; + int* r = data.value().r.get(); + int* g = data.value().g.get(); + int* b = data.value().b.get(); max_size /= sizeof(int); - for (size_t i = 0; i < max_size.ValueOrDie(); ++i) { + for (size_t i = 0; i < max_size.ValueOrDie(); ++i) sycc_to_rgb(offset, upb, *y++, *cb++, *cr++, r++, g++, b++); - } + opj_image_data_free(img->comps[0].data); opj_image_data_free(img->comps[1].data); opj_image_data_free(img->comps[2].data); - img->comps[0].data = d0; - img->comps[1].data = d1; - img->comps[2].data = d2; + img->comps[0].data = data.value().r.release(); + img->comps[1].data = data.value().g.release(); + img->comps[2].data = data.value().b.release(); } bool sycc420_422_size_is_valid(opj_image_t* img) { @@ -168,15 +173,13 @@ if (!y || !cb || !cr) return; - int* r; - int* g; - int* b; - if (!alloc_rgb(&r, &g, &b, max_size.ValueOrDie())) + Optional<OpjImageRgbData> data = alloc_rgb(max_size.ValueOrDie()); + if (!data.has_value()) return; - int* d0 = r; - int* d1 = g; - int* d2 = b; + int* r = data.value().r.get(); + int* g = data.value().g.get(); + int* b = data.value().b.get(); for (uint32_t i = 0; i < maxh; ++i) { OPJ_UINT32 j; for (j = 0; j < (maxw & ~static_cast<OPJ_UINT32>(1)); j += 2) { @@ -187,12 +190,13 @@ sycc_to_rgb(offset, upb, *y++, *cb++, *cr++, r++, g++, b++); } } + opj_image_data_free(img->comps[0].data); opj_image_data_free(img->comps[1].data); opj_image_data_free(img->comps[2].data); - img->comps[0].data = d0; - img->comps[1].data = d1; - img->comps[2].data = d2; + img->comps[0].data = data.value().r.release(); + img->comps[1].data = data.value().g.release(); + img->comps[2].data = data.value().b.release(); img->comps[1].w = maxw; img->comps[1].h = maxh; img->comps[2].w = maxw; @@ -336,27 +340,25 @@ OPJ_UINT32 crw = img->comps[2].w; bool extw = sycc420_must_extend_cbcr(yw, cbw); bool exth = sycc420_must_extend_cbcr(yh, cbh); - FX_SAFE_UINT32 safeSize = yw; - safeSize *= yh; - safeSize *= sizeof(int); - if (!safeSize.IsValid()) + FX_SAFE_UINT32 safe_size = yw; + safe_size *= yh; + safe_size *= sizeof(int); + if (!safe_size.IsValid()) return; - int* r; - int* g; - int* b; - if (!alloc_rgb(&r, &g, &b, safeSize.ValueOrDie())) - return; - - int* d0 = r; - int* d1 = g; - int* d2 = b; const int* y = img->comps[0].data; const int* cb = img->comps[1].data; const int* cr = img->comps[2].data; if (!y || !cb || !cr) return; + Optional<OpjImageRgbData> data = alloc_rgb(safe_size.ValueOrDie()); + if (!data.has_value()) + return; + + int* r = data.value().r.get(); + int* g = data.value().g.get(); + int* b = data.value().b.get(); const int* ny = nullptr; int* nr = nullptr; int* ng = nullptr; @@ -446,9 +448,9 @@ opj_image_data_free(img->comps[0].data); opj_image_data_free(img->comps[1].data); opj_image_data_free(img->comps[2].data); - img->comps[0].data = d0; - img->comps[1].data = d1; - img->comps[2].data = d2; + img->comps[0].data = data.value().r.release(); + img->comps[1].data = data.value().g.release(); + img->comps[2].data = data.value().b.release(); img->comps[1].w = yw; img->comps[1].h = yh; img->comps[2].w = yw;