diff options
-rw-r--r-- | BUILD.gn | 1 | ||||
-rw-r--r-- | core/include/fpdfapi/fpdf_parser.h | 15 | ||||
-rw-r--r-- | core/include/fxcrt/fx_system.h | 1 | ||||
-rw-r--r-- | core/src/fpdfapi/fpdf_parser/fpdf_parser_decode_embeddertest.cpp | 9 | ||||
-rw-r--r-- | core/src/fpdfapi/fpdf_parser/fpdf_parser_fdf.cpp | 2 | ||||
-rw-r--r-- | core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp | 36 | ||||
-rw-r--r-- | core/src/fxcrt/fx_basic_gcc.cpp | 25 | ||||
-rw-r--r-- | core/src/fxcrt/fx_basic_gcc_unittest.cpp | 88 | ||||
-rw-r--r-- | pdfium.gyp | 1 | ||||
-rw-r--r-- | testing/resources/bug_455199.pdf | 73 |
10 files changed, 209 insertions, 42 deletions
@@ -1435,6 +1435,7 @@ test("pdfium_unittests") { "core/src/fpdftext/fpdf_text_int_unittest.cpp", "core/src/fxcodec/codec/fx_codec_jpx_unittest.cpp", "core/src/fxcrt/fx_basic_bstring_unittest.cpp", + "core/src/fxcrt/fx_basic_gcc_unittest.cpp", "core/src/fxcrt/fx_basic_memmgr_unittest.cpp", "core/src/fxcrt/fx_basic_wstring_unittest.cpp", "core/src/fxcrt/fx_bidi_unittest.cpp", diff --git a/core/include/fpdfapi/fpdf_parser.h b/core/include/fpdfapi/fpdf_parser.h index c57d9f20b9..5903e82a16 100644 --- a/core/include/fpdfapi/fpdf_parser.h +++ b/core/include/fpdfapi/fpdf_parser.h @@ -239,43 +239,33 @@ class CPDF_SyntaxParser { void InitParser(IFX_FileRead* pFileAccess, FX_DWORD HeaderOffset); FX_FILESIZE SavePos() const { return m_Pos; } - void RestorePos(FX_FILESIZE pos) { m_Pos = pos; } CPDF_Object* GetObject(CPDF_IndirectObjectHolder* pObjList, FX_DWORD objnum, FX_DWORD gennum, FX_BOOL bDecrypt); - CPDF_Object* GetObjectByStrict(CPDF_IndirectObjectHolder* pObjList, FX_DWORD objnum, FX_DWORD gennum); - - int GetDirectNum(); - CFX_ByteString GetKeyword(); void ToNextLine(); - void ToNextWord(); FX_BOOL SearchWord(const CFX_ByteStringC& word, FX_BOOL bWholeWord, FX_BOOL bForward, FX_FILESIZE limit); - int SearchMultiWord(const CFX_ByteStringC& words, FX_BOOL bWholeWord, FX_FILESIZE limit); - FX_FILESIZE FindTag(const CFX_ByteStringC& tag, FX_FILESIZE limit); void SetEncrypt(std::unique_ptr<CPDF_CryptoHandler> pCryptoHandler); - FX_BOOL GetCharAt(FX_FILESIZE pos, uint8_t& ch); - FX_BOOL ReadBlock(uint8_t* pBuf, FX_DWORD size); - + FX_BOOL GetCharAt(FX_FILESIZE pos, uint8_t& ch); CFX_ByteString GetNextWord(bool* bIsNumber); protected: @@ -318,6 +308,9 @@ class CPDF_SyntaxParser { std::unique_ptr<CPDF_CryptoHandler> m_pCryptoHandler; uint8_t m_WordBuffer[257]; FX_DWORD m_WordSize; + + private: + uint32_t GetDirectNum(); }; class CPDF_Parser { diff --git a/core/include/fxcrt/fx_system.h b/core/include/fxcrt/fx_system.h index e28099ed4a..462fb3babf 100644 --- a/core/include/fxcrt/fx_system.h +++ b/core/include/fxcrt/fx_system.h @@ -264,6 +264,7 @@ wchar_t* FXSYS_wcsupr(wchar_t* str); #define FXSYS_HIWORD(dword) ((FX_WORD)((dword) >> 16)) #define FXSYS_LOWORD(dword) ((FX_WORD)(dword)) int32_t FXSYS_atoi(const FX_CHAR* str); +uint32_t FXSYS_atoui(const FX_CHAR* str); int32_t FXSYS_wtoi(const FX_WCHAR* str); int64_t FXSYS_atoi64(const FX_CHAR* str); int64_t FXSYS_wtoi64(const FX_WCHAR* str); diff --git a/core/src/fpdfapi/fpdf_parser/fpdf_parser_decode_embeddertest.cpp b/core/src/fpdfapi/fpdf_parser/fpdf_parser_decode_embeddertest.cpp index 9bb9d41db1..7ed82fdfb6 100644 --- a/core/src/fpdfapi/fpdf_parser/fpdf_parser_decode_embeddertest.cpp +++ b/core/src/fpdfapi/fpdf_parser/fpdf_parser_decode_embeddertest.cpp @@ -105,3 +105,12 @@ TEST_F(FPDFParserDecodeEmbeddertest, Bug_555784) { UnloadPage(page); } +TEST_F(FPDFParserDecodeEmbeddertest, Bug_455199) { + // Tests object numbers with a value > 01000000. + // Should open successfully. + EXPECT_TRUE(OpenDocument("bug_455199.pdf")); + FPDF_PAGE page = LoadPage(0); + FPDF_BITMAP bitmap = RenderPage(page); + FPDFBitmap_Destroy(bitmap); + UnloadPage(page); +} diff --git a/core/src/fpdfapi/fpdf_parser/fpdf_parser_fdf.cpp b/core/src/fpdfapi/fpdf_parser/fpdf_parser_fdf.cpp index b80568b63c..fbe6a8fb3a 100644 --- a/core/src/fpdfapi/fpdf_parser/fpdf_parser_fdf.cpp +++ b/core/src/fpdfapi/fpdf_parser/fpdf_parser_fdf.cpp @@ -51,7 +51,7 @@ void CFDF_Document::ParseStream(IFX_FileRead* pFile, FX_BOOL bOwnFile) { bool bNumber; CFX_ByteString word = parser.GetNextWord(&bNumber); if (bNumber) { - FX_DWORD objnum = FXSYS_atoi(word); + FX_DWORD objnum = FXSYS_atoui(word); word = parser.GetNextWord(&bNumber); if (!bNumber) { break; diff --git a/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp b/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp index 825a8a26d4..16d1134cb1 100644 --- a/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp +++ b/core/src/fpdfapi/fpdf_parser/fpdf_parser_parser.cpp @@ -534,7 +534,7 @@ bool CPDF_Parser::LoadCrossRefV4(FX_FILESIZE pos, break; } - FX_DWORD start_objnum = FXSYS_atoi(word); + FX_DWORD start_objnum = FXSYS_atoui(word); if (start_objnum >= kMaxObjectNumber) return false; @@ -758,10 +758,6 @@ FX_BOOL CPDF_Parser::RebuildCrossRef() { break; case 3: if (PDFCharIsWhitespace(byte) || PDFCharIsDelimiter(byte)) { - if (objnum > 0x1000000) { - state = ParserState::kDefault; - break; - } FX_FILESIZE obj_pos = start_pos - m_Syntax.m_HeaderOffset; m_SortedOffset.insert(obj_pos); last_obj = start_pos; @@ -1323,7 +1319,7 @@ void CPDF_Parser::GetIndirectBinary(FX_DWORD objnum, return; } - FX_DWORD parser_objnum = FXSYS_atoi(word); + FX_DWORD parser_objnum = FXSYS_atoui(word); if (parser_objnum && parser_objnum != objnum) { m_Syntax.RestorePos(SavedPos); return; @@ -1395,7 +1391,7 @@ CPDF_Object* CPDF_Parser::ParseIndirectObjectAt( FX_FILESIZE objOffset = m_Syntax.SavePos(); objOffset -= word.GetLength(); - FX_DWORD parser_objnum = FXSYS_atoi(word); + FX_DWORD parser_objnum = FXSYS_atoui(word); if (objnum && parser_objnum != objnum) { m_Syntax.RestorePos(SavedPos); return nullptr; @@ -1407,7 +1403,7 @@ CPDF_Object* CPDF_Parser::ParseIndirectObjectAt( return nullptr; } - FX_DWORD parser_gennum = FXSYS_atoi(word); + FX_DWORD parser_gennum = FXSYS_atoui(word); if (m_Syntax.GetKeyword() != "obj") { m_Syntax.RestorePos(SavedPos); return nullptr; @@ -1444,7 +1440,7 @@ CPDF_Object* CPDF_Parser::ParseIndirectObjectAtByStrict( return nullptr; } - FX_DWORD parser_objnum = FXSYS_atoi(word); + FX_DWORD parser_objnum = FXSYS_atoui(word); if (objnum && parser_objnum != objnum) { m_Syntax.RestorePos(SavedPos); return nullptr; @@ -1456,7 +1452,7 @@ CPDF_Object* CPDF_Parser::ParseIndirectObjectAtByStrict( return nullptr; } - FX_DWORD gennum = FXSYS_atoi(word); + FX_DWORD gennum = FXSYS_atoui(word); if (m_Syntax.GetKeyword() != "obj") { m_Syntax.RestorePos(SavedPos); return nullptr; @@ -1506,12 +1502,12 @@ FX_BOOL CPDF_Parser::IsLinearizedFile(IFX_FileRead* pFileAccess, if (!bIsNumber) return FALSE; - FX_DWORD objnum = FXSYS_atoi(word); + FX_DWORD objnum = FXSYS_atoui(word); word = m_Syntax.GetNextWord(&bIsNumber); if (!bIsNumber) return FALSE; - FX_DWORD gennum = FXSYS_atoi(word); + FX_DWORD gennum = FXSYS_atoui(word); if (m_Syntax.GetKeyword() != "obj") { m_Syntax.RestorePos(SavedPos); return FALSE; @@ -2039,7 +2035,7 @@ CPDF_Object* CPDF_SyntaxParser::GetObject(CPDF_IndirectObjectHolder* pObjList, if (bIsNumber) { CFX_ByteString nextword2 = GetNextWord(nullptr); if (nextword2 == "R") { - FX_DWORD objnum = FXSYS_atoi(word); + FX_DWORD objnum = FXSYS_atoui(word); return new CPDF_Reference(pObjList, objnum); } } @@ -2163,7 +2159,7 @@ CPDF_Object* CPDF_SyntaxParser::GetObjectByStrict( if (bIsNumber) { CFX_ByteString nextword2 = GetNextWord(nullptr); if (nextword2 == "R") - return new CPDF_Reference(pObjList, FXSYS_atoi(word)); + return new CPDF_Reference(pObjList, FXSYS_atoui(word)); } m_Pos = SavedPos; return new CPDF_Number(word); @@ -2440,14 +2436,14 @@ void CPDF_SyntaxParser::InitParser(IFX_FileRead* pFileAccess, (size_t)((FX_FILESIZE)m_BufSize > m_FileLen ? m_FileLen : m_BufSize)); } -int32_t CPDF_SyntaxParser::GetDirectNum() { +uint32_t CPDF_SyntaxParser::GetDirectNum() { bool bIsNumber; GetNextWordInternal(&bIsNumber); if (!bIsNumber) return 0; m_WordBuffer[m_WordSize] = 0; - return FXSYS_atoi(reinterpret_cast<const FX_CHAR*>(m_WordBuffer)); + return FXSYS_atoui(reinterpret_cast<const FX_CHAR*>(m_WordBuffer)); } bool CPDF_SyntaxParser::IsWholeWord(FX_FILESIZE startpos, @@ -3554,7 +3550,7 @@ CPDF_Object* CPDF_DataAvail::ParseIndirectObjectAt( if (!bIsNumber) return nullptr; - FX_DWORD parser_objnum = FXSYS_atoi(word); + FX_DWORD parser_objnum = FXSYS_atoui(word); if (objnum && parser_objnum != objnum) return nullptr; @@ -3562,7 +3558,7 @@ CPDF_Object* CPDF_DataAvail::ParseIndirectObjectAt( if (!bIsNumber) return nullptr; - FX_DWORD gennum = FXSYS_atoi(word); + FX_DWORD gennum = FXSYS_atoui(word); if (m_syntaxParser.GetKeyword() != "obj") { m_syntaxParser.RestorePos(SavedPos); return nullptr; @@ -3611,7 +3607,7 @@ FX_BOOL CPDF_DataAvail::IsLinearizedFile(uint8_t* pData, FX_DWORD dwLen) { if (!bNumber) return FALSE; - FX_DWORD objnum = FXSYS_atoi(wordObjNum); + FX_DWORD objnum = FXSYS_atoui(wordObjNum); if (m_pLinearized) { m_pLinearized->Release(); m_pLinearized = nullptr; @@ -3704,7 +3700,7 @@ int32_t CPDF_DataAvail::CheckCrossRefStream(IFX_DownloadHints* pHints, if (!bNumber) return -1; - FX_DWORD objNum = FXSYS_atoi(objnum); + FX_DWORD objNum = FXSYS_atoui(objnum); CPDF_Object* pObj = m_parser.ParseIndirectObjectAt(nullptr, 0, objNum); if (!pObj) { m_Pos += m_parser.m_Syntax.SavePos(); diff --git a/core/src/fxcrt/fx_basic_gcc.cpp b/core/src/fxcrt/fx_basic_gcc.cpp index d905d6b498..607f095570 100644 --- a/core/src/fxcrt/fx_basic_gcc.cpp +++ b/core/src/fxcrt/fx_basic_gcc.cpp @@ -13,20 +13,21 @@ template <class T> T FXSYS_StrToInt(const FX_CHAR* str) { - FX_BOOL neg = FALSE; + bool neg = false; if (!str) return 0; - if (*str == '-') { - neg = TRUE; + if (std::numeric_limits<T>::is_signed && *str == '-') { + neg = true; str++; } T num = 0; while (*str && std::isdigit(*str)) { - if (num > (std::numeric_limits<T>::max() - 9) / 10) + T val = FXSYS_toDecimalDigit(*str); + if (num > (std::numeric_limits<T>::max() - val) / 10) break; - num = num * 10 + FXSYS_toDecimalDigit(*str); + num = num * 10 + val; str++; } return neg ? -num : num; @@ -34,20 +35,21 @@ T FXSYS_StrToInt(const FX_CHAR* str) { template <class T> T FXSYS_StrToInt(const FX_WCHAR* str) { - FX_BOOL neg = FALSE; + bool neg = false; if (!str) return 0; - if (*str == '-') { - neg = TRUE; + if (std::numeric_limits<T>::is_signed && *str == '-') { + neg = true; str++; } T num = 0; while (*str && std::iswdigit(*str)) { - if (num > (std::numeric_limits<T>::max() - 9) / 10) + T val = FXSYS_toDecimalDigitWide(*str); + if (num > (std::numeric_limits<T>::max() - val) / 10) break; - num = num * 10 + FXSYS_toDecimalDigitWide(*str); + num = num * 10 + val; str++; } return neg ? -num : num; @@ -93,6 +95,9 @@ extern "C" { int32_t FXSYS_atoi(const FX_CHAR* str) { return FXSYS_StrToInt<int32_t>(str); } +uint32_t FXSYS_atoui(const FX_CHAR* str) { + return FXSYS_StrToInt<uint32_t>(str); +} int32_t FXSYS_wtoi(const FX_WCHAR* str) { return FXSYS_StrToInt<int32_t>(str); } diff --git a/core/src/fxcrt/fx_basic_gcc_unittest.cpp b/core/src/fxcrt/fx_basic_gcc_unittest.cpp new file mode 100644 index 0000000000..eb1e0669ae --- /dev/null +++ b/core/src/fxcrt/fx_basic_gcc_unittest.cpp @@ -0,0 +1,88 @@ +// Copyright 2016 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/include/fxcrt/fx_system.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(fxcrt, FXSYS_atoi) { + EXPECT_EQ(0, FXSYS_atoi("")); + EXPECT_EQ(0, FXSYS_atoi("0")); + EXPECT_EQ(-1, FXSYS_atoi("-1")); + EXPECT_EQ(2345, FXSYS_atoi("2345")); + EXPECT_EQ(2147483647, FXSYS_atoi("2147483647")); + EXPECT_EQ(-2147483647, FXSYS_atoi("-2147483647")); + EXPECT_EQ(9, FXSYS_atoi("9x9")); + + // TODO(dsinclair): These are all wacky ..... + EXPECT_EQ(2147483623, FXSYS_atoi("2147483623423412348")); + EXPECT_EQ(214748364, FXSYS_atoi("2147483648")); + // The digit is parsed as a positive value, so we end up not being able to + // handle the largest possible negative value. + EXPECT_EQ(-214748364, FXSYS_atoi("-2147483648")); +} + +TEST(fxcrt, FXSYS_atoi64) { + EXPECT_EQ(0, FXSYS_atoi64("")); + EXPECT_EQ(0, FXSYS_atoi64("0")); + EXPECT_EQ(-1, FXSYS_atoi64("-1")); + EXPECT_EQ(2345, FXSYS_atoi64("2345")); + EXPECT_EQ(9223372036854775807LL, FXSYS_atoi64("9223372036854775807")); + EXPECT_EQ(-9223372036854775807LL, FXSYS_atoi64("-9223372036854775807")); + EXPECT_EQ(9, FXSYS_atoi64("9x9")); + + // TODO(dsinclair): These are all wacky ..... + EXPECT_EQ(9223372036854712341LL, FXSYS_atoi64("922337203685471234123475807")); + EXPECT_EQ(922337203685477580LL, FXSYS_atoi64("9223372036854775808")); + // The digit is parsed as a positive value, so we end up not being able to + // handle the largest possible negative value. + EXPECT_EQ(-922337203685477580LL, FXSYS_atoi64("-9223372036854775808")); +} + +TEST(fxcrt, FXSYS_wtoi) { + EXPECT_EQ(0, FXSYS_wtoi(L"")); + EXPECT_EQ(0, FXSYS_wtoi(L"0")); + EXPECT_EQ(-1, FXSYS_wtoi(L"-1")); + EXPECT_EQ(2345, FXSYS_wtoi(L"2345")); + EXPECT_EQ(2147483647, FXSYS_wtoi(L"2147483647")); + EXPECT_EQ(-2147483647, FXSYS_wtoi(L"-2147483647")); + EXPECT_EQ(9, FXSYS_wtoi64(L"9x9")); + + // TODO(dsinclair): These are all wacky ..... + EXPECT_EQ(2147483623, FXSYS_wtoi(L"2147483623423412348")); + EXPECT_EQ(214748364, FXSYS_wtoi(L"2147483648")); + // The digit is parsed as a positive value, so we end up not being able to + // handle the largest possible negative value. + EXPECT_EQ(-214748364, FXSYS_wtoi(L"-2147483648")); +} + +TEST(fxcrt, FXSYS_wtoi64) { + EXPECT_EQ(0, FXSYS_wtoi64(L"")); + EXPECT_EQ(0, FXSYS_wtoi64(L"0")); + EXPECT_EQ(-1, FXSYS_wtoi64(L"-1")); + EXPECT_EQ(2345, FXSYS_wtoi64(L"2345")); + EXPECT_EQ(9223372036854775807LL, FXSYS_wtoi64(L"9223372036854775807")); + EXPECT_EQ(-9223372036854775807LL, FXSYS_wtoi64(L"-9223372036854775807")); + EXPECT_EQ(9, FXSYS_wtoi64(L"9x9")); + + // TODO(dsinclair): These are all wacky ..... + EXPECT_EQ(9223372036854712341LL, + FXSYS_wtoi64(L"922337203685471234123475807")); + EXPECT_EQ(922337203685477580LL, FXSYS_wtoi64(L"9223372036854775808")); + // The digit is parsed as a positive value, so we end up not being able to + // handle the largest possible negative value. + EXPECT_EQ(-922337203685477580LL, FXSYS_wtoi64(L"-9223372036854775808")); +} + +TEST(fxcrt, FXSYS_atoui) { + EXPECT_EQ(0, FXSYS_atoui("")); + EXPECT_EQ(0, FXSYS_atoui("0")); + EXPECT_EQ(0, FXSYS_atoui("-1")); + EXPECT_EQ(2345, FXSYS_atoui("2345")); + EXPECT_EQ(4294967295, FXSYS_atoui("4294967295")); + EXPECT_EQ(9, FXSYS_atoui("9x9")); + + // TODO(dsinclair): These are all wacky ..... + EXPECT_EQ(2147483623, FXSYS_atoi("2147483623423412348")); + EXPECT_EQ(429496729, FXSYS_atoi("4294967296")); +} diff --git a/pdfium.gyp b/pdfium.gyp index 14d18e1499..08d3f085f0 100644 --- a/pdfium.gyp +++ b/pdfium.gyp @@ -757,6 +757,7 @@ 'core/src/fpdftext/fpdf_text_int_unittest.cpp', 'core/src/fxcodec/codec/fx_codec_jpx_unittest.cpp', 'core/src/fxcrt/fx_basic_bstring_unittest.cpp', + 'core/src/fxcrt/fx_basic_gcc_unittest.cpp', 'core/src/fxcrt/fx_basic_memmgr_unittest.cpp', 'core/src/fxcrt/fx_basic_wstring_unittest.cpp', 'core/src/fxcrt/fx_bidi_unittest.cpp', diff --git a/testing/resources/bug_455199.pdf b/testing/resources/bug_455199.pdf new file mode 100644 index 0000000000..466affa4d1 --- /dev/null +++ b/testing/resources/bug_455199.pdf @@ -0,0 +1,73 @@ +%PDF-1.7 +% ò¤ô +1 0 obj << + /Type /Catalog + /Pages 2 0 R +>> +2 0 obj << + /Type /Pages + /MediaBox [ 0 0 200 200 ] + /Count 1 + /Kids [ 3 0 R ] +>> +endobj +3 0 obj << + /Type /Page + /Parent 2 0 R + /Resources << + /Font << + /F1 4 0 R + /F2 5 0 R + >> + >> + /Contents [6 0 R 7 0 R] +>> +endobj +4 0 obj << + /Type /Font + /Subtype /Type1 + /BaseFont /Times-Roman +>> +endobj +2147483648 0 obj +<</Length 163/Filter/FlateDecode>>stream +x<9c><85><8e>± +Â0^@^E÷|Å<9b>DAc<82>iSÝ,ZpP(fpU^ZKÔ64|Füzãè$·^^Ü¡&C¢T<84><83>%8¸^T<94>|_äBÒ,<83>êÈüd<84>^@^WPׯD3Æ<97>yR]KÆ^[^[û<87>=7ºAål·B<8c><91>^¼|_ôý^Zh¯ÃDÝ^HCK¶<8a>Ô¿^]Yм<80>d<94>-þU*ë°·N£<Îv +¥µw?ÅÁ^Fí1ÂÚ{Óö<9d>î<83>ÇÓ¤ö<9f><8b><9a>|^@ 9@Ø +endstream +endobj +5 0 obj << + /Type /Font + /Subtype /Type1 + /BaseFont /Helvetica +>> +endobj +6 0 obj << +>> +stream +BT +20 50 Td +/F1 12 Tf +(Hello, world!) Tj +0 50 Td +/F2 16 Tf +(Goodbye, world!) Tj +ET +endstream +endobj +xref +0 7 +0000000000 65535 f +0000000015 00000 n +0000000061 00000 n +0000000154 00000 n +0000000305 00000 n +0000000695 00000 n +0000000771 00000 n +trailer << + /Size 6 + /Root 1 0 R +>> +startxref +892 +%%EOF |