Skip to content

Commit

Permalink
[Bug] Fixed undefined behavior in affine pattern initializer
Browse files Browse the repository at this point in the history
  • Loading branch information
kobalicek committed Feb 24, 2024
1 parent 3e96d5e commit 5a263ce
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 23 deletions.
35 changes: 18 additions & 17 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,12 @@ if (NOT DEFINED BLEND2D_NO_NATVIS)
set(BLEND2D_NO_NATVIS FALSE)
endif()

set(BLEND2D_DIR "${BLEND2D_DIR}" CACHE PATH "Location of 'blend2d'")
set(BLEND2D_TEST "${BLEND2D_TEST}" CACHE BOOL "Build 'blend2d' tests and samples")
set(BLEND2D_EMBED "${BLEND2D_EMBED}" CACHE BOOL "Embed 'blend2d' library (no targets)")
set(BLEND2D_STATIC "${BLEND2D_STATIC}" CACHE BOOL "Build 'blend2d' statically")
set(BLEND2D_SANITIZE "${BLEND2D_SANITIZE}" CACHE STRING "List of sanitizers to use")
set(BLEND2D_DIR "${BLEND2D_DIR}" CACHE PATH "Location of 'blend2d'")
set(BLEND2D_TEST "${BLEND2D_TEST}" CACHE BOOL "Build 'blend2d' tests and samples")
set(BLEND2D_EMBED "${BLEND2D_EMBED}" CACHE BOOL "Embed 'blend2d' library (no targets)")
set(BLEND2D_STATIC "${BLEND2D_STATIC}" CACHE BOOL "Build 'blend2d' statically")
set(BLEND2D_SANITIZE "${BLEND2D_SANITIZE}" CACHE STRING "List of sanitizers to use")
set(BLEND2D_SANITIZE_OPTS "${BLEND2D_SANITIZE_OPTS}" CACHE STRING "Additional flags to pass to sanitizers")

# Experimental build options.
# set(BLEND2D_NO_JIT 1)
Expand All @@ -69,18 +70,18 @@ endif()
# Blend2D - Project
# =================

set(BLEND2D_INCLUDE_DIRS "${BLEND2D_DIR}/src") # Include directory is the same as source dir.
set(BLEND2D_DEPS "") # Blend2D dependencies (libraries) for the linker.
set(BLEND2D_LIBS "") # Dependencies of libs/apps that want to use Blend2D.
set(BLEND2D_CFLAGS "") # Public compiler flags.
set(BLEND2D_PRIVATE_CFLAGS "") # Private compiler flags independent of build type.
set(BLEND2D_PRIVATE_CFLAGS_DBG "") # Private compiler flags used by debug builds.
set(BLEND2D_PRIVATE_CFLAGS_REL "") # Private compiler flags used by release builds.
set(BLEND2D_PRIVATE_LFLAGS "") # Private linker flags.
set(BLEND2D_SANITIZE_CFLAGS "") # Compiler flags required by currently enabled sanitizers.
set(BLEND2D_SANITIZE_LFLAGS "") # Linker flags required by currently enabled sanitizers.
set(BLEND2D_NO_STDCXX_CFLAGS "") # Private compiler flags to disable linking to a standard C++ library.
set(BLEND2D_NO_STDCXX_LFLAGS "") # Private linker flags to disable linking to a standard C++ library.
set(BLEND2D_INCLUDE_DIRS "${BLEND2D_DIR}/src") # Include directory is the same as source dir.
set(BLEND2D_DEPS "") # Blend2D dependencies (libraries) for the linker.
set(BLEND2D_LIBS "") # Dependencies of libs/apps that want to use Blend2D.
set(BLEND2D_CFLAGS "") # Public compiler flags.
set(BLEND2D_PRIVATE_CFLAGS "") # Private compiler flags independent of build type.
set(BLEND2D_PRIVATE_CFLAGS_DBG "") # Private compiler flags used by debug builds.
set(BLEND2D_PRIVATE_CFLAGS_REL "") # Private compiler flags used by release builds.
set(BLEND2D_PRIVATE_LFLAGS "") # Private linker flags.
set(BLEND2D_SANITIZE_CFLAGS "${BLEND2D_SANITIZE_OPTS}") # Compiler flags required by currently enabled sanitizers.
set(BLEND2D_SANITIZE_LFLAGS "") # Linker flags required by currently enabled sanitizers.
set(BLEND2D_NO_STDCXX_CFLAGS "") # Private compiler flags to disable linking to a standard C++ library.
set(BLEND2D_NO_STDCXX_LFLAGS "") # Private linker flags to disable linking to a standard C++ library.

# Blend2D - Utilities
# ===================
Expand Down
38 changes: 32 additions & 6 deletions src/blend2d/pipeline/pipedefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,13 +306,39 @@ Signature initPatternAffine(FetchData::Pattern& fetchData, BLExtendMode extendMo
if (xy >= th_d) xy = fmod(xy, th_d);
}

fetchData.affine.xx.i64 = Math::floorToInt64(xx * fpScale);
fetchData.affine.xy.i64 = Math::floorToInt64(xy * fpScale);
fetchData.affine.yx.i64 = Math::floorToInt64(yx * fpScale);
fetchData.affine.yy.i64 = Math::floorToInt64(yy * fpScale);
xx *= fpScale;
xy *= fpScale;
yx *= fpScale;
yy *= fpScale;
tx *= fpScale;
ty *= fpScale;

// To prevent undefined behavior and thus passing invalid integer coordinates to the fetcher, we have to verify that
// double to int64 conversion is actually valid. To do that we simply combine min/max in a way to always propagate
// NaNs in case there is any.
double allMin = blMin(blMin(yy, yx), blMin(xy, xx));
double allMax = blMax(blMax(xx, xy), blMax(yx, yy));

allMin = blMin(allMin, blMin(ty, tx));
allMax = blMax(blMax(tx, ty), allMax);

if (allMin >= double(INT64_MIN + 1) && allMax <= double(INT64_MAX)) {
fetchData.affine.xx.i64 = Math::floorToInt64(xx);
fetchData.affine.xy.i64 = Math::floorToInt64(xy);
fetchData.affine.yx.i64 = Math::floorToInt64(yx);
fetchData.affine.yy.i64 = Math::floorToInt64(yy);
fetchData.affine.tx.i64 = Math::floorToInt64(tx);
fetchData.affine.ty.i64 = Math::floorToInt64(ty);
}
else {
fetchData.affine.xx.i64 = 0;
fetchData.affine.xy.i64 = 0;
fetchData.affine.yx.i64 = 0;
fetchData.affine.yy.i64 = 0;
fetchData.affine.tx.i64 = 0;
fetchData.affine.ty.i64 = 0;
}

fetchData.affine.tx.i64 = Math::floorToInt64(tx * fpScale);
fetchData.affine.ty.i64 = Math::floorToInt64(ty * fpScale);
fetchData.affine.rx.i64 = IntOps::shl(int64_t(rx), 32);
fetchData.affine.ry.i64 = IntOps::shl(int64_t(ry), 32);

Expand Down

0 comments on commit 5a263ce

Please sign in to comment.