toolkit/crashreporter/google-breakpad/src/common/test_assembler.cc

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 // Copyright (c) 2010, Google Inc.
michael@0 2 // All rights reserved.
michael@0 3 //
michael@0 4 // Redistribution and use in source and binary forms, with or without
michael@0 5 // modification, are permitted provided that the following conditions are
michael@0 6 // met:
michael@0 7 //
michael@0 8 // * Redistributions of source code must retain the above copyright
michael@0 9 // notice, this list of conditions and the following disclaimer.
michael@0 10 // * Redistributions in binary form must reproduce the above
michael@0 11 // copyright notice, this list of conditions and the following disclaimer
michael@0 12 // in the documentation and/or other materials provided with the
michael@0 13 // distribution.
michael@0 14 // * Neither the name of Google Inc. nor the names of its
michael@0 15 // contributors may be used to endorse or promote products derived from
michael@0 16 // this software without specific prior written permission.
michael@0 17 //
michael@0 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
michael@0 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@0 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@0 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
michael@0 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
michael@0 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
michael@0 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 29
michael@0 30 // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
michael@0 31
michael@0 32 // test_assembler.cc: Implementation of google_breakpad::TestAssembler.
michael@0 33 // See test_assembler.h for details.
michael@0 34
michael@0 35 #include "common/test_assembler.h"
michael@0 36
michael@0 37 #include <assert.h>
michael@0 38 #include <stdio.h>
michael@0 39
michael@0 40 #include <iterator>
michael@0 41
michael@0 42 namespace google_breakpad {
michael@0 43 namespace test_assembler {
michael@0 44
michael@0 45 using std::back_insert_iterator;
michael@0 46
michael@0 47 Label::Label() : value_(new Binding()) { }
michael@0 48 Label::Label(uint64_t value) : value_(new Binding(value)) { }
michael@0 49 Label::Label(const Label &label) {
michael@0 50 value_ = label.value_;
michael@0 51 value_->Acquire();
michael@0 52 }
michael@0 53 Label::~Label() {
michael@0 54 if (value_->Release()) delete value_;
michael@0 55 }
michael@0 56
michael@0 57 Label &Label::operator=(uint64_t value) {
michael@0 58 value_->Set(NULL, value);
michael@0 59 return *this;
michael@0 60 }
michael@0 61
michael@0 62 Label &Label::operator=(const Label &label) {
michael@0 63 value_->Set(label.value_, 0);
michael@0 64 return *this;
michael@0 65 }
michael@0 66
michael@0 67 Label Label::operator+(uint64_t addend) const {
michael@0 68 Label l;
michael@0 69 l.value_->Set(this->value_, addend);
michael@0 70 return l;
michael@0 71 }
michael@0 72
michael@0 73 Label Label::operator-(uint64_t subtrahend) const {
michael@0 74 Label l;
michael@0 75 l.value_->Set(this->value_, -subtrahend);
michael@0 76 return l;
michael@0 77 }
michael@0 78
michael@0 79 // When NDEBUG is #defined, assert doesn't evaluate its argument. This
michael@0 80 // means you can't simply use assert to check the return value of a
michael@0 81 // function with necessary side effects.
michael@0 82 //
michael@0 83 // ALWAYS_EVALUATE_AND_ASSERT(x) evaluates x regardless of whether
michael@0 84 // NDEBUG is #defined; when NDEBUG is not #defined, it further asserts
michael@0 85 // that x is true.
michael@0 86 #ifdef NDEBUG
michael@0 87 #define ALWAYS_EVALUATE_AND_ASSERT(x) x
michael@0 88 #else
michael@0 89 #define ALWAYS_EVALUATE_AND_ASSERT(x) assert(x)
michael@0 90 #endif
michael@0 91
michael@0 92 uint64_t Label::operator-(const Label &label) const {
michael@0 93 uint64_t offset;
michael@0 94 ALWAYS_EVALUATE_AND_ASSERT(IsKnownOffsetFrom(label, &offset));
michael@0 95 return offset;
michael@0 96 }
michael@0 97
michael@0 98 uint64_t Label::Value() const {
michael@0 99 uint64_t v = 0;
michael@0 100 ALWAYS_EVALUATE_AND_ASSERT(IsKnownConstant(&v));
michael@0 101 return v;
michael@0 102 };
michael@0 103
michael@0 104 bool Label::IsKnownConstant(uint64_t *value_p) const {
michael@0 105 Binding *base;
michael@0 106 uint64_t addend;
michael@0 107 value_->Get(&base, &addend);
michael@0 108 if (base != NULL) return false;
michael@0 109 if (value_p) *value_p = addend;
michael@0 110 return true;
michael@0 111 }
michael@0 112
michael@0 113 bool Label::IsKnownOffsetFrom(const Label &label, uint64_t *offset_p) const
michael@0 114 {
michael@0 115 Binding *label_base, *this_base;
michael@0 116 uint64_t label_addend, this_addend;
michael@0 117 label.value_->Get(&label_base, &label_addend);
michael@0 118 value_->Get(&this_base, &this_addend);
michael@0 119 // If this and label are related, Get will find their final
michael@0 120 // common ancestor, regardless of how indirect the relation is. This
michael@0 121 // comparison also handles the constant vs. constant case.
michael@0 122 if (this_base != label_base) return false;
michael@0 123 if (offset_p) *offset_p = this_addend - label_addend;
michael@0 124 return true;
michael@0 125 }
michael@0 126
michael@0 127 Label::Binding::Binding() : base_(this), addend_(), reference_count_(1) { }
michael@0 128
michael@0 129 Label::Binding::Binding(uint64_t addend)
michael@0 130 : base_(NULL), addend_(addend), reference_count_(1) { }
michael@0 131
michael@0 132 Label::Binding::~Binding() {
michael@0 133 assert(reference_count_ == 0);
michael@0 134 if (base_ && base_ != this && base_->Release())
michael@0 135 delete base_;
michael@0 136 }
michael@0 137
michael@0 138 void Label::Binding::Set(Binding *binding, uint64_t addend) {
michael@0 139 if (!base_ && !binding) {
michael@0 140 // We're equating two constants. This could be okay.
michael@0 141 assert(addend_ == addend);
michael@0 142 } else if (!base_) {
michael@0 143 // We are a known constant, but BINDING may not be, so turn the
michael@0 144 // tables and try to set BINDING's value instead.
michael@0 145 binding->Set(NULL, addend_ - addend);
michael@0 146 } else {
michael@0 147 if (binding) {
michael@0 148 // Find binding's final value. Since the final value is always either
michael@0 149 // completely unconstrained or a constant, never a reference to
michael@0 150 // another variable (otherwise, it wouldn't be final), this
michael@0 151 // guarantees we won't create cycles here, even for code like this:
michael@0 152 // l = m, m = n, n = l;
michael@0 153 uint64_t binding_addend;
michael@0 154 binding->Get(&binding, &binding_addend);
michael@0 155 addend += binding_addend;
michael@0 156 }
michael@0 157
michael@0 158 // It seems likely that setting a binding to itself is a bug
michael@0 159 // (although I can imagine this might turn out to be helpful to
michael@0 160 // permit).
michael@0 161 assert(binding != this);
michael@0 162
michael@0 163 if (base_ != this) {
michael@0 164 // Set the other bindings on our chain as well. Note that this
michael@0 165 // is sufficient even though binding relationships form trees:
michael@0 166 // All binding operations traverse their chains to the end, and
michael@0 167 // all bindings related to us share some tail of our chain, so
michael@0 168 // they will see the changes we make here.
michael@0 169 base_->Set(binding, addend - addend_);
michael@0 170 // We're not going to use base_ any more.
michael@0 171 if (base_->Release()) delete base_;
michael@0 172 }
michael@0 173
michael@0 174 // Adopt BINDING as our base. Note that it should be correct to
michael@0 175 // acquire here, after the release above, even though the usual
michael@0 176 // reference-counting rules call for acquiring first, and then
michael@0 177 // releasing: the self-reference assertion above should have
michael@0 178 // complained if BINDING were 'this' or anywhere along our chain,
michael@0 179 // so we didn't release BINDING.
michael@0 180 if (binding) binding->Acquire();
michael@0 181 base_ = binding;
michael@0 182 addend_ = addend;
michael@0 183 }
michael@0 184 }
michael@0 185
michael@0 186 void Label::Binding::Get(Binding **base, uint64_t *addend) {
michael@0 187 if (base_ && base_ != this) {
michael@0 188 // Recurse to find the end of our reference chain (the root of our
michael@0 189 // tree), and then rewrite every binding along the chain to refer
michael@0 190 // to it directly, adjusting addends appropriately. (This is why
michael@0 191 // this member function isn't this-const.)
michael@0 192 Binding *final_base;
michael@0 193 uint64_t final_addend;
michael@0 194 base_->Get(&final_base, &final_addend);
michael@0 195 if (final_base) final_base->Acquire();
michael@0 196 if (base_->Release()) delete base_;
michael@0 197 base_ = final_base;
michael@0 198 addend_ += final_addend;
michael@0 199 }
michael@0 200 *base = base_;
michael@0 201 *addend = addend_;
michael@0 202 }
michael@0 203
michael@0 204 template<typename Inserter>
michael@0 205 static inline void InsertEndian(test_assembler::Endianness endianness,
michael@0 206 size_t size, uint64_t number, Inserter dest) {
michael@0 207 assert(size > 0);
michael@0 208 if (endianness == kLittleEndian) {
michael@0 209 for (size_t i = 0; i < size; i++) {
michael@0 210 *dest++ = (char) (number & 0xff);
michael@0 211 number >>= 8;
michael@0 212 }
michael@0 213 } else {
michael@0 214 assert(endianness == kBigEndian);
michael@0 215 // The loop condition is odd, but it's correct for size_t.
michael@0 216 for (size_t i = size - 1; i < size; i--)
michael@0 217 *dest++ = (char) ((number >> (i * 8)) & 0xff);
michael@0 218 }
michael@0 219 }
michael@0 220
michael@0 221 Section &Section::Append(Endianness endianness, size_t size, uint64_t number) {
michael@0 222 InsertEndian(endianness, size, number,
michael@0 223 back_insert_iterator<string>(contents_));
michael@0 224 return *this;
michael@0 225 }
michael@0 226
michael@0 227 Section &Section::Append(Endianness endianness, size_t size,
michael@0 228 const Label &label) {
michael@0 229 // If this label's value is known, there's no reason to waste an
michael@0 230 // entry in references_ on it.
michael@0 231 uint64_t value;
michael@0 232 if (label.IsKnownConstant(&value))
michael@0 233 return Append(endianness, size, value);
michael@0 234
michael@0 235 // This will get caught when the references are resolved, but it's
michael@0 236 // nicer to find out earlier.
michael@0 237 assert(endianness != kUnsetEndian);
michael@0 238
michael@0 239 references_.push_back(Reference(contents_.size(), endianness, size, label));
michael@0 240 contents_.append(size, 0);
michael@0 241 return *this;
michael@0 242 }
michael@0 243
michael@0 244 #define ENDIANNESS_L kLittleEndian
michael@0 245 #define ENDIANNESS_B kBigEndian
michael@0 246 #define ENDIANNESS(e) ENDIANNESS_ ## e
michael@0 247
michael@0 248 #define DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \
michael@0 249 Section &Section::e ## bits(uint ## bits ## _t v) { \
michael@0 250 InsertEndian(ENDIANNESS(e), bits / 8, v, \
michael@0 251 back_insert_iterator<string>(contents_)); \
michael@0 252 return *this; \
michael@0 253 }
michael@0 254
michael@0 255 #define DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) \
michael@0 256 Section &Section::e ## bits(const Label &v) { \
michael@0 257 return Append(ENDIANNESS(e), bits / 8, v); \
michael@0 258 }
michael@0 259
michael@0 260 // Define L16, B32, and friends.
michael@0 261 #define DEFINE_SHORT_APPEND_ENDIAN(e, bits) \
michael@0 262 DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \
michael@0 263 DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits)
michael@0 264
michael@0 265 DEFINE_SHORT_APPEND_LABEL_ENDIAN(L, 8);
michael@0 266 DEFINE_SHORT_APPEND_LABEL_ENDIAN(B, 8);
michael@0 267 DEFINE_SHORT_APPEND_ENDIAN(L, 16);
michael@0 268 DEFINE_SHORT_APPEND_ENDIAN(L, 32);
michael@0 269 DEFINE_SHORT_APPEND_ENDIAN(L, 64);
michael@0 270 DEFINE_SHORT_APPEND_ENDIAN(B, 16);
michael@0 271 DEFINE_SHORT_APPEND_ENDIAN(B, 32);
michael@0 272 DEFINE_SHORT_APPEND_ENDIAN(B, 64);
michael@0 273
michael@0 274 #define DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \
michael@0 275 Section &Section::D ## bits(uint ## bits ## _t v) { \
michael@0 276 InsertEndian(endianness_, bits / 8, v, \
michael@0 277 back_insert_iterator<string>(contents_)); \
michael@0 278 return *this; \
michael@0 279 }
michael@0 280 #define DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) \
michael@0 281 Section &Section::D ## bits(const Label &v) { \
michael@0 282 return Append(endianness_, bits / 8, v); \
michael@0 283 }
michael@0 284 #define DEFINE_SHORT_APPEND_DEFAULT(bits) \
michael@0 285 DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \
michael@0 286 DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits)
michael@0 287
michael@0 288 DEFINE_SHORT_APPEND_LABEL_DEFAULT(8)
michael@0 289 DEFINE_SHORT_APPEND_DEFAULT(16);
michael@0 290 DEFINE_SHORT_APPEND_DEFAULT(32);
michael@0 291 DEFINE_SHORT_APPEND_DEFAULT(64);
michael@0 292
michael@0 293 Section &Section::Append(const Section &section) {
michael@0 294 size_t base = contents_.size();
michael@0 295 contents_.append(section.contents_);
michael@0 296 for (vector<Reference>::const_iterator it = section.references_.begin();
michael@0 297 it != section.references_.end(); it++)
michael@0 298 references_.push_back(Reference(base + it->offset, it->endianness,
michael@0 299 it->size, it->label));
michael@0 300 return *this;
michael@0 301 }
michael@0 302
michael@0 303 Section &Section::LEB128(long long value) {
michael@0 304 while (value < -0x40 || 0x3f < value) {
michael@0 305 contents_ += (value & 0x7f) | 0x80;
michael@0 306 if (value < 0)
michael@0 307 value = (value >> 7) | ~(((unsigned long long) -1) >> 7);
michael@0 308 else
michael@0 309 value = (value >> 7);
michael@0 310 }
michael@0 311 contents_ += value & 0x7f;
michael@0 312 return *this;
michael@0 313 }
michael@0 314
michael@0 315 Section &Section::ULEB128(uint64_t value) {
michael@0 316 while (value > 0x7f) {
michael@0 317 contents_ += (value & 0x7f) | 0x80;
michael@0 318 value = (value >> 7);
michael@0 319 }
michael@0 320 contents_ += value;
michael@0 321 return *this;
michael@0 322 }
michael@0 323
michael@0 324 Section &Section::Align(size_t alignment, uint8_t pad_byte) {
michael@0 325 // ALIGNMENT must be a power of two.
michael@0 326 assert(((alignment - 1) & alignment) == 0);
michael@0 327 size_t new_size = (contents_.size() + alignment - 1) & ~(alignment - 1);
michael@0 328 contents_.append(new_size - contents_.size(), pad_byte);
michael@0 329 assert((contents_.size() & (alignment - 1)) == 0);
michael@0 330 return *this;
michael@0 331 }
michael@0 332
michael@0 333 void Section::Clear() {
michael@0 334 contents_.clear();
michael@0 335 references_.clear();
michael@0 336 }
michael@0 337
michael@0 338 bool Section::GetContents(string *contents) {
michael@0 339 // For each label reference, find the label's value, and patch it into
michael@0 340 // the section's contents.
michael@0 341 for (size_t i = 0; i < references_.size(); i++) {
michael@0 342 Reference &r = references_[i];
michael@0 343 uint64_t value;
michael@0 344 if (!r.label.IsKnownConstant(&value)) {
michael@0 345 fprintf(stderr, "Undefined label #%zu at offset 0x%zx\n", i, r.offset);
michael@0 346 return false;
michael@0 347 }
michael@0 348 assert(r.offset < contents_.size());
michael@0 349 assert(contents_.size() - r.offset >= r.size);
michael@0 350 InsertEndian(r.endianness, r.size, value, contents_.begin() + r.offset);
michael@0 351 }
michael@0 352 contents->clear();
michael@0 353 std::swap(contents_, *contents);
michael@0 354 references_.clear();
michael@0 355 return true;
michael@0 356 }
michael@0 357
michael@0 358 } // namespace test_assembler
michael@0 359 } // namespace google_breakpad

mercurial