diff --git a/src/content/test/data/gpu/webgl-overly-large-uniform.html b/src/content/test/data/gpu/webgl-overly-large-uniform.html new file mode 100644 index 0000000000000..9b28fa5ebc2d6 --- /dev/null +++ b/src/content/test/data/gpu/webgl-overly-large-uniform.html @@ -0,0 +1,137 @@ + + + + + + + + + + + diff --git a/src/content/test/gpu/gpu_tests/context_lost_integration_test.py b/src/content/test/gpu/gpu_tests/context_lost_integration_test.py index 9096205323b23..315338ca8795a 100755 --- a/src/content/test/gpu/gpu_tests/context_lost_integration_test.py +++ b/src/content/test/gpu/gpu_tests/context_lost_integration_test.py @@ -160,6 +160,8 @@ class ContextLostIntegrationTest(gpu_integration_test.GpuIntegrationTest): 'webgl_with_select_element.html'), ('ContextLost_WebGLContextLostInHiddenTab', 'webgl.html?query=kill_after_notification'), + ('ContextLost_WebGLContextLostOverlyLargeUniform', + 'webgl-overly-large-uniform.html'), ('ContextLost_WebGLBlockedAfterJSNavigation', 'webgl-domain-blocking-page1.html'), ('ContextLost_WebGLUnblockedAfterUserInitiatedReload', @@ -387,6 +389,16 @@ class ContextLostIntegrationTest(gpu_integration_test.GpuIntegrationTest): tab.Activate() self._WaitForTabAndCheckCompletion() + def _ContextLost_WebGLContextLostOverlyLargeUniform(self, + test_path: str) -> None: + self.RestartBrowserIfNecessaryWithArgs([ + cba.DISABLE_DOMAIN_BLOCKING_FOR_3D_APIS, + '--enable-features=DisableArrayBufferSizeLimitsForTesting' + ]) + self._NavigateAndWaitForLoad(test_path) + # No reason to wait more than 10 seconds for this test to complete. + self._WaitForTabAndCheckCompletion(timeout=10) + def _ContextLost_WebGLBlockedAfterJSNavigation(self, test_path): self.RestartBrowserIfNecessaryWithArgs([]) self._NavigateAndWaitForLoad(test_path) diff --git a/src/gpu/command_buffer/client/client_discardable_manager_unittest.cc b/src/gpu/command_buffer/client/client_discardable_manager_unittest.cc index 4b86fca0a696d..026ee81f42bdc 100644 --- a/src/gpu/command_buffer/client/client_discardable_manager_unittest.cc +++ b/src/gpu/command_buffer/client/client_discardable_manager_unittest.cc @@ -45,6 +45,9 @@ class FakeCommandBuffer : public CommandBuffer { EXPECT_TRUE(found != active_ids_.end()); active_ids_.erase(found); } + void ForceLostContext(error::ContextLostReason reason) override { + // No-op; doesn't need to be exercised here. + } private: int32_t next_id_ = 1; diff --git a/src/gpu/command_buffer/client/client_test_helper.cc b/src/gpu/command_buffer/client/client_test_helper.cc index 4fd55a3274a87..826f466f40cfa 100644 --- a/src/gpu/command_buffer/client/client_test_helper.cc +++ b/src/gpu/command_buffer/client/client_test_helper.cc @@ -158,6 +158,13 @@ void MockClientCommandBuffer::DelegateToFake() { this, &FakeCommandBufferServiceBase::DestroyTransferBufferHelper)); } +void MockClientCommandBuffer::ForceLostContext( + error::ContextLostReason reason) { + // TODO(kbr): add a test for a call to this method. + SetParseError(error::kLostContext); + SetContextLostReason(reason); +} + MockClientCommandBufferMockFlush::MockClientCommandBufferMockFlush() { DelegateToFake(); } diff --git a/src/gpu/command_buffer/client/client_test_helper.h b/src/gpu/command_buffer/client/client_test_helper.h index bd0cc0739efaa..2548be832472a 100644 --- a/src/gpu/command_buffer/client/client_test_helper.h +++ b/src/gpu/command_buffer/client/client_test_helper.h @@ -86,6 +86,8 @@ class MockClientCommandBuffer : public CommandBuffer, void SetTokenForSetGetBuffer(int32_t token) { token_ = token; } + void ForceLostContext(error::ContextLostReason reason) override; + private: int32_t put_offset_ = 0; int32_t token_ = 10000; // All token checks in the tests should pass. diff --git a/src/gpu/command_buffer/client/cmd_buffer_helper.cc b/src/gpu/command_buffer/client/cmd_buffer_helper.cc index 620fa6535a890..5d9d1c23dddf7 100644 --- a/src/gpu/command_buffer/client/cmd_buffer_helper.cc +++ b/src/gpu/command_buffer/client/cmd_buffer_helper.cc @@ -157,7 +157,8 @@ void CommandBufferHelper::UpdateCachedState(const CommandBuffer::State& state) { (state.set_get_buffer_count != set_get_buffer_count_); cached_get_offset_ = service_on_old_buffer_ ? 0 : state.get_offset; cached_last_token_read_ = state.token; - context_lost_ = error::IsError(state.error); + // Don't transition from a lost context to a working context. + context_lost_ |= error::IsError(state.error); } bool CommandBufferHelper::WaitForGetOffsetInRange(int32_t start, int32_t end) { @@ -296,7 +297,6 @@ void CommandBufferHelper::WaitForAvailableEntries(int32_t count) { if (!AllocateRingBuffer()) return; DCHECK(HaveRingBuffer()); - DCHECK(count < total_entry_count_); if (put_ + count > total_entry_count_) { // There's not enough room between the current put and the end of the // buffer, so we need to wrap. We will add noops all the way to the end, @@ -344,7 +344,16 @@ void CommandBufferHelper::WaitForAvailableEntries(int32_t count) { put_)) return; CalcImmediateEntries(count); - DCHECK_GE(immediate_entry_count_, count); + if (immediate_entry_count_ < count) { + // Tell the underlying command buffer to signal a lost context to higher + // levels. + command_buffer_->ForceLostContext(error::kGuilty); + // Free the ring buffer and lose context. + FreeRingBuffer(); + usable_ = false; + context_lost_ = true; + return; + } } } } diff --git a/src/gpu/command_buffer/common/command_buffer.h b/src/gpu/command_buffer/common/command_buffer.h index 6335c4757f2e2..5ac9069424fe3 100644 --- a/src/gpu/command_buffer/common/command_buffer.h +++ b/src/gpu/command_buffer/common/command_buffer.h @@ -125,6 +125,10 @@ class GPU_EXPORT CommandBuffer { // before it is safe to call this function to destroy it. virtual void DestroyTransferBuffer(int32_t id) = 0; + // Forcibly lose this context. Used by higher-level code when it determines + // the necessity to do so. Has no effect if the context has already been lost. + virtual void ForceLostContext(error::ContextLostReason reason) = 0; + private: DISALLOW_COPY_AND_ASSIGN(CommandBuffer); }; diff --git a/src/gpu/command_buffer/service/command_buffer_direct.cc b/src/gpu/command_buffer/service/command_buffer_direct.cc index e32139b6bfd65..6a7f7e55487ef 100644 --- a/src/gpu/command_buffer/service/command_buffer_direct.cc +++ b/src/gpu/command_buffer/service/command_buffer_direct.cc @@ -63,6 +63,11 @@ void CommandBufferDirect::DestroyTransferBuffer(int32_t id) { service_.DestroyTransferBuffer(id); } +void CommandBufferDirect::ForceLostContext(error::ContextLostReason reason) { + service_.SetContextLostReason(reason); + service_.SetParseError(error::kLostContext); +} + CommandBufferServiceClient::CommandBatchProcessedResult CommandBufferDirect::OnCommandBatchProcessed() { return kContinueExecution; diff --git a/src/gpu/command_buffer/service/command_buffer_direct.h b/src/gpu/command_buffer/service/command_buffer_direct.h index d03ac687b6f4b..4d8175c3f56fa 100644 --- a/src/gpu/command_buffer/service/command_buffer_direct.h +++ b/src/gpu/command_buffer/service/command_buffer_direct.h @@ -40,6 +40,7 @@ class GPU_EXPORT CommandBufferDirect : public CommandBuffer, TransferBufferAllocationOption option = TransferBufferAllocationOption::kLoseContextOnOOM) override; void DestroyTransferBuffer(int32_t id) override; + void ForceLostContext(error::ContextLostReason reason) override; // CommandBufferServiceClient implementation: CommandBatchProcessedResult OnCommandBatchProcessed() override; diff --git a/src/gpu/ipc/client/command_buffer_proxy_impl.cc b/src/gpu/ipc/client/command_buffer_proxy_impl.cc index bfafcdc9524d8..77455d492fbfc 100644 --- a/src/gpu/ipc/client/command_buffer_proxy_impl.cc +++ b/src/gpu/ipc/client/command_buffer_proxy_impl.cc @@ -407,6 +407,22 @@ void CommandBufferProxyImpl::DestroyTransferBuffer(int32_t id) { GpuCommandBufferMsg_DestroyTransferBuffer(route_id_, id)); } +void CommandBufferProxyImpl::ForceLostContext(error::ContextLostReason reason) { + CheckLock(); + base::AutoLock lock(last_state_lock_); + if (last_state_.error == gpu::error::kLostContext) { + // Per specification, do nothing if the context is already lost. + return; + } + last_state_.error = gpu::error::kLostContext; + // The caller determines the context lost reason. + last_state_.context_lost_reason = reason; + // Calling code may be in an indeterminate state (possibly including + // being in a GpuControlClient callback), so avoid re-entering the + // GpuControlClient here. + DisconnectChannelInFreshCallStack(); +} + void CommandBufferProxyImpl::SetGpuControlClient(GpuControlClient* client) { CheckLock(); gpu_control_client_ = client; diff --git a/src/gpu/ipc/client/command_buffer_proxy_impl.h b/src/gpu/ipc/client/command_buffer_proxy_impl.h index 3a541f708a32e..540ca3486d869 100644 --- a/src/gpu/ipc/client/command_buffer_proxy_impl.h +++ b/src/gpu/ipc/client/command_buffer_proxy_impl.h @@ -111,6 +111,7 @@ class GPU_EXPORT CommandBufferProxyImpl : public gpu::CommandBuffer, TransferBufferAllocationOption option = TransferBufferAllocationOption::kLoseContextOnOOM) override; void DestroyTransferBuffer(int32_t id) override; + void ForceLostContext(error::ContextLostReason reason) override; // gpu::GpuControl implementation: void SetGpuControlClient(GpuControlClient* client) override; diff --git a/src/gpu/ipc/in_process_command_buffer.cc b/src/gpu/ipc/in_process_command_buffer.cc index 18dc45de9fa89..e3e9c59e54588 100644 --- a/src/gpu/ipc/in_process_command_buffer.cc +++ b/src/gpu/ipc/in_process_command_buffer.cc @@ -1040,6 +1040,21 @@ void InProcessCommandBuffer::DestroyTransferBuffer(int32_t id) { gpu_thread_weak_ptr_factory_.GetWeakPtr(), id)); } +void InProcessCommandBuffer::ForceLostContext(error::ContextLostReason reason) { + ScheduleGpuTask( + base::BindOnce(&InProcessCommandBuffer::ForceLostContextOnGpuThread, + gpu_thread_weak_ptr_factory_.GetWeakPtr(), reason)); +} + +void InProcessCommandBuffer::ForceLostContextOnGpuThread( + error::ContextLostReason reason) { + DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_); + + // Similar implementation to CommandBufferDirect. + command_buffer_->SetContextLostReason(reason); + command_buffer_->SetParseError(error::kLostContext); +} + void InProcessCommandBuffer::DestroyTransferBufferOnGpuThread(int32_t id) { DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_); command_buffer_->DestroyTransferBuffer(id); diff --git a/src/gpu/ipc/in_process_command_buffer.h b/src/gpu/ipc/in_process_command_buffer.h index 82d4dc1c7263d..5c32e278a30ca 100644 --- a/src/gpu/ipc/in_process_command_buffer.h +++ b/src/gpu/ipc/in_process_command_buffer.h @@ -142,6 +142,7 @@ class GL_IN_PROCESS_CONTEXT_EXPORT InProcessCommandBuffer TransferBufferAllocationOption option = TransferBufferAllocationOption::kLoseContextOnOOM) override; void DestroyTransferBuffer(int32_t id) override; + void ForceLostContext(error::ContextLostReason reason) override; // GpuControl implementation (called on client thread): void SetGpuControlClient(GpuControlClient*) override; @@ -313,6 +314,7 @@ class GL_IN_PROCESS_CONTEXT_EXPORT InProcessCommandBuffer void RegisterTransferBufferOnGpuThread(int32_t id, scoped_refptr buffer); void DestroyTransferBufferOnGpuThread(int32_t id); + void ForceLostContextOnGpuThread(error::ContextLostReason reason); void CreateImageOnGpuThread(int32_t id, gfx::GpuMemoryBufferHandle handle, diff --git a/src/ppapi/proxy/ppapi_command_buffer_proxy.cc b/src/ppapi/proxy/ppapi_command_buffer_proxy.cc index a76aaab2f9ab9..ff4d71888f74c 100644 --- a/src/ppapi/proxy/ppapi_command_buffer_proxy.cc +++ b/src/ppapi/proxy/ppapi_command_buffer_proxy.cc @@ -171,6 +171,12 @@ void PpapiCommandBufferProxy::DestroyTransferBuffer(int32_t id) { ppapi::API_ID_PPB_GRAPHICS_3D, resource_, id)); } +void PpapiCommandBufferProxy::ForceLostContext(gpu::error::ContextLostReason) { + // This entry point was added to CommandBuffer well after PPAPI's + // deprecation. No current clients determined its necessity, so it + // will not be implemented. +} + void PpapiCommandBufferProxy::SetLock(base::Lock*) { NOTREACHED(); } diff --git a/src/ppapi/proxy/ppapi_command_buffer_proxy.h b/src/ppapi/proxy/ppapi_command_buffer_proxy.h index ce2697a5a869e..9c40ab8eaaf45 100644 --- a/src/ppapi/proxy/ppapi_command_buffer_proxy.h +++ b/src/ppapi/proxy/ppapi_command_buffer_proxy.h @@ -55,6 +55,7 @@ class PPAPI_PROXY_EXPORT PpapiCommandBufferProxy : public gpu::CommandBuffer, gpu::TransferBufferAllocationOption option = gpu::TransferBufferAllocationOption::kLoseContextOnOOM) override; void DestroyTransferBuffer(int32_t id) override; + void ForceLostContext(gpu::error::ContextLostReason reason) override; // gpu::GpuControl implementation: void SetGpuControlClient(gpu::GpuControlClient*) override; diff --git a/src/third_party/blink/common/features.cc b/src/third_party/blink/common/features.cc index 4b469825b4cda..766786ebc2dd9 100644 --- a/src/third_party/blink/common/features.cc +++ b/src/third_party/blink/common/features.cc @@ -887,5 +887,9 @@ const base::FeatureParam const base::Feature kCLSM90Improvements{"CLSM90Improvements", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kDisableArrayBufferSizeLimitsForTesting{ + "DisableArrayBufferSizeLimitsForTesting", + base::FEATURE_DISABLED_BY_DEFAULT}; + } // namespace features } // namespace blink diff --git a/src/third_party/blink/public/common/features.h b/src/third_party/blink/public/common/features.h index e371d93b8ffbd..89c12448b0ec8 100644 --- a/src/third_party/blink/public/common/features.h +++ b/src/third_party/blink/public/common/features.h @@ -364,6 +364,12 @@ BLINK_COMMON_EXPORT extern const base::FeatureParam BLINK_COMMON_EXPORT extern const base::Feature kCLSM90Improvements; +// TODO(https://crbug.com/1201109): temporary flag to disable new ArrayBuffer +// size limits, so that tests can be written against code receiving these +// buffers. Remove when the bindings code instituting these limits is removed. +BLINK_COMMON_EXPORT extern const base::Feature + kDisableArrayBufferSizeLimitsForTesting; + } // namespace features } // namespace blink diff --git a/src/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/src/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc index 86415db444bd7..00666c5ff35d8 100644 --- a/src/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc +++ b/src/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc @@ -8310,6 +8310,22 @@ bool WebGLRenderingContextBase::ValidateUniformMatrixParameters( SynthesizeGLError(GL_INVALID_VALUE, function_name, "invalid size"); return false; } + // By design the command buffer has an internal (signed) 32-bit + // limit, so ensure that the amount of data passed down to it + // doesn't exceed what it can handle. Only integer or float typed + // arrays can be passed into the uniform*v or uniformMatrix*v + // functions; each has 4-byte elements. + base::CheckedNumeric total_size(actual_size); + total_size *= 4; + // Add on a fixed constant to account for internal metadata in the + // command buffer. + constexpr int32_t kExtraCommandSize = 1024; + total_size += kExtraCommandSize; + if (!total_size.IsValid()) { + SynthesizeGLError(GL_INVALID_VALUE, function_name, + "size * elementSize, plus a constant, is too large"); + return false; + } return true; } diff --git a/src/third_party/libwebp/README.chromium b/src/third_party/libwebp/README.chromium index fd77980a907cc..4968eaea94686 100644 --- a/src/third_party/libwebp/README.chromium +++ b/src/third_party/libwebp/README.chromium @@ -1,7 +1,7 @@ Name: WebP image encoder/decoder Short Name: libwebp URL: http://developers.google.com/speed/webp -Version: v1.2.0 +Version: 20ef03ee351d4ff03fc5ff3ec4804a879d1b9d5c CPEPrefix: cpe:/a:webmproject:libwebp:1.2.0 License: BSD License File: LICENSE @@ -9,7 +9,7 @@ Security Critical: Yes Description: Source archive: - https://chromium.googlesource.com/webm/libwebp/+archive/v1.2.0.tar.gz + https://chromium.googlesource.com/webm/libwebp/+archive/20ef03ee351d4ff03fc5ff3ec4804a879d1b9d5c.tar.gz WebP is an image format that does both lossy and lossless compression of digital photographic images. WebP consists of a codec based on VP8, that Google diff --git a/src/third_party/libwebp/src/dsp/alpha_processing_neon.c b/src/third_party/libwebp/src/dsp/alpha_processing_neon.c index 9d55421704cc8..27d717507c5fe 100644 --- a/src/third_party/libwebp/src/dsp/alpha_processing_neon.c +++ b/src/third_party/libwebp/src/dsp/alpha_processing_neon.c @@ -83,7 +83,7 @@ static void ApplyAlphaMultiply_NEON(uint8_t* rgba, int alpha_first, static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride, int width, int height, uint8_t* dst, int dst_stride) { - uint32_t alpha_mask = 0xffffffffu; + uint32_t alpha_mask = 0xffu; uint8x8_t mask8 = vdup_n_u8(0xff); uint32_t tmp[2]; int i, j; @@ -107,6 +107,7 @@ static int DispatchAlpha_NEON(const uint8_t* alpha, int alpha_stride, dst += dst_stride; } vst1_u8((uint8_t*)tmp, mask8); + alpha_mask *= 0x01010101; alpha_mask &= tmp[0]; alpha_mask &= tmp[1]; return (alpha_mask != 0xffffffffu); @@ -134,7 +135,7 @@ static void DispatchAlphaToGreen_NEON(const uint8_t* alpha, int alpha_stride, static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride, int width, int height, uint8_t* alpha, int alpha_stride) { - uint32_t alpha_mask = 0xffffffffu; + uint32_t alpha_mask = 0xffu; uint8x8_t mask8 = vdup_n_u8(0xff); uint32_t tmp[2]; int i, j; @@ -156,6 +157,7 @@ static int ExtractAlpha_NEON(const uint8_t* argb, int argb_stride, alpha += alpha_stride; } vst1_u8((uint8_t*)tmp, mask8); + alpha_mask *= 0x01010101; alpha_mask &= tmp[0]; alpha_mask &= tmp[1]; return (alpha_mask == 0xffffffffu); diff --git a/src/third_party/libwebp/src/dsp/lossless_enc_mips32.c b/src/third_party/libwebp/src/dsp/lossless_enc_mips32.c index 0412a093cf9ab..9963051798eee 100644 --- a/src/third_party/libwebp/src/dsp/lossless_enc_mips32.c +++ b/src/third_party/libwebp/src/dsp/lossless_enc_mips32.c @@ -347,24 +347,24 @@ static void GetCombinedEntropyUnrefined_MIPS32(const uint32_t X[], static void AddVector_MIPS32(const uint32_t* pa, const uint32_t* pb, uint32_t* pout, int size) { uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; - const uint32_t end = ((size) / 4) * 4; + const int end = ((size) / 4) * 4; const uint32_t* const LoopEnd = pa + end; int i; ASM_START ADD_TO_OUT(0, 4, 8, 12, 1, pa, pb, pout) ASM_END_0 - for (i = end; i < size; ++i) pout[i] = pa[i] + pb[i]; + for (i = 0; i < size - end; ++i) pout[i] = pa[i] + pb[i]; } static void AddVectorEq_MIPS32(const uint32_t* pa, uint32_t* pout, int size) { uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; - const uint32_t end = ((size) / 4) * 4; + const int end = ((size) / 4) * 4; const uint32_t* const LoopEnd = pa + end; int i; ASM_START ADD_TO_OUT(0, 4, 8, 12, 0, pa, pout, pout) ASM_END_1 - for (i = end; i < size; ++i) pout[i] += pa[i]; + for (i = 0; i < size - end; ++i) pout[i] += pa[i]; } #undef ASM_END_1 diff --git a/src/third_party/libwebp/src/enc/backward_references_cost_enc.c b/src/third_party/libwebp/src/enc/backward_references_cost_enc.c index 516abd73eb45c..5eb24d449953d 100644 --- a/src/third_party/libwebp/src/enc/backward_references_cost_enc.c +++ b/src/third_party/libwebp/src/enc/backward_references_cost_enc.c @@ -577,7 +577,7 @@ static int BackwardReferencesHashChainDistanceOnly( (CostModel*)WebPSafeCalloc(1ULL, cost_model_size); VP8LColorCache hashers; CostManager* cost_manager = - (CostManager*)WebPSafeMalloc(1ULL, sizeof(*cost_manager)); + (CostManager*)WebPSafeCalloc(1ULL, sizeof(*cost_manager)); int offset_prev = -1, len_prev = -1; double offset_cost = -1; int first_offset_is_constant = -1; // initialized with 'impossible' value diff --git a/src/third_party/libwebp/src/enc/backward_references_enc.c b/src/third_party/libwebp/src/enc/backward_references_enc.c index 519b36a09153e..d5e931efdd8cf 100644 --- a/src/third_party/libwebp/src/enc/backward_references_enc.c +++ b/src/third_party/libwebp/src/enc/backward_references_enc.c @@ -976,15 +976,16 @@ static int GetBackwardReferences(int width, int height, const VP8LHashChain* const hash_chain_tmp = (lz77_types_best[i] == kLZ77Standard) ? hash_chain : &hash_chain_box; const int cache_bits = (i == 1) ? 0 : *cache_bits_best; - if (VP8LBackwardReferencesTraceBackwards(width, height, argb, cache_bits, - hash_chain_tmp, &refs[i], - refs_tmp)) { - double bit_cost_trace; - VP8LHistogramCreate(histo, refs_tmp, cache_bits); - bit_cost_trace = VP8LHistogramEstimateBits(histo); - if (bit_cost_trace < bit_costs_best[i]) { - BackwardRefsSwap(refs_tmp, &refs[i]); - } + double bit_cost_trace; + if (!VP8LBackwardReferencesTraceBackwards(width, height, argb, cache_bits, + hash_chain_tmp, &refs[i], + refs_tmp)) { + goto Error; + } + VP8LHistogramCreate(histo, refs_tmp, cache_bits); + bit_cost_trace = VP8LHistogramEstimateBits(histo); + if (bit_cost_trace < bit_costs_best[i]) { + BackwardRefsSwap(refs_tmp, &refs[i]); } } diff --git a/src/third_party/libwebp/src/enc/vp8l_enc.c b/src/third_party/libwebp/src/enc/vp8l_enc.c index 0b44ebe46ec54..1875e53552d31 100644 --- a/src/third_party/libwebp/src/enc/vp8l_enc.c +++ b/src/third_party/libwebp/src/enc/vp8l_enc.c @@ -1706,11 +1706,16 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config, const WebPWorkerInterface* const worker_interface = WebPGetWorkerInterface(); int ok_main; + if (enc_main == NULL || !VP8LBitWriterInit(&bw_side, 0)) { + WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY); + VP8LEncoderDelete(enc_main); + return 0; + } + // Analyze image (entropy, num_palettes etc) - if (enc_main == NULL || - !EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main, + if (!EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main, &red_and_blue_always_zero) || - !EncoderInit(enc_main) || !VP8LBitWriterInit(&bw_side, 0)) { + !EncoderInit(enc_main)) { err = VP8_ENC_ERROR_OUT_OF_MEMORY; goto Error; }