tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Xdr.cpp (5353B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      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/. */
      6 
      7 #include "vm/Xdr.h"
      8 
      9 #include "mozilla/Assertions.h"   // MOZ_ASSERT, MOZ_ASSERT_IF
     10 #include "mozilla/EndianUtils.h"  // mozilla::NativeEndian, MOZ_LITTLE_ENDIAN
     11 #include "mozilla/Result.h"       // mozilla::{Result, Ok, Err}, MOZ_TRY
     12 #include "mozilla/Utf8.h"         // mozilla::Utf8Unit
     13 
     14 #include <algorithm>    // std::transform
     15 #include <stddef.h>     // size_t
     16 #include <stdint.h>     // uint8_t, uint32_t, uintptr_t
     17 #include <string>       // std::char_traits
     18 #include <type_traits>  // std::is_same_v
     19 #include <utility>      // std::move
     20 
     21 #include "frontend/FrontendContext.h"  // FrontendContext
     22 #include "js/Transcoding.h"  // JS::TranscodeResult, JS::TranscodeBuffer, JS::TranscodeRange
     23 #include "js/UniquePtr.h"   // UniquePtr
     24 #include "js/Utility.h"     // JS::FreePolicy, js_delete
     25 #include "vm/JSContext.h"   // JSContext, ReportAllocationOverflow
     26 #include "vm/StringType.h"  // JSString
     27 
     28 using namespace js;
     29 
     30 using mozilla::Utf8Unit;
     31 
     32 #ifdef DEBUG
     33 bool XDRCoderBase::validateResultCode(FrontendContext* fc,
     34                                      JS::TranscodeResult code) const {
     35  return fc->hadErrors() == bool(code == JS::TranscodeResult::Throw);
     36 }
     37 #endif
     38 
     39 template <XDRMode mode>
     40 XDRResult XDRState<mode>::codeChars(char* chars, size_t nchars) {
     41  return codeBytes(chars, nchars);
     42 }
     43 
     44 template <XDRMode mode>
     45 XDRResult XDRState<mode>::codeChars(Latin1Char* chars, size_t nchars) {
     46  static_assert(sizeof(Latin1Char) == 1,
     47                "Latin1Char must be 1 byte for nchars below to be the "
     48                "proper count of bytes");
     49  static_assert(std::is_same_v<Latin1Char, unsigned char>,
     50                "Latin1Char must be unsigned char to C++-safely reinterpret "
     51                "the bytes generically copied below as Latin1Char");
     52  return codeBytes(chars, nchars);
     53 }
     54 
     55 template <XDRMode mode>
     56 XDRResult XDRState<mode>::codeChars(Utf8Unit* units, size_t count) {
     57  if (count == 0) {
     58    return Ok();
     59  }
     60 
     61  if (mode == XDR_ENCODE) {
     62    uint8_t* ptr = buf->write(count);
     63    if (!ptr) {
     64      return fail(JS::TranscodeResult::Throw);
     65    }
     66 
     67    std::transform(units, units + count, ptr,
     68                   [](const Utf8Unit& unit) { return unit.toUint8(); });
     69  } else {
     70    const uint8_t* ptr = buf->read(count);
     71    if (!ptr) {
     72      return fail(JS::TranscodeResult::Failure_BadDecode);
     73    }
     74 
     75    std::transform(ptr, ptr + count, units,
     76                   [](const uint8_t& value) { return Utf8Unit(value); });
     77  }
     78 
     79  return Ok();
     80 }
     81 
     82 template <XDRMode mode>
     83 XDRResult XDRState<mode>::codeChars(char16_t* chars, size_t nchars) {
     84  if (nchars == 0) {
     85    return Ok();
     86  }
     87 
     88  size_t nbytes = nchars * sizeof(char16_t);
     89  if (mode == XDR_ENCODE) {
     90    uint8_t* ptr = buf->write(nbytes);
     91    if (!ptr) {
     92      return fail(JS::TranscodeResult::Throw);
     93    }
     94 
     95    // |mozilla::NativeEndian| correctly handles writing into unaligned |ptr|.
     96    mozilla::NativeEndian::copyAndSwapToLittleEndian(ptr, chars, nchars);
     97  } else {
     98    const uint8_t* ptr = buf->read(nbytes);
     99    if (!ptr) {
    100      return fail(JS::TranscodeResult::Failure_BadDecode);
    101    }
    102 
    103    // |mozilla::NativeEndian| correctly handles reading from unaligned |ptr|.
    104    mozilla::NativeEndian::copyAndSwapFromLittleEndian(chars, ptr, nchars);
    105  }
    106  return Ok();
    107 }
    108 
    109 template <XDRMode mode, typename CharT>
    110 static XDRResult XDRCodeCharsZ(XDRState<mode>* xdr,
    111                               XDRTranscodeString<CharT>& buffer) {
    112  MOZ_ASSERT_IF(mode == XDR_ENCODE, !buffer.empty());
    113  MOZ_ASSERT_IF(mode == XDR_DECODE, buffer.empty());
    114 
    115  using OwnedString = js::UniquePtr<CharT[], JS::FreePolicy>;
    116  OwnedString owned;
    117 
    118  static_assert(JSString::MAX_LENGTH <= INT32_MAX,
    119                "String length must fit in int32_t");
    120 
    121  uint32_t length = 0;
    122  CharT* chars = nullptr;
    123 
    124  if (mode == XDR_ENCODE) {
    125    chars = const_cast<CharT*>(buffer.template ref<const CharT*>());
    126 
    127    // Set a reasonable limit on string length.
    128    size_t lengthSizeT = std::char_traits<CharT>::length(chars);
    129    if (lengthSizeT > JSString::MAX_LENGTH) {
    130      ReportAllocationOverflow(xdr->fc());
    131      return xdr->fail(JS::TranscodeResult::Throw);
    132    }
    133    length = static_cast<uint32_t>(lengthSizeT);
    134  }
    135  MOZ_TRY(xdr->codeUint32(&length));
    136 
    137  if (mode == XDR_DECODE) {
    138    owned =
    139        xdr->fc()->getAllocator()->template make_pod_array<CharT>(length + 1);
    140    if (!owned) {
    141      return xdr->fail(JS::TranscodeResult::Throw);
    142    }
    143    chars = owned.get();
    144  }
    145 
    146  MOZ_TRY(xdr->codeChars(chars, length));
    147  if (mode == XDR_DECODE) {
    148    // Null-terminate and transfer ownership to caller.
    149    owned[length] = '\0';
    150    buffer.template construct<OwnedString>(std::move(owned));
    151  }
    152 
    153  return Ok();
    154 }
    155 
    156 template <XDRMode mode>
    157 XDRResult XDRState<mode>::codeCharsZ(XDRTranscodeString<char>& buffer) {
    158  return XDRCodeCharsZ(this, buffer);
    159 }
    160 
    161 template <XDRMode mode>
    162 XDRResult XDRState<mode>::codeCharsZ(XDRTranscodeString<char16_t>& buffer) {
    163  return XDRCodeCharsZ(this, buffer);
    164 }
    165 
    166 template class js::XDRState<XDR_ENCODE>;
    167 template class js::XDRState<XDR_DECODE>;