Sat, 03 Jan 2015 20:18:00 +0100
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 §ion) { |
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 |