summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver Chang <ochang@chromium.org>2016-08-16 12:52:24 -0700
committerOliver Chang <ochang@chromium.org>2016-08-16 12:52:24 -0700
commitfe9485fff248dd04a0643e4ce2309aec7ae237e1 (patch)
tree6d9f9a1a315f637cfb77c894c26da9c7c90076d8
parent3cde1a2d144e562b8bf3c8009039ca1cf67a8b44 (diff)
downloadpdfium-fe9485fff248dd04a0643e4ce2309aec7ae237e1.tar.xz
Merge 2 CLs to M53.
TBR=tsepez@chromium.org Remove another potential stale CJS_Timer usage Fix memory ownership model for PDFium timers. The |app| class owns the CJS_Timer as part of its vector<unique_ptr> to them. The CJS_Timer "owns" its slot in the global ID to timer map, and removes itself when it is destroyed. Nothing else deletes from the global map. Deleting from the global map is accompanied by a callback to the embedder to clear its resources. Next, the proper way to remove a CJS_Timer is by going through the app, and having the app erase its unique ptr, which then deletes the CJS_Timer, which in turn cleans up the global map. Provide a CJS_Timer::Cancel static method to do this conveniently. There is a alternate path to the CJS_timer via JS and its CJS_TimerObj. CJS_TimerObj owns a TimerObj that currently points to the CJS_Timer. If the timer fires, and cleans itself up, this can go stale. Make the TimerObj maintain a weak reference via global timer ID rather than a direct pointer to the CJS_Timer, so that if the timer fires and is destroyed, future attempts to cancel find nothing. There is another path, where if the JS timer object is GC'd, then we just clean up its CJS_TimerObj without touching the actual CJS_Timers. We could make this match the spec by calling into the new cancel routine as described above, but it seems weird to have a timer depend on whether a gc happened or not. A subsequent CL will rename these objects to more closely match the conventions used by the other JS wrappers. BUG=634716 Review-Url: https://codereview.chromium.org/2221513002 (cherry picked from commit 8ca63de14d522d3d259d74fa43b28b05b02728e8) openjpeg: Prevent negative x, y values in opj_tcd_init_tile BUG=632622 Review-Url: https://codereview.chromium.org/2223303002 (cherry picked from commit b6befb2ed2485a3805cddea86dc7574510178ea9) Review URL: https://codereview.chromium.org/2251703003 .
-rw-r--r--fpdfsdk/fpdfformfill_embeddertest.cpp22
-rw-r--r--fpdfsdk/javascript/JS_Object.cpp38
-rw-r--r--fpdfsdk/javascript/JS_Object.h10
-rw-r--r--fpdfsdk/javascript/app.cpp47
-rw-r--r--fpdfsdk/javascript/app.h6
-rw-r--r--testing/resources/bug_634716.in126
-rw-r--r--testing/resources/bug_634716.pdf180
-rw-r--r--third_party/libopenjpeg20/0021-tcd_init_tile_negative.patch21
-rw-r--r--third_party/libopenjpeg20/README.pdfium1
-rw-r--r--third_party/libopenjpeg20/tcd.c7
10 files changed, 403 insertions, 55 deletions
diff --git a/fpdfsdk/fpdfformfill_embeddertest.cpp b/fpdfsdk/fpdfformfill_embeddertest.cpp
index dfbfc66be5..20eba09e47 100644
--- a/fpdfsdk/fpdfformfill_embeddertest.cpp
+++ b/fpdfsdk/fpdfformfill_embeddertest.cpp
@@ -125,4 +125,26 @@ TEST_F(FPDFFormFillEmbeddertest, BUG_634394) {
EXPECT_EQ(2U, alerts.size());
}
+TEST_F(FPDFFormFillEmbeddertest, BUG_634716) {
+ EmbedderTestTimerHandlingDelegate delegate;
+ SetDelegate(&delegate);
+
+ EXPECT_TRUE(OpenDocument("bug_634716.pdf"));
+ FPDF_PAGE page = LoadPage(0);
+ EXPECT_TRUE(page);
+ DoOpenActions();
+
+ // Timers fire at most once per AdvanceTime(), allow intervals
+ // to fire several times if possible.
+ delegate.AdvanceTime(1000);
+ delegate.AdvanceTime(1000);
+ delegate.AdvanceTime(1000);
+ delegate.AdvanceTime(1000);
+ delegate.AdvanceTime(1000);
+ UnloadPage(page);
+
+ const auto& alerts = delegate.GetAlerts();
+ EXPECT_EQ(2U, alerts.size());
+}
+
#endif // PDF_ENABLE_V8
diff --git a/fpdfsdk/javascript/JS_Object.cpp b/fpdfsdk/javascript/JS_Object.cpp
index 9505799048..641c6a6167 100644
--- a/fpdfsdk/javascript/JS_Object.cpp
+++ b/fpdfsdk/javascript/JS_Object.cpp
@@ -120,7 +120,7 @@ CJS_Timer::CJS_Timer(CJS_EmbedObj* pObj,
m_pRuntime(pRuntime),
m_pApp(pApp) {
CFX_SystemHandler* pHandler = m_pApp->GetSysHandler();
- m_nTimerID = pHandler->SetTimer(dwElapse, TimerProc);
+ m_nTimerID = pHandler->SetTimer(dwElapse, Trigger);
(*GetGlobalTimerMap())[m_nTimerID] = this;
m_pRuntime->AddObserver(this);
}
@@ -129,23 +129,19 @@ CJS_Timer::~CJS_Timer() {
CJS_Runtime* pRuntime = GetRuntime();
if (pRuntime)
pRuntime->RemoveObserver(this);
- KillJSTimer();
-}
-void CJS_Timer::KillJSTimer() {
- if (m_nTimerID) {
- if (m_bValid) {
- CFX_SystemHandler* pHandler = m_pApp->GetSysHandler();
- pHandler->KillTimer(m_nTimerID);
- }
- GetGlobalTimerMap()->erase(m_nTimerID);
- m_nTimerID = 0;
- }
+ if (!m_nTimerID)
+ return;
+
+ if (m_bValid)
+ m_pApp->GetSysHandler()->KillTimer(m_nTimerID);
+
+ GetGlobalTimerMap()->erase(m_nTimerID);
}
// static
-void CJS_Timer::TimerProc(int idEvent) {
- auto it = GetGlobalTimerMap()->find(idEvent);
+void CJS_Timer::Trigger(int nTimerID) {
+ auto it = GetGlobalTimerMap()->find(nTimerID);
if (it == GetGlobalTimerMap()->end())
return;
@@ -158,12 +154,24 @@ void CJS_Timer::TimerProc(int idEvent) {
pTimer->m_pEmbedObj->TimerProc(pTimer);
// Timer proc may have destroyed timer, find it again.
- it = GetGlobalTimerMap()->find(idEvent);
+ it = GetGlobalTimerMap()->find(nTimerID);
if (it == GetGlobalTimerMap()->end())
return;
pTimer = it->second;
pTimer->m_bProcessing = false;
+ if (pTimer->IsOneShot())
+ pTimer->m_pEmbedObj->CancelProc(pTimer);
+}
+
+// static
+void CJS_Timer::Cancel(int nTimerID) {
+ auto it = GetGlobalTimerMap()->find(nTimerID);
+ if (it == GetGlobalTimerMap()->end())
+ return;
+
+ CJS_Timer* pTimer = it->second;
+ pTimer->m_pEmbedObj->CancelProc(pTimer);
}
// static
diff --git a/fpdfsdk/javascript/JS_Object.h b/fpdfsdk/javascript/JS_Object.h
index 908645ce33..974008226a 100644
--- a/fpdfsdk/javascript/JS_Object.h
+++ b/fpdfsdk/javascript/JS_Object.h
@@ -18,12 +18,14 @@ class CJS_Context;
class CJS_Object;
class CJS_Timer;
class CPDFDoc_Environment;
+
class CJS_EmbedObj {
public:
explicit CJS_EmbedObj(CJS_Object* pJSObject);
virtual ~CJS_EmbedObj();
virtual void TimerProc(CJS_Timer* pTimer) {}
+ virtual void CancelProc(CJS_Timer* pTimer) {}
CJS_Object* GetJSObject() const { return m_pJSObject; }
@@ -84,15 +86,15 @@ class CJS_Timer : public CJS_Runtime::Observer {
uint32_t dwTimeOut);
~CJS_Timer() override;
- void KillJSTimer();
+ static void Trigger(int nTimerID);
+ static void Cancel(int nTimerID);
- int GetType() const { return m_nType; }
+ bool IsOneShot() const { return m_nType == 1; }
uint32_t GetTimeOut() const { return m_dwTimeOut; }
+ int GetTimerID() const { return m_nTimerID; }
CJS_Runtime* GetRuntime() const { return m_bValid ? m_pRuntime : nullptr; }
CFX_WideString GetJScript() const { return m_swJScript; }
- static void TimerProc(int idEvent);
-
private:
using TimerMap = std::map<FX_UINT, CJS_Timer*>;
static TimerMap* GetGlobalTimerMap();
diff --git a/fpdfsdk/javascript/app.cpp b/fpdfsdk/javascript/app.cpp
index dd706ebd8c..78b7bcae70 100644
--- a/fpdfsdk/javascript/app.cpp
+++ b/fpdfsdk/javascript/app.cpp
@@ -31,16 +31,12 @@ END_JS_STATIC_METHOD()
IMPLEMENT_JS_CLASS(CJS_TimerObj, TimerObj)
TimerObj::TimerObj(CJS_Object* pJSObject)
- : CJS_EmbedObj(pJSObject), m_pTimer(nullptr) {}
+ : CJS_EmbedObj(pJSObject), m_nTimerID(0) {}
TimerObj::~TimerObj() {}
void TimerObj::SetTimer(CJS_Timer* pTimer) {
- m_pTimer = pTimer;
-}
-
-CJS_Timer* TimerObj::GetTimer() const {
- return m_pTimer;
+ m_nTimerID = pTimer->GetTimerID();
}
#define JS_STR_VIEWERTYPE L"pdfium"
@@ -473,20 +469,7 @@ void app::ClearTimerCommon(const CJS_Value& param) {
if (!pTimerObj)
return;
- CJS_Timer* pTimer = pTimerObj->GetTimer();
- if (!pTimer)
- return;
-
- pTimer->KillJSTimer();
- auto iter = std::find_if(m_Timers.begin(), m_Timers.end(),
- [pTimer](const std::unique_ptr<CJS_Timer>& that) {
- return pTimer == that.get();
- });
-
- if (iter != m_Timers.end())
- m_Timers.erase(iter);
-
- pTimerObj->SetTimer(nullptr);
+ CJS_Timer::Cancel(pTimerObj->GetTimerID());
}
FX_BOOL app::execMenuItem(IJS_Context* cc,
@@ -498,20 +481,18 @@ FX_BOOL app::execMenuItem(IJS_Context* cc,
void app::TimerProc(CJS_Timer* pTimer) {
CJS_Runtime* pRuntime = pTimer->GetRuntime();
+ if (pRuntime && (!pTimer->IsOneShot() || pTimer->GetTimeOut() > 0))
+ RunJsScript(pRuntime, pTimer->GetJScript());
+}
- switch (pTimer->GetType()) {
- case 0: // interval
- if (pRuntime)
- RunJsScript(pRuntime, pTimer->GetJScript());
- break;
- case 1:
- if (pTimer->GetTimeOut() > 0) {
- if (pRuntime)
- RunJsScript(pRuntime, pTimer->GetJScript());
- pTimer->KillJSTimer();
- }
- break;
- }
+void app::CancelProc(CJS_Timer* pTimer) {
+ auto iter = std::find_if(m_Timers.begin(), m_Timers.end(),
+ [pTimer](const std::unique_ptr<CJS_Timer>& that) {
+ return pTimer == that.get();
+ });
+
+ if (iter != m_Timers.end())
+ m_Timers.erase(iter);
}
void app::RunJsScript(CJS_Runtime* pRuntime, const CFX_WideString& wsScript) {
diff --git a/fpdfsdk/javascript/app.h b/fpdfsdk/javascript/app.h
index c6cda555d9..bb083cedb4 100644
--- a/fpdfsdk/javascript/app.h
+++ b/fpdfsdk/javascript/app.h
@@ -20,12 +20,11 @@ class TimerObj : public CJS_EmbedObj {
TimerObj(CJS_Object* pJSObject);
~TimerObj() override;
- public:
void SetTimer(CJS_Timer* pTimer);
- CJS_Timer* GetTimer() const;
+ int GetTimerID() const { return m_nTimerID; }
private:
- CJS_Timer* m_pTimer;
+ int m_nTimerID; // Weak reference to timer through global map.
};
class CJS_TimerObj : public CJS_Object {
@@ -158,6 +157,7 @@ class app : public CJS_EmbedObj {
private:
// CJS_EmbedObj
void TimerProc(CJS_Timer* pTimer) override;
+ void CancelProc(CJS_Timer* pTimer) override;
void RunJsScript(CJS_Runtime* pRuntime, const CFX_WideString& wsScript);
void ClearTimerCommon(const CJS_Value& param);
diff --git a/testing/resources/bug_634716.in b/testing/resources/bug_634716.in
new file mode 100644
index 0000000000..a485daed97
--- /dev/null
+++ b/testing/resources/bug_634716.in
@@ -0,0 +1,126 @@
+{{header}}
+{{object 1 0}} <<
+ /Type /Catalog
+ /Pages 2 0 R
+ /AcroForm 6 0 R
+ /Names <</JavaScript 13 0 R>>
+>>
+endobj
+{{object 2 0}} <<
+ /Type /Pages
+ /Count 1
+ /Kids [4 0 R]
+>>
+endobj
+{{object 4 0}} <<
+ /Type /Page
+ /Parent 2 0 R
+ /MediaBox [0 0 612 792]
+ /CropBox [0 0 612 792]
+ /Resources <<>>
+>>
+endobj
+{{object 6 0}} <<
+ /DR <<
+ /Font <</Helv 7 0 R>>
+ >>
+ /DA (/Helv 0 Tf 0 g)
+ /Fields [5 0 R]
+>>
+endobj
+{{object 7 0}} <<
+ /Type /Font
+ /Subtype /Type1
+ /BaseFont /Helvetica
+ /Encoding /WinAnsiEncoding
+>>
+endobj
+{{object 8 0}} <<
+ /Type /XObject
+ /Subtype /Form
+ /FormType 1
+ /Matrix [1 0 0 1 0 0]
+ /BBox [0 0 75.907 28.472]
+ /Resources <<
+ /Font <</FXF0 7 0 R>>
+ >>
+>>
+stream
+q
+Q
+
+
+endstream
+endobj
+{{object 11 0}} <<
+ /Type /Action
+ /S /JavaScript
+ /JS 50 0 R
+>>
+endobj
+{{object 13 0}} <<
+ /Names [(startDelay) 11 0 R]
+>>
+endobj
+{{object 50 0}} <<
+>>
+stream
+var timeOut = 0;
+var array = new Array(1024*4);
+var doc = this;
+
+function myFunction() {
+ try {
+ // Free the Timer Objects
+ app.clearTimeOut(timeOut);
+ for (var i=0; i<array.length; i++) {
+ for (var j=0; j<array[i].length; j++) {
+ app.clearTimeOut(array[i][j]);
+ }
+ }
+
+ // Trigger the Garbage Collection
+ array.length = 0;
+ array.push(new ArrayBuffer(1024*1024));
+ array.length=0;
+ array.length=1024*4;
+ var str = 'AA';
+ for (var i = 0; i < array.length ; i++) {
+ for (var j = 0; j < 10; j++ ) {
+ doc.addIcon(str + "-" + str + str + str + str + str, doc.icons);
+ }
+ }
+ } catch(err) {
+ app.alert(err);
+ }
+}
+
+function main() {
+ try {
+ for (var i = 0; i < array.length ; i++) {
+ if (i == array.length / 2) {
+ timeOut = app.setTimeOut("myFunction()", 1000);
+ }
+ array[i] = new Array(4);
+ for (var j = 0; j < array[i].length ; j++ ) {
+ array[i][j] = app.setTimeOut("aaaaaaaaaa()", 100000);
+ }
+ }
+ } catch(err) {
+ app.alert(err);
+ }
+}
+
+// Execute the JS.
+app.setTimeOut("main()", 1000);
+
+// Be sure all of this code ran to completion.
+app.alert("done");
+endstream
+endobj
+{{xref}}
+trailer <<
+ /Root 1 0 R
+>>
+{{startxref}}
+%%EOF
diff --git a/testing/resources/bug_634716.pdf b/testing/resources/bug_634716.pdf
new file mode 100644
index 0000000000..6330b9a4e5
--- /dev/null
+++ b/testing/resources/bug_634716.pdf
@@ -0,0 +1,180 @@
+%PDF-1.7
+% ò¤ô
+1 0 obj <<
+ /Type /Catalog
+ /Pages 2 0 R
+ /AcroForm 6 0 R
+ /Names <</JavaScript 13 0 R>>
+>>
+endobj
+2 0 obj <<
+ /Type /Pages
+ /Count 1
+ /Kids [4 0 R]
+>>
+endobj
+4 0 obj <<
+ /Type /Page
+ /Parent 2 0 R
+ /MediaBox [0 0 612 792]
+ /CropBox [0 0 612 792]
+ /Resources <<>>
+>>
+endobj
+6 0 obj <<
+ /DR <<
+ /Font <</Helv 7 0 R>>
+ >>
+ /DA (/Helv 0 Tf 0 g)
+ /Fields [5 0 R]
+>>
+endobj
+7 0 obj <<
+ /Type /Font
+ /Subtype /Type1
+ /BaseFont /Helvetica
+ /Encoding /WinAnsiEncoding
+>>
+endobj
+8 0 obj <<
+ /Type /XObject
+ /Subtype /Form
+ /FormType 1
+ /Matrix [1 0 0 1 0 0]
+ /BBox [0 0 75.907 28.472]
+ /Resources <<
+ /Font <</FXF0 7 0 R>>
+ >>
+>>
+stream
+q
+Q
+
+
+endstream
+endobj
+11 0 obj <<
+ /Type /Action
+ /S /JavaScript
+ /JS 50 0 R
+>>
+endobj
+13 0 obj <<
+ /Names [(startDelay) 11 0 R]
+>>
+endobj
+50 0 obj <<
+>>
+stream
+var timeOut = 0;
+var array = new Array(1024*4);
+var doc = this;
+
+function myFunction() {
+ try {
+ // Free the Timer Objects
+ app.clearTimeOut(timeOut);
+ for (var i=0; i<array.length; i++) {
+ for (var j=0; j<array[i].length; j++) {
+ app.clearTimeOut(array[i][j]);
+ }
+ }
+
+ // Trigger the Garbage Collection
+ array.length = 0;
+ array.push(new ArrayBuffer(1024*1024));
+ array.length=0;
+ array.length=1024*4;
+ var str = 'AA';
+ for (var i = 0; i < array.length ; i++) {
+ for (var j = 0; j < 10; j++ ) {
+ doc.addIcon(str + "-" + str + str + str + str + str, doc.icons);
+ }
+ }
+ } catch(err) {
+ app.alert(err);
+ }
+}
+
+function main() {
+ try {
+ for (var i = 0; i < array.length ; i++) {
+ if (i == array.length / 2) {
+ timeOut = app.setTimeOut("myFunction()", 1000);
+ }
+ array[i] = new Array(4);
+ for (var j = 0; j < array[i].length ; j++ ) {
+ array[i][j] = app.setTimeOut("aaaaaaaaaa()", 100000);
+ }
+ }
+ } catch(err) {
+ app.alert(err);
+ }
+}
+
+// Execute the JS.
+app.setTimeOut("main()", 1000);
+
+// Be sure all of this code ran to completion.
+app.alert("done");
+endstream
+endobj
+xref
+0 51
+0000000000 65535 f
+0000000015 00000 n
+0000000118 00000 n
+0000000000 65535 f
+0000000181 00000 n
+0000000000 65535 f
+0000000302 00000 n
+0000000404 00000 n
+0000000509 00000 n
+0000000000 65535 f
+0000000000 65535 f
+0000000701 00000 n
+0000000000 65535 f
+0000000769 00000 n
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000000 65535 f
+0000000822 00000 n
+trailer <<
+ /Root 1 0 R
+>>
+startxref
+2036
+%%EOF
diff --git a/third_party/libopenjpeg20/0021-tcd_init_tile_negative.patch b/third_party/libopenjpeg20/0021-tcd_init_tile_negative.patch
new file mode 100644
index 0000000000..33694f81fc
--- /dev/null
+++ b/third_party/libopenjpeg20/0021-tcd_init_tile_negative.patch
@@ -0,0 +1,21 @@
+diff --git a/third_party/libopenjpeg20/tcd.c b/third_party/libopenjpeg20/tcd.c
+index 9270efe..06eee4e 100644
+--- a/third_party/libopenjpeg20/tcd.c
++++ b/third_party/libopenjpeg20/tcd.c
+@@ -706,9 +706,16 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no,
+ l_tx0 = l_cp->tx0 + p * l_cp->tdx; /* can't be greater than l_image->x1 so won't overflow */
+ l_tile->x0 = (OPJ_INT32)opj_uint_max(l_tx0, l_image->x0);
+ l_tile->x1 = (OPJ_INT32)opj_uint_min(opj_uint_adds(l_tx0, l_cp->tdx), l_image->x1);
++ if (l_tile->x0 < 0 || l_tile->x1 < 0) {
++ return OPJ_FALSE;
++ }
++
+ l_ty0 = l_cp->ty0 + q * l_cp->tdy; /* can't be greater than l_image->y1 so won't overflow */
+ l_tile->y0 = (OPJ_INT32)opj_uint_max(l_ty0, l_image->y0);
+ l_tile->y1 = (OPJ_INT32)opj_uint_min(opj_uint_adds(l_ty0, l_cp->tdy), l_image->y1);
++ if (l_tile->y0 < 0 || l_tile->y1 < 0) {
++ return OPJ_FALSE;
++ }
+
+ /* testcase 1888.pdf.asan.35.988 */
+ if (l_tccp->numresolutions == 0) {
diff --git a/third_party/libopenjpeg20/README.pdfium b/third_party/libopenjpeg20/README.pdfium
index a40ed7ba3f..7779044799 100644
--- a/third_party/libopenjpeg20/README.pdfium
+++ b/third_party/libopenjpeg20/README.pdfium
@@ -30,4 +30,5 @@ Local Modifications:
0018-tcd_get_decoded_tile_size.patch: Fix an integer overflow in opj_tcd_get_decoded_tile_size.
0019-tcd_init_tile.patch: Prevent integer overflows during calculation of |l_nb_code_blocks_size|.
0020-opj_aligned_malloc.patch: Prevent overflows when using opj_aligned_malloc().
+0021-tcd_init_tile_negative.patch: Prevent negative x, y values in opj_tcd_init_tile.
TODO(thestig): List all the other patches.
diff --git a/third_party/libopenjpeg20/tcd.c b/third_party/libopenjpeg20/tcd.c
index 9270efe399..06eee4ebd5 100644
--- a/third_party/libopenjpeg20/tcd.c
+++ b/third_party/libopenjpeg20/tcd.c
@@ -706,9 +706,16 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no,
l_tx0 = l_cp->tx0 + p * l_cp->tdx; /* can't be greater than l_image->x1 so won't overflow */
l_tile->x0 = (OPJ_INT32)opj_uint_max(l_tx0, l_image->x0);
l_tile->x1 = (OPJ_INT32)opj_uint_min(opj_uint_adds(l_tx0, l_cp->tdx), l_image->x1);
+ if (l_tile->x0 < 0 || l_tile->x1 < 0) {
+ return OPJ_FALSE;
+ }
+
l_ty0 = l_cp->ty0 + q * l_cp->tdy; /* can't be greater than l_image->y1 so won't overflow */
l_tile->y0 = (OPJ_INT32)opj_uint_max(l_ty0, l_image->y0);
l_tile->y1 = (OPJ_INT32)opj_uint_min(opj_uint_adds(l_ty0, l_cp->tdy), l_image->y1);
+ if (l_tile->y0 < 0 || l_tile->y1 < 0) {
+ return OPJ_FALSE;
+ }
/* testcase 1888.pdf.asan.35.988 */
if (l_tccp->numresolutions == 0) {