From 914ccb0478ee442d10e796596006cdf88688ed6b Mon Sep 17 00:00:00 2001 From: Lei Zhang Date: Tue, 13 Oct 2015 15:51:04 -0700 Subject: Merge to M47: Sanitize CJBig2_SymbolDict's memory usage. - Use std::vector instead of storing pointers to arrays. - Make CJBig2_SymbolDict's members private with accessors. - Use std::vector in related places. - Steal Chromium's vector_as_array() and use it as an adaptor as needed. BUG=514891 R=tsepez@chromium.org Review URL: https://codereview.chromium.org/1388203003 . (cherry picked from commit 3acb1ef909a22368507ed13817c4988c818e3aee) Review URL: https://codereview.chromium.org/1399243003 . --- core/src/fxcodec/jbig2/JBig2_Context.cpp | 189 ++++++++++++++-------------- core/src/fxcodec/jbig2/JBig2_SddProc.cpp | 27 ++-- core/src/fxcodec/jbig2/JBig2_SddProc.h | 15 +-- core/src/fxcodec/jbig2/JBig2_SymbolDict.cpp | 14 +-- core/src/fxcodec/jbig2/JBig2_SymbolDict.h | 19 ++- third_party/BUILD.gn | 1 + third_party/base/stl_util.h | 27 ++++ third_party/third_party.gyp | 3 +- 8 files changed, 167 insertions(+), 128 deletions(-) create mode 100644 third_party/base/stl_util.h diff --git a/core/src/fxcodec/jbig2/JBig2_Context.cpp b/core/src/fxcodec/jbig2/JBig2_Context.cpp index 4e21a8cca4..d0afbae341 100644 --- a/core/src/fxcodec/jbig2/JBig2_Context.cpp +++ b/core/src/fxcodec/jbig2/JBig2_Context.cpp @@ -16,6 +16,18 @@ #include "JBig2_SddProc.h" #include "JBig2_TrdProc.h" +namespace { + +size_t GetHuffContextSize(uint8_t val) { + return val == 0 ? 65536 : val == 1 ? 8192 : 1024; +} + +size_t GetRefAggContextSize(FX_BOOL val) { + return val ? 1024 : 8192; +} + +} // namespace + // Implement a very small least recently used (LRU) cache. It is very // common for a JBIG2 dictionary to span multiple pages in a PDF file, // and we do not want to decode the same dictionary over and over @@ -437,11 +449,7 @@ int32_t CJBig2_Context::parseSymbolDict(CJBig2_Segment* pSegment, int32_t i, nIndex, nRet; CJBig2_Segment* pSeg = nullptr; CJBig2_Segment* pLRSeg = nullptr; - FX_BOOL bUsed; CJBig2_Image** SDINSYMS = nullptr; - JBig2ArithCtx* gbContext = nullptr; - JBig2ArithCtx* grContext = nullptr; - CJBig2_ArithDecoder* pArithDecoder; CJBig2_SDDProc* pSymbolDictDecoder = new CJBig2_SDDProc(); const uint8_t* key = pSegment->m_pData; FX_BOOL cache_hit = false; @@ -592,90 +600,93 @@ int32_t CJBig2_Context::parseSymbolDict(CJBig2_Segment* pSegment, } } } - if ((wFlags & 0x0100) && pLRSeg && pLRSeg->m_Result.sd->m_bContextRetained) { - if (pSymbolDictDecoder->SDHUFF == 0) { - dwTemp = pSymbolDictDecoder->SDTEMPLATE == 0 - ? 65536 - : pSymbolDictDecoder->SDTEMPLATE == 1 ? 8192 : 1024; - gbContext = FX_Alloc(JBig2ArithCtx, dwTemp); - JBIG2_memcpy(gbContext, pLRSeg->m_Result.sd->m_gbContext, - sizeof(JBig2ArithCtx) * dwTemp); - } - if (pSymbolDictDecoder->SDREFAGG == 1) { - dwTemp = pSymbolDictDecoder->SDRTEMPLATE ? 1 << 10 : 1 << 13; - grContext = FX_Alloc(JBig2ArithCtx, dwTemp); - JBIG2_memcpy(grContext, pLRSeg->m_Result.sd->m_grContext, - sizeof(JBig2ArithCtx) * dwTemp); - } - } else { - if (pSymbolDictDecoder->SDHUFF == 0) { - dwTemp = pSymbolDictDecoder->SDTEMPLATE == 0 - ? 65536 - : pSymbolDictDecoder->SDTEMPLATE == 1 ? 8192 : 1024; - gbContext = FX_Alloc(JBig2ArithCtx, dwTemp); - JBIG2_memset(gbContext, 0, sizeof(JBig2ArithCtx) * dwTemp); - } - if (pSymbolDictDecoder->SDREFAGG == 1) { - dwTemp = pSymbolDictDecoder->SDRTEMPLATE ? 1 << 10 : 1 << 13; - grContext = FX_Alloc(JBig2ArithCtx, dwTemp); - JBIG2_memset(grContext, 0, sizeof(JBig2ArithCtx) * dwTemp); - } - } - pSegment->m_nResultType = JBIG2_SYMBOL_DICT_POINTER; - for (std::list::iterator it = m_pSymbolDictCache->begin(); - it != m_pSymbolDictCache->end(); ++it) { - if (it->first == key) { - nonstd::unique_ptr copy(it->second->DeepCopy()); - pSegment->m_Result.sd = copy.release(); - m_pSymbolDictCache->push_front(*it); - m_pSymbolDictCache->erase(it); - cache_hit = true; - break; - } - } - if (!cache_hit) { - if (pSymbolDictDecoder->SDHUFF == 0) { - pArithDecoder = new CJBig2_ArithDecoder(m_pStream.get()); - pSegment->m_Result.sd = - pSymbolDictDecoder->decode_Arith(pArithDecoder, gbContext, grContext); - delete pArithDecoder; - if (pSegment->m_Result.sd == NULL) { - nRet = JBIG2_ERROR_FATAL; - goto failed; + + // The code below is in its own block to avoid issues with gotos jumping over + // variable declarations. The master branch does not have this issue since the + // gotos have been removed. + { + const bool bUseGbContext = (pSymbolDictDecoder->SDHUFF == 0); + const bool bUseGrContext = (pSymbolDictDecoder->SDREFAGG == 1); + const size_t gbContextSize = + GetHuffContextSize(pSymbolDictDecoder->SDTEMPLATE); + const size_t grContextSize = + GetRefAggContextSize(pSymbolDictDecoder->SDRTEMPLATE); + std::vector gbContext; + std::vector grContext; + if ((wFlags & 0x0100) && pLRSeg) { + if (bUseGbContext) { + gbContext = pLRSeg->m_Result.sd->GbContext(); + if (gbContext.size() != gbContextSize) { + nRet = JBIG2_ERROR_FATAL; + goto failed; + } } - m_pStream->alignByte(); - m_pStream->offset(2); - } else { - pSegment->m_Result.sd = pSymbolDictDecoder->decode_Huffman( - m_pStream.get(), gbContext, grContext, pPause); - if (pSegment->m_Result.sd == NULL) { - nRet = JBIG2_ERROR_FATAL; - goto failed; + if (bUseGrContext) { + grContext = pLRSeg->m_Result.sd->GrContext(); + if (grContext.size() != grContextSize) { + nRet = JBIG2_ERROR_FATAL; + goto failed; + } } - m_pStream->alignByte(); + } else { + if (bUseGbContext) + gbContext.resize(gbContextSize); + if (bUseGrContext) + grContext.resize(grContextSize); } - nonstd::unique_ptr value = - pSegment->m_Result.sd->DeepCopy(); - if (value && kSymbolDictCacheMaxSize > 0) { - while (m_pSymbolDictCache->size() >= kSymbolDictCacheMaxSize) { - delete m_pSymbolDictCache->back().second; - m_pSymbolDictCache->pop_back(); + + pSegment->m_nResultType = JBIG2_SYMBOL_DICT_POINTER; + for (std::list::iterator it = m_pSymbolDictCache->begin(); + it != m_pSymbolDictCache->end(); ++it) { + if (it->first == key) { + nonstd::unique_ptr copy(it->second->DeepCopy()); + pSegment->m_Result.sd = copy.release(); + m_pSymbolDictCache->push_front(*it); + m_pSymbolDictCache->erase(it); + cache_hit = true; + break; } - m_pSymbolDictCache->push_front(CJBig2_CachePair(key, value.release())); } - } - if (wFlags & 0x0200) { - pSegment->m_Result.sd->m_bContextRetained = TRUE; - if (pSymbolDictDecoder->SDHUFF == 0) { - pSegment->m_Result.sd->m_gbContext = gbContext; + if (!cache_hit) { + if (bUseGbContext) { + nonstd::unique_ptr pArithDecoder( + new CJBig2_ArithDecoder(m_pStream.get())); + pSegment->m_Result.sd = pSymbolDictDecoder->decode_Arith( + pArithDecoder.get(), &gbContext, &grContext); + if (!pSegment->m_Result.sd) { + nRet = JBIG2_ERROR_FATAL; + goto failed; + } + + m_pStream->alignByte(); + m_pStream->offset(2); + } else { + pSegment->m_Result.sd = pSymbolDictDecoder->decode_Huffman( + m_pStream.get(), &gbContext, &grContext, pPause); + if (!pSegment->m_Result.sd) { + nRet = JBIG2_ERROR_FATAL; + goto failed; + } + m_pStream->alignByte(); + } + nonstd::unique_ptr value = + pSegment->m_Result.sd->DeepCopy(); + if (value && kSymbolDictCacheMaxSize > 0) { + while (m_pSymbolDictCache->size() >= kSymbolDictCacheMaxSize) { + delete m_pSymbolDictCache->back().second; + m_pSymbolDictCache->pop_back(); + } + m_pSymbolDictCache->push_front(CJBig2_CachePair(key, value.release())); + } } - if (pSymbolDictDecoder->SDREFAGG == 1) { - pSegment->m_Result.sd->m_grContext = grContext; + if (wFlags & 0x0200) { + if (bUseGbContext) + pSegment->m_Result.sd->SetGbContext(gbContext); + if (bUseGrContext) + pSegment->m_Result.sd->SetGrContext(grContext); } - bUsed = TRUE; - } else { - bUsed = FALSE; } + delete pSymbolDictDecoder; FX_Free(SDINSYMS); delete Table_B1; @@ -683,10 +694,6 @@ int32_t CJBig2_Context::parseSymbolDict(CJBig2_Segment* pSegment, delete Table_B3; delete Table_B4; delete Table_B5; - if (bUsed == FALSE) { - FX_Free(gbContext); - FX_Free(grContext); - } return JBIG2_SUCCESS; failed: delete pSymbolDictDecoder; @@ -696,8 +703,6 @@ failed: delete Table_B3; delete Table_B4; delete Table_B5; - FX_Free(gbContext); - FX_Free(grContext); return nRet; } @@ -985,7 +990,7 @@ int32_t CJBig2_Context::parseTextRegion(CJBig2_Segment* pSegment) { } } if (pTRD->SBREFINE == 1) { - dwTemp = pTRD->SBRTEMPLATE ? 1 << 10 : 1 << 13; + dwTemp = GetRefAggContextSize(pTRD->SBRTEMPLATE); grContext = FX_Alloc(JBig2ArithCtx, dwTemp); JBIG2_memset(grContext, 0, sizeof(JBig2ArithCtx) * dwTemp); } @@ -1080,8 +1085,7 @@ int32_t CJBig2_Context::parsePatternDict(CJBig2_Segment* pSegment, pPDD->HDTEMPLATE = (cFlags >> 1) & 0x03; pSegment->m_nResultType = JBIG2_PATTERN_DICT_POINTER; if (pPDD->HDMMR == 0) { - dwTemp = - pPDD->HDTEMPLATE == 0 ? 65536 : pPDD->HDTEMPLATE == 1 ? 8192 : 1024; + dwTemp = GetHuffContextSize(pPDD->HDTEMPLATE); gbContext = FX_Alloc(JBig2ArithCtx, dwTemp); JBIG2_memset(gbContext, 0, sizeof(JBig2ArithCtx) * dwTemp); pArithDecoder = new CJBig2_ArithDecoder(m_pStream.get()); @@ -1164,7 +1168,7 @@ int32_t CJBig2_Context::parseHalftoneRegion(CJBig2_Segment* pSegment, pHRD->HPH = pPatternDict->HDPATS[0]->m_nHeight; pSegment->m_nResultType = JBIG2_IMAGE_POINTER; if (pHRD->HMMR == 0) { - dwTemp = pHRD->HTEMPLATE == 0 ? 65536 : pHRD->HTEMPLATE == 1 ? 8192 : 1024; + dwTemp = GetHuffContextSize(pHRD->HTEMPLATE); gbContext = FX_Alloc(JBig2ArithCtx, dwTemp); JBIG2_memset(gbContext, 0, sizeof(JBig2ArithCtx) * dwTemp); pArithDecoder = new CJBig2_ArithDecoder(m_pStream.get()); @@ -1249,8 +1253,7 @@ int32_t CJBig2_Context::parseGenericRegion(CJBig2_Segment* pSegment, } pSegment->m_nResultType = JBIG2_IMAGE_POINTER; if (m_pGRD->MMR == 0) { - dwTemp = - m_pGRD->GBTEMPLATE == 0 ? 65536 : m_pGRD->GBTEMPLATE == 1 ? 8192 : 1024; + dwTemp = GetHuffContextSize(m_pGRD->GBTEMPLATE); if (m_gbContext == NULL) { m_gbContext = FX_Alloc(JBig2ArithCtx, dwTemp); JBIG2_memset(m_gbContext, 0, sizeof(JBig2ArithCtx) * dwTemp); @@ -1377,7 +1380,7 @@ int32_t CJBig2_Context::parseGenericRefinementRegion(CJBig2_Segment* pSegment) { } pGRRD->GRREFERENCEDX = 0; pGRRD->GRREFERENCEDY = 0; - dwTemp = pGRRD->GRTEMPLATE ? 1 << 10 : 1 << 13; + dwTemp = GetRefAggContextSize(pGRRD->GRTEMPLATE); grContext = FX_Alloc(JBig2ArithCtx, dwTemp); JBIG2_memset(grContext, 0, sizeof(JBig2ArithCtx) * dwTemp); pArithDecoder = new CJBig2_ArithDecoder(m_pStream.get()); diff --git a/core/src/fxcodec/jbig2/JBig2_SddProc.cpp b/core/src/fxcodec/jbig2/JBig2_SddProc.cpp index 1d0393a7e3..ab3b34f583 100644 --- a/core/src/fxcodec/jbig2/JBig2_SddProc.cpp +++ b/core/src/fxcodec/jbig2/JBig2_SddProc.cpp @@ -7,6 +7,7 @@ #include "JBig2_SddProc.h" #include "../../../../third_party/base/nonstd_unique_ptr.h" +#include "../../../../third_party/base/stl_util.h" #include "../../../include/fxcrt/fx_basic.h" #include "JBig2_ArithIntDecoder.h" #include "JBig2_GrdProc.h" @@ -16,10 +17,12 @@ #include "JBig2_SymbolDict.h" #include "JBig2_TrdProc.h" +using pdfium::vector_as_array; + CJBig2_SymbolDict* CJBig2_SDDProc::decode_Arith( CJBig2_ArithDecoder* pArithDecoder, - JBig2ArithCtx* gbContext, - JBig2ArithCtx* grContext) { + std::vector* gbContext, + std::vector* grContext) { CJBig2_Image** SDNEWSYMS; FX_DWORD HCHEIGHT, NSYMSDECODED; int32_t HCDH; @@ -104,7 +107,7 @@ CJBig2_SymbolDict* CJBig2_SDDProc::decode_Arith( pGRD->GBAT[5] = SDAT[5]; pGRD->GBAT[6] = SDAT[6]; pGRD->GBAT[7] = SDAT[7]; - BS = pGRD->decode_Arith(pArithDecoder, gbContext); + BS = pGRD->decode_Arith(pArithDecoder, vector_as_array(gbContext)); if (!BS) { goto failed; } @@ -192,7 +195,8 @@ CJBig2_SymbolDict* CJBig2_SDDProc::decode_Arith( ids.IARDX = IARDX.get(); ids.IARDY = IARDY.get(); ids.IAID = IAID.get(); - BS = pDecoder->decode_Arith(pArithDecoder, grContext, &ids); + BS = pDecoder->decode_Arith(pArithDecoder, vector_as_array(grContext), + &ids); if (!BS) { FX_Free(SBSYMS); goto failed; @@ -227,7 +231,7 @@ CJBig2_SymbolDict* CJBig2_SDDProc::decode_Arith( pGRRD->GRAT[1] = SDRAT[1]; pGRRD->GRAT[2] = SDRAT[2]; pGRRD->GRAT[3] = SDRAT[3]; - BS = pGRRD->decode(pArithDecoder, grContext); + BS = pGRRD->decode(pArithDecoder, vector_as_array(grContext)); if (!BS) { FX_Free(SBSYMS); goto failed; @@ -285,10 +289,11 @@ failed: return nullptr; } -CJBig2_SymbolDict* CJBig2_SDDProc::decode_Huffman(CJBig2_BitStream* pStream, - JBig2ArithCtx* gbContext, - JBig2ArithCtx* grContext, - IFX_Pause* pPause) { +CJBig2_SymbolDict* CJBig2_SDDProc::decode_Huffman( + CJBig2_BitStream* pStream, + std::vector* gbContext, + std::vector* grContext, + IFX_Pause* pPause) { CJBig2_Image** SDNEWSYMS; FX_DWORD* SDNEWSYMWIDTHS; FX_DWORD HCHEIGHT, NSYMSDECODED; @@ -440,7 +445,7 @@ CJBig2_SymbolDict* CJBig2_SDDProc::decode_Huffman(CJBig2_BitStream* pStream, pDecoder->SBRAT[1] = SDRAT[1]; pDecoder->SBRAT[2] = SDRAT[2]; pDecoder->SBRAT[3] = SDRAT[3]; - BS = pDecoder->decode_Huffman(pStream, grContext); + BS = pDecoder->decode_Huffman(pStream, vector_as_array(grContext)); if (!BS) { FX_Free(SBSYMCODES); FX_Free(SBSYMS); @@ -512,7 +517,7 @@ CJBig2_SymbolDict* CJBig2_SDDProc::decode_Huffman(CJBig2_BitStream* pStream, pGRRD->GRAT[3] = SDRAT[3]; nonstd::unique_ptr pArithDecoder( new CJBig2_ArithDecoder(pStream)); - BS = pGRRD->decode(pArithDecoder.get(), grContext); + BS = pGRRD->decode(pArithDecoder.get(), vector_as_array(grContext)); if (!BS) { FX_Free(SBSYMS); goto failed; diff --git a/core/src/fxcodec/jbig2/JBig2_SddProc.h b/core/src/fxcodec/jbig2/JBig2_SddProc.h index 7bc910fea1..01f8014ccc 100644 --- a/core/src/fxcodec/jbig2/JBig2_SddProc.h +++ b/core/src/fxcodec/jbig2/JBig2_SddProc.h @@ -7,25 +7,26 @@ #ifndef CORE_SRC_FXCODEC_JBIG2_JBIG2_SDDPROC_H_ #define CORE_SRC_FXCODEC_JBIG2_JBIG2_SDDPROC_H_ -#include "../../../core/include/fxcrt/fx_system.h" +#include + +#include "../../../include/fxcrt/fx_system.h" +#include "JBig2_ArithDecoder.h" -class CJBig2_ArithDecoder; class CJBig2_BitStream; class CJBig2_HuffmanTable; class CJBig2_Image; class CJBig2_SymbolDict; class IFX_Pause; -struct JBig2ArithCtx; class CJBig2_SDDProc { public: CJBig2_SymbolDict* decode_Arith(CJBig2_ArithDecoder* pArithDecoder, - JBig2ArithCtx* gbContext, - JBig2ArithCtx* grContext); + std::vector* gbContext, + std::vector* grContext); CJBig2_SymbolDict* decode_Huffman(CJBig2_BitStream* pStream, - JBig2ArithCtx* gbContext, - JBig2ArithCtx* grContext, + std::vector* gbContext, + std::vector* grContext, IFX_Pause* pPause); public: diff --git a/core/src/fxcodec/jbig2/JBig2_SymbolDict.cpp b/core/src/fxcodec/jbig2/JBig2_SymbolDict.cpp index a8f8a94529..351a8389c8 100644 --- a/core/src/fxcodec/jbig2/JBig2_SymbolDict.cpp +++ b/core/src/fxcodec/jbig2/JBig2_SymbolDict.cpp @@ -10,27 +10,19 @@ #include "JBig2_Image.h" CJBig2_SymbolDict::CJBig2_SymbolDict() { - m_bContextRetained = FALSE; - m_gbContext = m_grContext = NULL; } CJBig2_SymbolDict::~CJBig2_SymbolDict() { - if (m_bContextRetained) { - FX_Free(m_gbContext); - FX_Free(m_grContext); - } } nonstd::unique_ptr CJBig2_SymbolDict::DeepCopy() const { - nonstd::unique_ptr dst; const CJBig2_SymbolDict* src = this; - if (src->m_bContextRetained || src->m_gbContext || src->m_grContext) - return dst; - - dst.reset(new CJBig2_SymbolDict); + nonstd::unique_ptr dst(new CJBig2_SymbolDict); for (size_t i = 0; i < src->m_SDEXSYMS.size(); ++i) { CJBig2_Image* image = src->m_SDEXSYMS.get(i); dst->m_SDEXSYMS.push_back(image ? new CJBig2_Image(*image) : nullptr); } + dst->m_gbContext = src->m_gbContext; + dst->m_grContext = src->m_grContext; return dst; } diff --git a/core/src/fxcodec/jbig2/JBig2_SymbolDict.h b/core/src/fxcodec/jbig2/JBig2_SymbolDict.h index bec19f3eb7..bdca2693fe 100644 --- a/core/src/fxcodec/jbig2/JBig2_SymbolDict.h +++ b/core/src/fxcodec/jbig2/JBig2_SymbolDict.h @@ -7,12 +7,14 @@ #ifndef _JBIG2_SYMBOL_DICT_H_ #define _JBIG2_SYMBOL_DICT_H_ +#include + #include "../../../../third_party/base/nonstd_unique_ptr.h" #include "../../../include/fxcrt/fx_basic.h" +#include "JBig2_ArithDecoder.h" #include "JBig2_List.h" class CJBig2_Image; -struct JBig2ArithCtx; class CJBig2_SymbolDict { public: @@ -27,12 +29,19 @@ class CJBig2_SymbolDict { size_t NumImages() const { return m_SDEXSYMS.size(); } CJBig2_Image* GetImage(size_t index) const { return m_SDEXSYMS.get(index); } - public: - FX_BOOL m_bContextRetained; - JBig2ArithCtx* m_gbContext; - JBig2ArithCtx* m_grContext; + const std::vector& GbContext() const { return m_gbContext; } + const std::vector& GrContext() const { return m_grContext; } + + void SetGbContext(const std::vector& gbContext) { + m_gbContext = gbContext; + } + void SetGrContext(const std::vector& grContext) { + m_grContext = grContext; + } private: + std::vector m_gbContext; + std::vector m_grContext; CJBig2_List m_SDEXSYMS; }; diff --git a/third_party/BUILD.gn b/third_party/BUILD.gn index 21d3d5db32..f6358147be 100644 --- a/third_party/BUILD.gn +++ b/third_party/BUILD.gn @@ -300,6 +300,7 @@ source_set("pdfium_base") { "base/numerics/safe_conversions_impl.h", "base/numerics/safe_math.h", "base/numerics/safe_math_impl.h", + "base/stl_util.h", "base/template_util.h", ] } diff --git a/third_party/base/stl_util.h b/third_party/base/stl_util.h new file mode 100644 index 0000000000..fcbe5882a2 --- /dev/null +++ b/third_party/base/stl_util.h @@ -0,0 +1,27 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PDFIUM_THIRD_PARTY_BASE_STL_UTIL_H_ +#define PDFIUM_THIRD_PARTY_BASE_STL_UTIL_H_ + +#include + +namespace pdfium { + +// To treat a possibly-empty vector as an array, use these functions. +// If you know the array will never be empty, you can use &*v.begin() +// directly, but that is undefined behaviour if |v| is empty. +template +inline T* vector_as_array(std::vector* v) { + return v->empty() ? nullptr : &*v->begin(); +} + +template +inline const T* vector_as_array(const std::vector* v) { + return v->empty() ? nullptr : &*v->begin(); +} + +} // namespace pdfium + +#endif // PDFIUM_THIRD_PARTY_BASE_STL_UTIL_H_ diff --git a/third_party/third_party.gyp b/third_party/third_party.gyp index 6ad8beb48c..1ec0509eb2 100644 --- a/third_party/third_party.gyp +++ b/third_party/third_party.gyp @@ -281,11 +281,12 @@ 'base/logging.h', 'base/macros.h', 'base/nonstd_unique_ptr.h', - 'base/template_util.h', 'base/numerics/safe_conversions.h', 'base/numerics/safe_conversions_impl.h', 'base/numerics/safe_math.h', 'base/numerics/safe_math_impl.h', + 'base/stl_util.h', + 'base/template_util.h', ], }, ], -- cgit v1.2.3