diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-08-24 12:15:48 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-08-28 13:30:04 +0000 |
commit | b014812705fc80bff0a5c120dfcef88f349816dc (patch) | |
tree | 25a2e2d9fa285f1add86aa333389a839f81a39ae /chromium/components/zucchini/imposed_ensemble_matcher.cc | |
parent | 9f4560b1027ae06fdb497023cdcaf91b8511fa74 (diff) | |
download | qtwebengine-chromium-b014812705fc80bff0a5c120dfcef88f349816dc.tar.gz |
BASELINE: Update Chromium to 68.0.3440.125
Change-Id: I23f19369e01f688e496f5bf179abb521ad73874f
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components/zucchini/imposed_ensemble_matcher.cc')
-rw-r--r-- | chromium/components/zucchini/imposed_ensemble_matcher.cc | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/chromium/components/zucchini/imposed_ensemble_matcher.cc b/chromium/components/zucchini/imposed_ensemble_matcher.cc new file mode 100644 index 00000000000..e735bc4e79e --- /dev/null +++ b/chromium/components/zucchini/imposed_ensemble_matcher.cc @@ -0,0 +1,143 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/zucchini/imposed_ensemble_matcher.h" + +#include <algorithm> +#include <sstream> +#include <utility> + +#include "base/bind.h" +#include "base/logging.h" +#include "components/zucchini/io_utils.h" + +namespace zucchini { + +/******** ImposedMatchParser ********/ + +ImposedMatchParser::ImposedMatchParser() = default; + +ImposedMatchParser::~ImposedMatchParser() = default; + +ImposedMatchParser::Status ImposedMatchParser::Parse( + std::string imposed_matches, + ConstBufferView old_image, + ConstBufferView new_image, + ElementDetector&& detector) { + CHECK(matches_.empty()); + CHECK(bad_matches_.empty()); + + // Parse |imposed_matches| and check bounds. + std::istringstream iss(std::move(imposed_matches)); + bool first = true; + iss.peek(); // Makes empty |iss| realize EOF is reached. + while (iss && !iss.eof()) { + // Eat delimiter. + if (first) { + first = false; + } else if (!(iss >> EatChar(','))) { + return kInvalidDelimiter; + } + // Extract parameters for one imposed match. + offset_t old_offset = 0U; + size_t old_size = 0U; + offset_t new_offset = 0U; + size_t new_size = 0U; + if (!(iss >> StrictUInt<offset_t>(old_offset) >> EatChar('+') >> + StrictUInt<size_t>(old_size) >> EatChar('=') >> + StrictUInt<offset_t>(new_offset) >> EatChar('+') >> + StrictUInt<size_t>(new_size))) { + return kParseError; + } + // Check bounds. + if (old_size == 0 || new_size == 0 || + !old_image.covers({old_offset, old_size}) || + !new_image.covers({new_offset, new_size})) { + return kOutOfBound; + } + matches_.push_back( + {{{old_offset, old_size}, kExeTypeUnknown}, // Assign type later. + {{new_offset, new_size}, kExeTypeUnknown}}); // Assign type later. + } + // Sort matches by "new" file offsets. This helps with overlap checks. + std::sort(matches_.begin(), matches_.end(), + [](const ElementMatch& match_a, const ElementMatch& match_b) { + return match_a.new_element.offset < match_b.new_element.offset; + }); + + // Check for overlaps in "new" file. + if (std::adjacent_find( + matches_.begin(), matches_.end(), + [](const ElementMatch& match1, const ElementMatch& match2) { + return match1.new_element.hi() > match2.new_element.lo(); + }) != matches_.end()) { + return kOverlapInNew; + } + + // Compute types and verify consistency. Remove identical matches and matches + // where any sub-image has an unknown type. + size_t write_idx = 0; + for (size_t read_idx = 0; read_idx < matches_.size(); ++read_idx) { + ConstBufferView old_sub_image( + old_image[matches_[read_idx].old_element.region()]); + ConstBufferView new_sub_image( + new_image[matches_[read_idx].new_element.region()]); + // Remove identical match. + if (old_sub_image.equals(new_sub_image)) { + ++num_identical_; + continue; + } + // Check executable types of sub-images. + base::Optional<Element> old_element = detector.Run(old_sub_image); + base::Optional<Element> new_element = detector.Run(new_sub_image); + if (!old_element || !new_element) { + // Skip unknown types, including those mixed with known types. + bad_matches_.push_back(matches_[read_idx]); + continue; + } else if (old_element->exe_type != new_element->exe_type) { + // Error if types are known, but inconsistent. + return kTypeMismatch; + } + + // Keep match and remove gaps. + matches_[read_idx].old_element.exe_type = old_element->exe_type; + matches_[read_idx].new_element.exe_type = new_element->exe_type; + if (write_idx < read_idx) + matches_[write_idx] = matches_[read_idx]; + ++write_idx; + } + matches_.resize(write_idx); + return kSuccess; +} + +/******** ImposedEnsembleMatcher ********/ + +ImposedEnsembleMatcher::ImposedEnsembleMatcher( + const std::string& imposed_matches) + : imposed_matches_(imposed_matches) {} + +ImposedEnsembleMatcher::~ImposedEnsembleMatcher() = default; + +bool ImposedEnsembleMatcher::RunMatch(ConstBufferView old_image, + ConstBufferView new_image) { + DCHECK(matches_.empty()); + LOG(INFO) << "Start matching."; + ImposedMatchParser parser; + ImposedMatchParser::Status status = + parser.Parse(std::move(imposed_matches_), old_image, new_image, + base::BindRepeating(DetectElementFromDisassembler)); + // Print all warnings first. + for (const ElementMatch& bad_match : *parser.mutable_bad_matches()) + LOG(WARNING) << "Skipped match with unknown type: " << bad_match.ToString(); + if (status != ImposedMatchParser::kSuccess) { + LOG(ERROR) << "Imposed match failed with error code " << status << "."; + return false; + } + num_identical_ = parser.num_identical(); + matches_ = std::move(*parser.mutable_matches()); + Trim(); + return true; +} + +} // namespace zucchini |