js/src/vm/SharedArrayObject.cpp

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.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "vm/SharedArrayObject.h"
     9 #include "jsprf.h"
    10 #include "jsobjinlines.h"
    12 #ifdef XP_WIN
    13 # include "jswin.h"
    14 #else
    15 # include <sys/mman.h>
    16 #endif
    18 #ifdef MOZ_VALGRIND
    19 # include <valgrind/memcheck.h>
    20 #endif
    22 #include "mozilla/Atomics.h"
    23 #include "jit/AsmJS.h"
    25 using namespace js;
    27 using mozilla::IsNaN;
    28 using mozilla::PodCopy;
    30 /*
    31  * SharedArrayRawBuffer
    32  */
    34 static inline void *
    35 MapMemory(size_t length, bool commit)
    36 {
    37 #ifdef XP_WIN
    38     int prot = (commit ? MEM_COMMIT : MEM_RESERVE);
    39     int flags = (commit ? PAGE_READWRITE : PAGE_NOACCESS);
    40     return VirtualAlloc(nullptr, length, prot, flags);
    41 #else
    42     int prot = (commit ? (PROT_READ | PROT_WRITE) : PROT_NONE);
    43     void *p = mmap(nullptr, length, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
    44     if (p == MAP_FAILED)
    45         return nullptr;
    46     return p;
    47 #endif
    48 }
    50 static inline void
    51 UnmapMemory(void *addr, size_t len)
    52 {
    53 #ifdef XP_WIN
    54     VirtualFree(addr, 0, MEM_RELEASE);
    55 #else
    56     munmap(addr, len);
    57 #endif
    58 }
    60 static inline bool
    61 MarkValidRegion(void *addr, size_t len)
    62 {
    63 #ifdef XP_WIN
    64     if (!VirtualAlloc(addr, len, MEM_COMMIT, PAGE_READWRITE))
    65         return false;
    66     return true;
    67 #else
    68     if (mprotect(addr, len, PROT_READ | PROT_WRITE))
    69         return false;
    70     return true;
    71 #endif
    72 }
    74 SharedArrayRawBuffer *
    75 SharedArrayRawBuffer::New(uint32_t length)
    76 {
    77     // Enforced by SharedArrayBufferObject constructor.
    78     JS_ASSERT(IsValidAsmJSHeapLength(length));
    80 #ifdef JS_CPU_X64
    81     // Get the entire reserved region (with all pages inaccessible)
    82     void *p = MapMemory(AsmJSMappedSize, false);
    83     if (!p)
    84         return nullptr;
    86     size_t validLength = AsmJSPageSize + length;
    87     if (!MarkValidRegion(p, validLength)) {
    88         UnmapMemory(p, AsmJSMappedSize);
    89         return nullptr;
    90     }
    91 #   if defined(MOZ_VALGRIND) && defined(VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE)
    92     // Tell Valgrind/Memcheck to not report accesses in the inaccessible region.
    93     VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE((unsigned char*)p + validLength,
    94                                                    AsmJSMappedSize-validLength);
    95 #   endif
    96 #else
    97     uint32_t allocSize = length + AsmJSPageSize;
    98     if (allocSize <= length)
    99         return nullptr;
   101     void *p = MapMemory(allocSize, true);
   102     if (!p)
   103         return nullptr;
   104 #endif
   105     uint8_t *buffer = reinterpret_cast<uint8_t*>(p) + AsmJSPageSize;
   106     uint8_t *base = buffer - sizeof(SharedArrayRawBuffer);
   107     return new (base) SharedArrayRawBuffer(buffer, length);
   108 }
   110 void
   111 SharedArrayRawBuffer::addReference()
   112 {
   113     JS_ASSERT(this->refcount > 0);
   114     ++this->refcount; // Atomic.
   115 }
   117 void
   118 SharedArrayRawBuffer::dropReference()
   119 {
   120     // Drop the reference to the buffer.
   121     uint32_t refcount = --this->refcount; // Atomic.
   123     // If this was the final reference, release the buffer.
   124     if (refcount == 0) {
   125         uint8_t *p = this->dataPointer() - AsmJSPageSize;
   126         JS_ASSERT(uintptr_t(p) % AsmJSPageSize == 0);
   127 #ifdef JS_CPU_X64
   128         UnmapMemory(p, AsmJSMappedSize);
   129 #       if defined(MOZ_VALGRIND) \
   130            && defined(VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE)
   131         // Tell Valgrind/Memcheck to recommence reporting accesses in the
   132         // previously-inaccessible region.
   133         if (AsmJSMappedSize > 0) {
   134             VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(p, AsmJSMappedSize);
   135         }
   136 #       endif
   137 #else
   138         UnmapMemory(p, this->length + AsmJSPageSize);
   139 #endif
   140     }
   141 }
   143 /*
   144  * SharedArrayBufferObject
   145  */
   146 bool
   147 js::IsSharedArrayBuffer(HandleValue v)
   148 {
   149     return v.isObject() && v.toObject().is<SharedArrayBufferObject>();
   150 }
   152 MOZ_ALWAYS_INLINE bool
   153 SharedArrayBufferObject::byteLengthGetterImpl(JSContext *cx, CallArgs args)
   154 {
   155     JS_ASSERT(IsSharedArrayBuffer(args.thisv()));
   156     args.rval().setInt32(args.thisv().toObject().as<SharedArrayBufferObject>().byteLength());
   157     return true;
   158 }
   160 bool
   161 SharedArrayBufferObject::byteLengthGetter(JSContext *cx, unsigned argc, Value *vp)
   162 {
   163     CallArgs args = CallArgsFromVp(argc, vp);
   164     return CallNonGenericMethod<IsSharedArrayBuffer, byteLengthGetterImpl>(cx, args);
   165 }
   167 bool
   168 SharedArrayBufferObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
   169 {
   170     int32_t length = 0;
   171     CallArgs args = CallArgsFromVp(argc, vp);
   172     if (args.length() > 0 && !ToInt32(cx, args[0], &length))
   173         return false;
   175     if (length < 0) {
   176         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
   177         return false;
   178     }
   180     JSObject *bufobj = New(cx, uint32_t(length));
   181     if (!bufobj)
   182         return false;
   183     args.rval().setObject(*bufobj);
   184     return true;
   185 }
   187 JSObject *
   188 SharedArrayBufferObject::New(JSContext *cx, uint32_t length)
   189 {
   190     if (!IsValidAsmJSHeapLength(length)) {
   191         ScopedJSFreePtr<char> msg(
   192             JS_smprintf("SharedArrayBuffer byteLength 0x%x is not a valid length. The next valid "
   193                         "length is 0x%x", length, RoundUpToNextValidAsmJSHeapLength(length)));
   194         JS_ReportError(cx, msg.get());
   195         return nullptr;
   196     }
   198     SharedArrayRawBuffer *buffer = SharedArrayRawBuffer::New(length);
   199     if (!buffer)
   200         return nullptr;
   202     return New(cx, buffer);
   203 }
   205 JSObject *
   206 SharedArrayBufferObject::New(JSContext *cx, SharedArrayRawBuffer *buffer)
   207 {
   208     Rooted<SharedArrayBufferObject*> obj(cx, NewBuiltinClassInstance<SharedArrayBufferObject>(cx));
   209     if (!obj)
   210         return nullptr;
   212     JS_ASSERT(obj->getClass() == &class_);
   214     obj->initialize(buffer->byteLength(), nullptr, DoesntOwnData);
   216     obj->acceptRawBuffer(buffer);
   217     obj->setIsSharedArrayBuffer();
   219     return obj;
   220 }
   222 void
   223 SharedArrayBufferObject::acceptRawBuffer(SharedArrayRawBuffer *buffer)
   224 {
   225     setReservedSlot(SharedArrayBufferObject::RAWBUF_SLOT, PrivateValue(buffer));
   226 }
   228 void
   229 SharedArrayBufferObject::dropRawBuffer()
   230 {
   231     setReservedSlot(SharedArrayBufferObject::RAWBUF_SLOT, UndefinedValue());
   232 }
   234 SharedArrayRawBuffer *
   235 SharedArrayBufferObject::rawBufferObject() const
   236 {
   237     // RAWBUF_SLOT must be populated via acceptRawBuffer(),
   238     // and the raw buffer must not have been dropped.
   239     Value v = getReservedSlot(SharedArrayBufferObject::RAWBUF_SLOT);
   240     return (SharedArrayRawBuffer *)v.toPrivate();
   241 }
   243 uint8_t *
   244 SharedArrayBufferObject::dataPointer() const
   245 {
   246     return rawBufferObject()->dataPointer();
   247 }
   249 uint32_t
   250 SharedArrayBufferObject::byteLength() const
   251 {
   252     return rawBufferObject()->byteLength();
   253 }
   255 void
   256 SharedArrayBufferObject::Finalize(FreeOp *fop, JSObject *obj)
   257 {
   258     SharedArrayBufferObject &buf = obj->as<SharedArrayBufferObject>();
   260     // Detect the case of failure during SharedArrayBufferObject creation,
   261     // which causes a SharedArrayRawBuffer to never be attached.
   262     Value v = buf.getReservedSlot(SharedArrayBufferObject::RAWBUF_SLOT);
   263     if (!v.isUndefined()) {
   264         buf.rawBufferObject()->dropReference();
   265         buf.dropRawBuffer();
   266     }
   267 }
   269 /*
   270  * SharedArrayBufferObject
   271  */
   273 const Class SharedArrayBufferObject::protoClass = {
   274     "SharedArrayBufferPrototype",
   275     JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer),
   276     JS_PropertyStub,         /* addProperty */
   277     JS_DeletePropertyStub,   /* delProperty */
   278     JS_PropertyStub,         /* getProperty */
   279     JS_StrictPropertyStub,   /* setProperty */
   280     JS_EnumerateStub,
   281     JS_ResolveStub,
   282     JS_ConvertStub
   283 };
   285 const Class SharedArrayBufferObject::class_ = {
   286     "SharedArrayBuffer",
   287     JSCLASS_IMPLEMENTS_BARRIERS |
   288     JSCLASS_HAS_RESERVED_SLOTS(SharedArrayBufferObject::RESERVED_SLOTS) |
   289     JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer),
   290     JS_PropertyStub,         /* addProperty */
   291     JS_DeletePropertyStub,   /* delProperty */
   292     JS_PropertyStub,         /* getProperty */
   293     JS_StrictPropertyStub,   /* setProperty */
   294     JS_EnumerateStub,
   295     JS_ResolveStub,
   296     JS_ConvertStub,
   297     SharedArrayBufferObject::Finalize,
   298     nullptr,        /* call        */
   299     nullptr,        /* hasInstance */
   300     nullptr,        /* construct   */
   301     ArrayBufferObject::obj_trace,
   302     JS_NULL_CLASS_SPEC,
   303     JS_NULL_CLASS_EXT
   304 };
   306 JSObject *
   307 js_InitSharedArrayBufferClass(JSContext *cx, HandleObject obj)
   308 {
   309     JS_ASSERT(obj->isNative());
   310     Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
   311     RootedObject proto(cx, global->createBlankPrototype(cx, &SharedArrayBufferObject::protoClass));
   312     if (!proto)
   313         return nullptr;
   315     RootedFunction ctor(cx, global->createConstructor(cx, SharedArrayBufferObject::class_constructor,
   316                                                       cx->names().SharedArrayBuffer, 1));
   317     if (!ctor)
   318         return nullptr;
   320     if (!LinkConstructorAndPrototype(cx, ctor, proto))
   321         return nullptr;
   323     RootedId byteLengthId(cx, NameToId(cx->names().byteLength));
   324     unsigned attrs = JSPROP_SHARED | JSPROP_GETTER | JSPROP_PERMANENT;
   325     JSObject *getter = NewFunction(cx, NullPtr(), SharedArrayBufferObject::byteLengthGetter, 0,
   326                                    JSFunction::NATIVE_FUN, global, NullPtr());
   327     if (!getter)
   328         return nullptr;
   330     RootedValue value(cx, UndefinedValue());
   331     if (!DefineNativeProperty(cx, proto, byteLengthId, value,
   332                               JS_DATA_TO_FUNC_PTR(PropertyOp, getter), nullptr, attrs))
   333     {
   334         return nullptr;
   335     }
   337     if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_SharedArrayBuffer, ctor, proto))
   338         return nullptr;
   339     return proto;
   340 }

mercurial