aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar fmalita <fmalita@chromium.org>2016-10-05 09:28:42 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-10-05 09:28:42 -0700
commit088e21ba652ceaa4abb4ba8cdd2ec1bc8afc32ed (patch)
treed85e228092824a9e721d5831947209842f2bdf1c
parentc6618dd1dadeac8b47b81fbee108c42cca8ab166 (diff)
Harden degenerate gradient context handling
Certain inputs produce degenerate values at context creation time only. Detect such cases after context creation, and abort drawing by returning a null shader context instead. BUG=skia:5821 R=reed@google.com,brianosman@google.com GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2397473003 Review-Url: https://codereview.chromium.org/2397473003
-rw-r--r--include/core/SkMatrix.h9
-rw-r--r--src/effects/gradients/Sk4fGradientBase.cpp5
-rw-r--r--src/effects/gradients/Sk4fGradientBase.h2
-rw-r--r--src/effects/gradients/SkGradientShader.cpp4
-rw-r--r--src/effects/gradients/SkGradientShaderPriv.h13
-rw-r--r--src/effects/gradients/SkLinearGradient.cpp4
-rw-r--r--src/effects/gradients/SkRadialGradient.cpp2
-rw-r--r--src/effects/gradients/SkSweepGradient.cpp2
-rw-r--r--src/effects/gradients/SkTwoPointConicalGradient.cpp2
9 files changed, 33 insertions, 10 deletions
diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h
index 19103843bf..f565a537ba 100644
--- a/include/core/SkMatrix.h
+++ b/include/core/SkMatrix.h
@@ -736,6 +736,11 @@ public:
this->setTypeMask(mask | kRectStaysRect_Mask);
}
+ /**
+ * Are all elements of the matrix finite?
+ */
+ bool isFinite() const { return SkScalarsAreFinite(fMat, 9); }
+
private:
enum {
/** Set if the matrix will map a rectangle to another rectangle. This
@@ -768,10 +773,6 @@ private:
SkScalar fMat[9];
mutable uint32_t fTypeMask;
- /** Are all elements of the matrix finite?
- */
- bool isFinite() const { return SkScalarsAreFinite(fMat, 9); }
-
static void ComputeInv(SkScalar dst[9], const SkScalar src[9], double invDet, bool isPersp);
uint8_t computeTypeMask() const;
diff --git a/src/effects/gradients/Sk4fGradientBase.cpp b/src/effects/gradients/Sk4fGradientBase.cpp
index a22136831d..8994db3a91 100644
--- a/src/effects/gradients/Sk4fGradientBase.cpp
+++ b/src/effects/gradients/Sk4fGradientBase.cpp
@@ -158,6 +158,11 @@ GradientShaderBase4fContext::GradientShaderBase4fContext(const SkGradientShaderB
|| shader.fColorsAreOpaque;
}
+bool SkGradientShaderBase::
+GradientShaderBase4fContext::isValid() const {
+ return fDstToPos.isFinite();
+}
+
void SkGradientShaderBase::
GradientShaderBase4fContext::buildIntervals(const SkGradientShaderBase& shader,
const ContextRec& rec, bool reverse) {
diff --git a/src/effects/gradients/Sk4fGradientBase.h b/src/effects/gradients/Sk4fGradientBase.h
index 17f9563957..fd6d6563a7 100644
--- a/src/effects/gradients/Sk4fGradientBase.h
+++ b/src/effects/gradients/Sk4fGradientBase.h
@@ -28,6 +28,8 @@ public:
void shadeSpan(int x, int y, SkPMColor dst[], int count) override;
void shadeSpan4f(int x, int y, SkPM4f dst[], int count) override;
+ bool isValid() const;
+
protected:
struct Interval {
Interval(const Sk4f& c0, SkScalar p0,
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 4ee82037d1..17302d9d4f 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -397,6 +397,10 @@ SkGradientShaderBase::GradientShaderBaseContext::GradientShaderBaseContext(
}
}
+bool SkGradientShaderBase::GradientShaderBaseContext::isValid() const {
+ return fDstToIndex.isFinite();
+}
+
SkGradientShaderBase::GradientShaderCache::GradientShaderCache(
U8CPU alpha, bool dither, const SkGradientShaderBase& shader)
: fCacheAlpha(alpha)
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index f850994761..61a44184ff 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -115,7 +115,6 @@ public:
SkAutoMalloc fDynamicStorage;
};
-public:
SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit);
virtual ~SkGradientShaderBase();
@@ -159,6 +158,8 @@ public:
uint32_t getFlags() const override { return fFlags; }
+ bool isValid() const;
+
protected:
SkMatrix fDstToIndex;
SkMatrix::MapXYProc fDstToIndexProc;
@@ -233,6 +234,16 @@ protected:
SkColor* colorSrc, Rec* recSrc,
int count);
+ template <typename T, typename... Args>
+ static Context* CheckedCreateContext(void* storage, Args&&... args) {
+ auto* ctx = new (storage) T(std::forward<Args>(args)...);
+ if (!ctx->isValid()) {
+ ctx->~T();
+ return nullptr;
+ }
+ return ctx;
+ }
+
private:
enum {
kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index be29540add..a249ae4ac8 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -82,8 +82,8 @@ size_t SkLinearGradient::onContextSize(const ContextRec& rec) const {
SkShader::Context* SkLinearGradient::onCreateContext(const ContextRec& rec, void* storage) const {
return use_4f_context(rec, fGradFlags)
- ? static_cast<SkShader::Context*>(new (storage) LinearGradient4fContext(*this, rec))
- : static_cast<SkShader::Context*>(new (storage) LinearGradientContext(*this, rec));
+ ? CheckedCreateContext<LinearGradient4fContext>(storage, *this, rec)
+ : CheckedCreateContext< LinearGradientContext>(storage, *this, rec);
}
// This swizzles SkColor into the same component order as SkPMColor, but does not actually
diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp
index b0ef205f44..18ef376862 100644
--- a/src/effects/gradients/SkRadialGradient.cpp
+++ b/src/effects/gradients/SkRadialGradient.cpp
@@ -44,7 +44,7 @@ size_t SkRadialGradient::onContextSize(const ContextRec&) const {
}
SkShader::Context* SkRadialGradient::onCreateContext(const ContextRec& rec, void* storage) const {
- return new (storage) RadialGradientContext(*this, rec);
+ return CheckedCreateContext<RadialGradientContext>(storage, *this, rec);
}
SkRadialGradient::RadialGradientContext::RadialGradientContext(
diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp
index d99d979f68..d1fe269b9c 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -50,7 +50,7 @@ size_t SkSweepGradient::onContextSize(const ContextRec&) const {
}
SkShader::Context* SkSweepGradient::onCreateContext(const ContextRec& rec, void* storage) const {
- return new (storage) SweepGradientContext(*this, rec);
+ return CheckedCreateContext<SweepGradientContext>(storage, *this, rec);
}
SkSweepGradient::SweepGradientContext::SweepGradientContext(
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp
index fd48a62679..599fd4c9fd 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp
@@ -216,7 +216,7 @@ size_t SkTwoPointConicalGradient::onContextSize(const ContextRec&) const {
SkShader::Context* SkTwoPointConicalGradient::onCreateContext(const ContextRec& rec,
void* storage) const {
- return new (storage) TwoPointConicalGradientContext(*this, rec);
+ return CheckedCreateContext<TwoPointConicalGradientContext>(storage, *this, rec);
}
SkTwoPointConicalGradient::TwoPointConicalGradientContext::TwoPointConicalGradientContext(