Verified Commit a6477a0d authored by longsonr's avatar longsonr Committed by ma1
Browse files

Bug 2074896 - Prevent feTile rect calculations from overflowing a=dmeehan DONTBUILD

parent 59224c72
Loading
Loading
Loading
Loading
+15 −7
Changes for gfx/2d/FilterNodeSoftware.cpp: 15 added lines, 7 removed lines.
Original line number Diff line number Diff line
@@ -1636,9 +1636,7 @@ int32_t FilterNodeTileSoftware::InputIndex(uint32_t aInputEnumIndex) {
void FilterNodeTileSoftware::SetAttribute(uint32_t aIndex,
                                          const IntRect& aSourceRect) {
  MOZ_ASSERT(aIndex == ATT_TILE_SOURCE_RECT);
  mSourceRect.SetRect(int32_t(aSourceRect.X()), int32_t(aSourceRect.Y()),
                      int32_t(aSourceRect.Width()),
                      int32_t(aSourceRect.Height()));
  mSourceRect = aSourceRect;
  Invalidate();
}

@@ -1676,14 +1674,24 @@ already_AddRefed<DataSourceSurface> FilterNodeTileSoftware::Render(
      InputMap;
  InputMap inputs;

  auto IntRectToInt64Rect = [](const IntRect& aRect) {
    return RectTyped<UnknownUnits, int64_t>(aRect.X(), aRect.Y(), aRect.Width(),
                                            aRect.Height());
  };

  IntPoint startIndex = TileIndex(mSourceRect, aRect.TopLeft());
  IntPoint endIndex = TileIndex(mSourceRect, aRect.BottomRight());
  for (int32_t ix = startIndex.x; ix <= endIndex.x; ix++) {
    for (int32_t iy = startIndex.y; iy <= endIndex.y; iy++) {
      IntPoint sourceToDestOffset(ix * mSourceRect.Width(),
                                  iy * mSourceRect.Height());
      IntRect destRect = aRect.Intersect(mSourceRect + sourceToDestOffset);
      IntRect srcRect = destRect - sourceToDestOffset;
      auto sourceToDestOffset = PointTyped<UnknownUnits, int64_t>(
          ix * mSourceRect.Width(), iy * mSourceRect.Height());
      auto destRect64 = IntRectToInt64Rect(aRect).Intersect(
          IntRectToInt64Rect(mSourceRect) + sourceToDestOffset);
      auto srcRect64 = destRect64 - sourceToDestOffset;
      IntRect destRect, srcRect;
      if (!destRect64.ToIntRect(&destRect) || !srcRect64.ToIntRect(&srcRect)) {
        return nullptr;
      }
      if (srcRect.IsEmpty()) {
        continue;
      }
+84 −0
Changes for gfx/tests/gtest/TestFilterNodeSoftware.cpp: 84 added lines, 0 removed lines.
Original line number Diff line number Diff line
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <cstring>
#include <iterator>
#include <limits>
#include <vector>

#include "2D.h"
#include "FilterNodeSoftware.h"
#include "gtest/gtest.h"

using namespace mozilla;
using namespace mozilla::gfx;

namespace {

class TileTestInput final : public FilterNodeSoftware {
 public:
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(TileTestInput, override)

  std::vector<IntRect> mRects;

 protected:
  IntRect GetOutputRectInRect(const IntRect& aRect) override { return aRect; }

  already_AddRefed<DataSourceSurface> GetOutput(const IntRect& aRect) override {
    return Render(aRect);
  }

  already_AddRefed<DataSourceSurface> Render(const IntRect& aRect) override {
    mRects.push_back(aRect);
    RefPtr<DataSourceSurface> surface =
        Factory::CreateDataSourceSurface(aRect.Size(), SurfaceFormat::A8, true);
    if (!surface) {
      return nullptr;
    }
    DataSourceSurface::ScopedMap map(surface, DataSourceSurface::WRITE);
    if (!map.IsMapped()) {
      return nullptr;
    }
    for (int32_t y = 0; y < aRect.Height(); ++y) {
      std::memset(map.GetData() + y * map.GetStride(), 0x7f, aRect.Width());
    }
    return surface.forget();
  }
};

class TileTestNode final : public FilterNodeTileSoftware {
 public:
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(TileTestNode, override)
  using FilterNodeTileSoftware::Render;
};

}  // namespace

TEST(Moz2D, TileAcrossCoordinateLimits)
{
  constexpr int32_t extent = std::numeric_limits<int32_t>::max() - 1;
  constexpr int32_t last = extent - 6;
  RefPtr<TileTestInput> input = MakeRefPtr<TileTestInput>();
  RefPtr<TileTestNode> tile = MakeRefPtr<TileTestNode>();
  tile->SetInput(IN_TILE_IN, input.get());
  tile->SetAttribute(ATT_TILE_SOURCE_RECT, IntRect(-4, -4, extent, extent));

  RefPtr<DataSourceSurface> output = tile->Render(IntRect(-6, -6, 4, 4));
  ASSERT_TRUE(output);
  const IntRect expected[] = {IntRect(last, last, 2, 2),
                              IntRect(last, -4, 2, 2), IntRect(-4, last, 2, 2),
                              IntRect(-4, -4, 2, 2)};
  ASSERT_EQ(input->mRects.size(), std::size(expected));
  for (size_t i = 0; i < std::size(expected); ++i) {
    EXPECT_EQ(input->mRects[i], expected[i]);
  }

  DataSourceSurface::ScopedMap map(output, DataSourceSurface::READ);
  ASSERT_TRUE(map.IsMapped());
  for (int32_t y = 0; y < 4; ++y) {
    for (int32_t x = 0; x < 4; ++x) {
      EXPECT_EQ(map.GetData()[y * map.GetStride() + x], 0x7f);
    }
  }
}
+1 −0
Changes for gfx/tests/gtest/moz.build: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ UNIFIED_SOURCES += [
    "TestBufferRotation.cpp",
    "TestConfigManager.cpp",
    "TestCoord.cpp",
    "TestFilterNodeSoftware.cpp",
    "TestGfxWidgets.cpp",
    "TestMatrix.cpp",
    "TestMoz2D.cpp",