diff options
author | zmiao <miao.zhao@mapbox.com> | 2020-04-07 16:30:30 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-07 16:30:30 +0300 |
commit | bf4c7340f32c1e673e6a37b91fc65305757f52d1 (patch) | |
tree | c7871ff8901617b09d8a8d45b57334c2198b9b99 | |
parent | 8986b558eb92e431c773b6033d8ae271eb71de00 (diff) |
[build] Fix undefined behavour sanitizer (#16375)
* [build] Fix integer overflow runtime error for core part
Temporarily remove circle ci UBSAN build precondition
* [build] Enable all of the ubsans
[build] Check runtime error
[build] Update UBSAN_OPTION
* [build] Add UBSAN blacklist
[build] Ignore system libraries
[build] Ignore vendor library
* [build] Fix implicit conversion runtime error in core
* [build] Fix division by zero runtime error
* [build] Add unfixed error to ubsan blacklist
* [build] Make UBSAN halt on error
Revert "Temporary remove build precondition"
* [build] Fix division by zero error
* [build] Make UBSAN officially work without FIXME prefix
* [build] Fix implicit conversion from int64_t to uint64_t
* [build] Rename style test json file name
* Address review findings
21 files changed, 110 insertions, 51 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fdd98a41..89096358d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,8 @@ add_library( mbgl-compiler-options INTERFACE ) +set(UBSAN_BLACKLIST ${PROJECT_SOURCE_DIR}/scripts/ubsan.blacklist) + target_compile_options( mbgl-compiler-options INTERFACE @@ -36,9 +38,16 @@ target_compile_options( $<$<BOOL:${MBGL_WITH_SANITIZER}>:-fno-optimize-sibling-calls> $<$<STREQUAL:${MBGL_WITH_SANITIZER},address>:-fsanitize=address> $<$<STREQUAL:${MBGL_WITH_SANITIZER},thread>:-fsanitize=thread> - $<$<STREQUAL:${MBGL_WITH_SANITIZER},undefined>:-fsanitize=implicit-conversion> - $<$<STREQUAL:${MBGL_WITH_SANITIZER},undefined>:-fsanitize=undefined> - $<$<STREQUAL:${MBGL_WITH_SANITIZER},undefined>:-fsanitize=unsigned-integer-overflow> + $<$<STREQUAL:${MBGL_WITH_SANITIZER},undefined>:-fsanitize=implicit-conversion, + -fsanitize-blacklist=${UBSAN_BLACKLIST}> + $<$<STREQUAL:${MBGL_WITH_SANITIZER},undefined>:-fsanitize=undefined, + -fsanitize-blacklist=${UBSAN_BLACKLIST}> + $<$<STREQUAL:${MBGL_WITH_SANITIZER},undefined>:-fsanitize=unsigned-integer-overflow, + -fsanitize-blacklist=${UBSAN_BLACKLIST}> + $<$<STREQUAL:${MBGL_WITH_SANITIZER},undefined>:-fsanitize=nullability, + -fsanitize-blacklist=${UBSAN_BLACKLIST}> + $<$<STREQUAL:${MBGL_WITH_SANITIZER},undefined>:-fsanitize=float-divide-by-zero, + -fsanitize-blacklist=${UBSAN_BLACKLIST}> $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<NOT:$<BOOL:${MBGL_WITH_RTTI}>>>:-fno-rtti> $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<NOT:$<PLATFORM_ID:Windows>>>:-Wall> $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<NOT:$<PLATFORM_ID:Windows>>>:-Wshadow> diff --git a/circle.yml b/circle.yml index 9ef993977..0617389f9 100644 --- a/circle.yml +++ b/circle.yml @@ -114,13 +114,12 @@ workflows: config_params: '-G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER=clang-8 -DCMAKE_CXX_COMPILER=clang++-8 -DCMAKE_CXX_FLAGS=-DSANITIZE' test_params: '-j 4 -E "mbgl-node|gl-benchmark" -D ExperimentalMemCheck || true' - build-template: - name: FIXME-linux-ubsan + name: linux-ubsan executor_name: ubuntu-disco target_is_linux: true requires: - sanity-checks config_params: '-G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER=clang-8 -DCMAKE_CXX_COMPILER=clang++-8 -DMBGL_WITH_SANITIZER=undefined' - test_params: '|| true' style_tests: true - build-template: name: qt5-linux-gcc5-release @@ -244,7 +243,7 @@ executors: working_directory: /src environment: DISPLAY: :99 - UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=0 + UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1:report_error_type=1 ASAN_OPTIONS: strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:halt_on_error=0 QT_INSTALL_DOCS: /usr/share/qt5/doc QT_VERSION: 5 diff --git a/metrics/FIXME-linux-ubsan-style.json b/metrics/linux-ubsan-style.json index 7c99b2784..7c99b2784 100644 --- a/metrics/FIXME-linux-ubsan-style.json +++ b/metrics/linux-ubsan-style.json diff --git a/platform/default/src/mbgl/storage/offline_database.cpp b/platform/default/src/mbgl/storage/offline_database.cpp index ff283ed10..084b99052 100644 --- a/platform/default/src/mbgl/storage/offline_database.cpp +++ b/platform/default/src/mbgl/storage/offline_database.cpp @@ -1275,7 +1275,8 @@ bool OfflineDatabase::evict(uint64_t neededFreeSize, DatabaseSizeChangeStats& st const uint64_t tileChanges = tileQuery.changes(); // Update current ambient cache size, based on how many bytes were released. - newAmbientCacheSize = std::max<int64_t>(newAmbientCacheSize - stats.bytesReleased(), 0u); + newAmbientCacheSize = std::max<int64_t>( + static_cast<int64_t>(newAmbientCacheSize) - static_cast<int64_t>(stats.bytesReleased()), 0u); // The cached value of offlineTileCount does not need to be updated // here because only non-offline tiles can be removed by eviction. @@ -1465,9 +1466,9 @@ uint64_t OfflineDatabase::DatabaseSizeChangeStats::pageSize() const { } int64_t OfflineDatabase::DatabaseSizeChangeStats::diff() const { - const uint64_t currentSize = - pageSize_ * (db->getPragma<int64_t>("PRAGMA page_count") - db->getPragma<int64_t>("PRAGMA freelist_count")); - return currentSize - initialSize_; + const int64_t currentSize = static_cast<int64_t>(pageSize_) * (db->getPragma<int64_t>("PRAGMA page_count") - + db->getPragma<int64_t>("PRAGMA freelist_count")); + return currentSize - static_cast<int64_t>(initialSize_); } uint64_t OfflineDatabase::DatabaseSizeChangeStats::bytesReleased() const { @@ -1478,7 +1479,7 @@ uint64_t OfflineDatabase::DatabaseSizeChangeStats::bytesReleased() const { void OfflineDatabase::updateAmbientCacheSize(DatabaseSizeChangeStats& stats) { assert(currentAmbientCacheSize); if (currentAmbientCacheSize) { - *currentAmbientCacheSize = std::max<int64_t>(*currentAmbientCacheSize + stats.diff(), 0u); + *currentAmbientCacheSize = std::max<int64_t>(static_cast<int64_t>(*currentAmbientCacheSize) + stats.diff(), 0u); } } diff --git a/platform/default/src/mbgl/util/image.cpp b/platform/default/src/mbgl/util/image.cpp index 25063892b..7d36dbd54 100644 --- a/platform/default/src/mbgl/util/image.cpp +++ b/platform/default/src/mbgl/util/image.cpp @@ -12,7 +12,8 @@ PremultipliedImage decodeImage(const std::string& string) { const size_t size = string.size(); if (size >= 4) { - uint32_t magic = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + uint32_t magic = (static_cast<uint32_t>(data[0]) << 24) | (static_cast<uint32_t>(data[1]) << 16) | + (static_cast<uint32_t>(data[2]) << 8) | static_cast<uint32_t>(data[3]); if (magic == 0x89504E47U) { return decodePNG(data, size); } diff --git a/platform/default/src/mbgl/util/timer.cpp b/platform/default/src/mbgl/util/timer.cpp index 90a85bfc1..f59b35284 100644 --- a/platform/default/src/mbgl/util/timer.cpp +++ b/platform/default/src/mbgl/util/timer.cpp @@ -60,8 +60,8 @@ Timer::Timer() Timer::~Timer() = default; void Timer::start(Duration timeout, Duration repeat, std::function<void()>&& cb) { - impl->start(std::chrono::duration_cast<Milliseconds>(timeout).count(), - std::chrono::duration_cast<Milliseconds>(repeat).count(), + impl->start(static_cast<uint64_t>(std::chrono::duration_cast<Milliseconds>(timeout).count()), + static_cast<uint64_t>(std::chrono::duration_cast<Milliseconds>(repeat).count()), std::move(cb)); } diff --git a/scripts/ubsan.blacklist b/scripts/ubsan.blacklist new file mode 100644 index 000000000..2248b0001 --- /dev/null +++ b/scripts/ubsan.blacklist @@ -0,0 +1,28 @@ +############################################################################# +# Ignore system libraries. +src:*/usr/* + +############################################################################# +# Mostly hash functions where integer overflow is OK. +src:*/mbgl/util/hash.hpp + +############################################################################# +# vendor libs + +# unsigned integer overflow: unsigned interger index in for loop +src:*/vendor/earcut.hpp/include/mapbox/earcut.hpp + +# unsigned integer overflow: hash function: str_hash +src:*/vendor/eternal/*/eternal.hpp + +# unsigned integer overflow +src:*/vendor/*/rapidjson/reader.h + +# division by zero: ill usage of test data in 'render-tests/filter/in', latitude shouldn't be +/-90 +src:*/vendor/*/geojsonvt/convert.hpp + +# Boost bug: Implicit conversion +src:*/include/boost/locale/utf.hpp + +# Boost bug: unsigned integer overflow +src:*/include/boost/crc.hpp
\ No newline at end of file diff --git a/src/mbgl/geometry/line_atlas.cpp b/src/mbgl/geometry/line_atlas.cpp index 6ddf16af0..2042195b6 100644 --- a/src/mbgl/geometry/line_atlas.cpp +++ b/src/mbgl/geometry/line_atlas.cpp @@ -54,13 +54,17 @@ void addRoundDash( if (ranges.empty()) return; for (int y = -n; y <= n; y++) { - int row = yOffset + n + y; + int row = static_cast<int32_t>(yOffset) + n + y; const uint32_t index = image.size.width * row; uint32_t currIndex = 0; DashRange range = ranges[currIndex]; for (uint32_t x = 0; x < image.size.width; ++x) { - if (x / range.right > 1.0f && ++currIndex < ranges.size()) { + if (range.right == 0) { + if (x != 0 && ++currIndex < ranges.size()) { + range = ranges[currIndex]; + } + } else if (x / range.right > 1.0f && ++currIndex < ranges.size()) { range = ranges[currIndex]; } diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index 0a1c3c4fb..d996041eb 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -738,10 +738,12 @@ std::vector<float> SymbolLayout::calculateTileDistances(const GeometryCoordinate sumForwardLength += util::dist<float>(line[i + 1], line[i]); } } - for (std::size_t i = ++segment; i-- > 0;) { + for (std::size_t i = segment;; --i) { tileDistances[i] = sumBackwardLength; if (i != 0u) { sumBackwardLength += util::dist<float>(line[i - 1], line[i]); + } else { + break; // Add break to avoid unsigned integer overflow when i==0 } } } diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index 1894c59e2..0333f4860 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -70,8 +70,11 @@ void TransformState::matrixFor(mat4& matrix, const UnwrappedTileID& tileID) cons const double s = Projection::worldSize(scale) / tileScale; matrix::identity(matrix); - matrix::translate( - matrix, matrix, int64_t(tileID.canonical.x + tileID.wrap * tileScale) * s, int64_t(tileID.canonical.y) * s, 0); + matrix::translate(matrix, + matrix, + int64_t(tileID.canonical.x + tileID.wrap * static_cast<int64_t>(tileScale)) * s, + int64_t(tileID.canonical.y) * s, + 0); matrix::scale(matrix, matrix, s / util::EXTENT, s / util::EXTENT, 1); } diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index af5c28870..b03ac8027 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -242,7 +242,7 @@ GeometryCollection offsetLine(const GeometryCollection& rings, double offset) { Point<double> extrude = util::unit(aToB + bToC); const double cosHalfAngle = extrude.x * bToC.x + extrude.y * bToC.y; - extrude *= (1.0 / cosHalfAngle); + extrude *= (cosHalfAngle != 0) ? (1.0 / cosHalfAngle) : 0; newRing.emplace_back(convertPoint<int16_t>(extrude * offset) + p); } diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index cdb85385e..aeba4b5ee 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -108,8 +108,8 @@ void Renderer::Impl::render(const RenderTree& renderTree) { } parameters.staticData.depthRenderbuffer->setShouldClear(true); - uint32_t i = static_cast<uint32_t>(layerRenderItems.size()) - 1; - for (auto it = layerRenderItems.begin(); it != layerRenderItems.end(); ++it, --i) { + int32_t i = static_cast<int32_t>(layerRenderItems.size()) - 1; + for (auto it = layerRenderItems.begin(); it != layerRenderItems.end() && i >= 0; ++it, --i) { parameters.currentLayer = i; const RenderItem& renderItem = it->get(); if (renderItem.hasRenderPass(parameters.pass)) { @@ -159,8 +159,8 @@ void Renderer::Impl::render(const RenderTree& renderTree) { parameters.pass = RenderPass::Translucent; const auto debugGroup(parameters.renderPass->createDebugGroup("translucent")); - uint32_t i = static_cast<uint32_t>(layerRenderItems.size()) - 1; - for (auto it = layerRenderItems.begin(); it != layerRenderItems.end(); ++it, --i) { + int32_t i = static_cast<int32_t>(layerRenderItems.size()) - 1; + for (auto it = layerRenderItems.begin(); it != layerRenderItems.end() && i >= 0; ++it, --i) { parameters.currentLayer = i; const RenderItem& renderItem = it->get(); if (renderItem.hasRenderPass(parameters.pass)) { diff --git a/src/mbgl/sprite/sprite_parser.cpp b/src/mbgl/sprite/sprite_parser.cpp index ac0b7f91f..997e363e5 100644 --- a/src/mbgl/sprite/sprite_parser.cpp +++ b/src/mbgl/sprite/sprite_parser.cpp @@ -17,21 +17,22 @@ namespace mbgl { std::unique_ptr<style::Image> createStyleImage(const std::string& id, const PremultipliedImage& image, - const uint32_t srcX, - const uint32_t srcY, - const uint32_t width, - const uint32_t height, + const int32_t srcX, + const int32_t srcY, + const int32_t width, + const int32_t height, const double ratio, const bool sdf, style::ImageStretches&& stretchX, style::ImageStretches&& stretchY, const optional<style::ImageContent>& content) { // Disallow invalid parameter configurations. - if (width <= 0 || height <= 0 || width > 1024 || height > 1024 || ratio <= 0 || ratio > 10 || - srcX >= image.size.width || srcY >= image.size.height || srcX + width > image.size.width || - srcY + height > image.size.height) { + if (width <= 0 || height <= 0 || width > 1024 || height > 1024 || ratio <= 0 || ratio > 10 || srcX < 0 || + srcY < 0 || srcX >= static_cast<int32_t>(image.size.width) || srcY >= static_cast<int32_t>(image.size.height) || + srcX + width > static_cast<int32_t>(image.size.width) || + srcY + height > static_cast<int32_t>(image.size.height)) { Log::Error(Event::Sprite, - "Can't create image with invalid metrics: %ux%u@%u,%u in %ux%u@%sx sprite", + "Can't create image with invalid metrics: %dx%d@%d,%d in %ux%u@%sx sprite", width, height, srcX, @@ -42,10 +43,11 @@ std::unique_ptr<style::Image> createStyleImage(const std::string& id, return nullptr; } - PremultipliedImage dstImage({width, height}); + const Size size(static_cast<uint32_t>(width), static_cast<uint32_t>(height)); + PremultipliedImage dstImage(size); // Copy from the source image into our individual sprite image - PremultipliedImage::copy(image, dstImage, {srcX, srcY}, {0, 0}, {width, height}); + PremultipliedImage::copy(image, dstImage, {static_cast<uint32_t>(srcX), static_cast<uint32_t>(srcY)}, {0, 0}, size); try { return std::make_unique<style::Image>( diff --git a/src/mbgl/sprite/sprite_parser.hpp b/src/mbgl/sprite/sprite_parser.hpp index 7d545a6d9..baba427f4 100644 --- a/src/mbgl/sprite/sprite_parser.hpp +++ b/src/mbgl/sprite/sprite_parser.hpp @@ -9,10 +9,10 @@ namespace mbgl { // Extracts an individual image from a spritesheet from the given location. std::unique_ptr<style::Image> createStyleImage(const std::string& id, const PremultipliedImage&, - uint32_t srcX, - uint32_t srcY, - uint32_t srcWidth, - uint32_t srcHeight, + int32_t srcX, + int32_t srcY, + int32_t srcWidth, + int32_t srcHeight, double ratio, bool sdf, style::ImageStretches&& stretchX = {}, diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp index 2477fe791..bae0258aa 100644 --- a/src/mbgl/style/expression/compound_expression.cpp +++ b/src/mbgl/style/expression/compound_expression.cpp @@ -15,6 +15,7 @@ #include <mapbox/eternal.hpp> #include <cmath> +#include <limits> namespace mbgl { namespace style { @@ -498,7 +499,15 @@ const auto& multiplyCompoundExpression() { } const auto& divideCompoundExpression() { - static auto signature = detail::makeSignature("/", [](double a, double b) -> Result<double> { return a / b; }); + static auto signature = detail::makeSignature("/", [](double a, double b) -> Result<double> { + if (b == 0) { + if (a == 0) return std::numeric_limits<double>::quiet_NaN(); + double inf = std::numeric_limits<double>::infinity(); + if (a > 0) return inf; + if (a < 0) return -inf; + } + return a / b; + }); return signature; } diff --git a/src/mbgl/text/tagged_string.cpp b/src/mbgl/text/tagged_string.cpp index b18ad4d14..9c374ae27 100644 --- a/src/mbgl/text/tagged_string.cpp +++ b/src/mbgl/text/tagged_string.cpp @@ -29,7 +29,7 @@ void TaggedString::addImageSection(const std::string& imageID) { styledText.first += *nextImageSectionCharCode; sections.emplace_back(imageID); - styledText.second.resize(styledText.first.size(), sections.size() - 1); + styledText.second.resize(styledText.first.size(), static_cast<uint8_t>(sections.size() - 1)); } optional<char16_t> TaggedString::getNextImageSectionCharCode() { diff --git a/src/mbgl/tile/raster_dem_tile.cpp b/src/mbgl/tile/raster_dem_tile.cpp index e3c8eed82..b70e581ea 100644 --- a/src/mbgl/tile/raster_dem_tile.cpp +++ b/src/mbgl/tile/raster_dem_tile.cpp @@ -84,8 +84,9 @@ HillshadeBucket* RasterDEMTile::getBucket() const { } void RasterDEMTile::backfillBorder(const RasterDEMTile& borderTile, const DEMTileNeighbors mask) { - int32_t dx = borderTile.id.canonical.x - id.canonical.x; - const int8_t dy = borderTile.id.canonical.y - id.canonical.y; + int32_t dx = static_cast<int32_t>(borderTile.id.canonical.x) - static_cast<int32_t>(id.canonical.x); + const auto dy = + static_cast<int8_t>(static_cast<int32_t>(borderTile.id.canonical.y) - static_cast<int32_t>(id.canonical.y)); const uint32_t dim = pow(2, id.canonical.z); if (dx == 0 && dy == 0) return; if (std::abs(dy) > 1) return; diff --git a/src/mbgl/util/premultiply.cpp b/src/mbgl/util/premultiply.cpp index d9fb2480d..02c045fbb 100644 --- a/src/mbgl/util/premultiply.cpp +++ b/src/mbgl/util/premultiply.cpp @@ -40,9 +40,9 @@ UnassociatedImage unpremultiply(PremultipliedImage&& src) { uint8_t& b = data[i + 2]; uint8_t& a = data[i + 3]; if (a) { - r = (255 * r + (a / 2)) / a; - g = (255 * g + (a / 2)) / a; - b = (255 * b + (a / 2)) / a; + r = static_cast<uint8_t>((255 * r + (a / 2)) / a); + g = static_cast<uint8_t>((255 * g + (a / 2)) / a); + b = static_cast<uint8_t>((255 * b + (a / 2)) / a); } } diff --git a/src/mbgl/util/tiny_sdf.cpp b/src/mbgl/util/tiny_sdf.cpp index 6edcd83bc..a71d04386 100644 --- a/src/mbgl/util/tiny_sdf.cpp +++ b/src/mbgl/util/tiny_sdf.cpp @@ -35,7 +35,7 @@ void edt1d(std::vector<double>& f, for (uint32_t q = 0, k = 0; q < n; q++) { while (z[k + 1] < q) k++; - d[q] = (q - v[k]) * (q - v[k]) + f[v[k]]; + d[q] = (static_cast<double>(q) - v[k]) * (static_cast<double>(q) - v[k]) + f[v[k]]; } } diff --git a/test/sprite/sprite_parser.test.cpp b/test/sprite/sprite_parser.test.cpp index 58979a0e6..db6f8fb5a 100644 --- a/test/sprite/sprite_parser.test.cpp +++ b/test/sprite/sprite_parser.test.cpp @@ -54,7 +54,7 @@ TEST(Sprite, SpriteImageCreationInvalid) { EventSeverity::Error, Event::Sprite, int64_t(-1), - "Can't create image with invalid metrics: 4294967295x16@0,0 in 200x299@1x sprite", + "Can't create image with invalid metrics: -1x16@0,0 in 200x299@1x sprite", })); EXPECT_EQ(0u, log.uncheckedCount()); @@ -64,7 +64,7 @@ TEST(Sprite, SpriteImageCreationInvalid) { EventSeverity::Error, Event::Sprite, int64_t(-1), - "Can't create image with invalid metrics: 16x4294967295@0,0 in 200x299@1x sprite", + "Can't create image with invalid metrics: 16x-1@0,0 in 200x299@1x sprite", })); EXPECT_EQ(0u, log.uncheckedCount()); @@ -124,7 +124,7 @@ TEST(Sprite, SpriteImageCreationInvalid) { EventSeverity::Error, Event::Sprite, int64_t(-1), - "Can't create image with invalid metrics: 16x16@4294967295,0 in 200x299@1x sprite", + "Can't create image with invalid metrics: 16x16@-1,0 in 200x299@1x sprite", })); EXPECT_EQ(0u, log.uncheckedCount()); @@ -134,7 +134,7 @@ TEST(Sprite, SpriteImageCreationInvalid) { EventSeverity::Error, Event::Sprite, int64_t(-1), - "Can't create image with invalid metrics: 16x16@0,4294967295 in 200x299@1x sprite", + "Can't create image with invalid metrics: 16x16@0,-1 in 200x299@1x sprite", })); EXPECT_EQ(0u, log.uncheckedCount()); diff --git a/test/storage/offline_database.test.cpp b/test/storage/offline_database.test.cpp index 146cb3353..6b444bf3d 100644 --- a/test/storage/offline_database.test.cpp +++ b/test/storage/offline_database.test.cpp @@ -34,7 +34,7 @@ static std::shared_ptr<std::string> randomString(size_t size) { std::mt19937 random; for (size_t i = 0; i < size; i++) { - (*result)[i] = random(); + (*result)[i] = static_cast<char>(random()); } return result; |