diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 00000000..135a1a9b --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,58 @@ +Checks: > + clang-analyzer-*, + clang-diagnostic-*, + cppcoreguidelines-*, + modernize-*, + performance-*, + readability-*, + bugprone-*, + misc-redundant-expression, + misc-uniqueptr-reset-release, + misc-unused-alias-decls, + misc-unused-using-decls, + -clang-analyzer-optin.core.EnumCastOutOfRange, + -cppcoreguidelines-avoid-do-while, + -cppcoreguidelines-avoid-c-arrays, + -cppcoreguidelines-pro-type-reinterpret-cast, + -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay, + -cppcoreguidelines-owning-memory, + -cppcoreguidelines-avoid-non-const-global-variables, + -cppcoreguidelines-pro-type-vararg, + -cppcoreguidelines-narrowing-conversions, + -cppcoreguidelines-pro-bounds-pointer-arithmetic, + -cppcoreguidelines-pro-type-cstyle-cast, + -cppcoreguidelines-init-variables, + -cppcoreguidelines-macro-usage, + -cppcoreguidelines-interfaces-global-init, + -cppcoreguidelines-use-default-member-init, + -cppcoreguidelines-pro-type-static-cast-downcast, + -modernize-use-trailing-return-type, + -modernize-avoid-c-arrays, + -modernize-use-ranges, + -readability-identifier-length, + -readability-static-accessed-through-instance, + -readability-function-cognitive-complexity, + -readability-magic-numbers, + -readability-simplify-boolean-expr, + -bugprone-easily-swappable-parameters, + -bugprone-dynamic-static-initializers, + -bugprone-assignment-in-if-condition, + -bugprone-narrowing-conversions, + +# Check options configuration +CheckOptions: + - key: readability-implicit-bool-conversion.AllowPointerConditions + value: 'true' + +# Treat all warnings as errors +WarningsAsErrors: '*' + +# Only warn on headers in the code tree +HeaderFilterRegex: 'builtins/|runtime/' + +# Use the same style as clang-format (look for .clang-format) +FormatStyle: file + +# Explicitly exclude system/dependency headers +SystemHeaders: false diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d251ec64..c6c55be3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -113,6 +113,13 @@ jobs: name: spidermonkey-${{ matrix.build }} path: spidermonkey-dist-${{ matrix.build }}/* + - name: Install Just + uses: taiki-e/install-action@just + + - name: Run clang linter + if: matrix.build == 'debug' + run: just lint + release-spidermonkey: needs: test if: needs.test.outputs.SM_TAG_EXISTS == 'false' && (github.event_name == 'push' && diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f24aa77..d7054b92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,7 @@ include("spidermonkey") include("openssl") include("${HOST_API}/host_api.cmake") include("build-crates") +include("lint") option(ENABLE_JS_DEBUGGER "Enable support for debugging content via a socket connection" ON) diff --git a/builtins/web/abort/abort-controller.cpp b/builtins/web/abort/abort-controller.cpp index a1b83070..4902f099 100644 --- a/builtins/web/abort/abort-controller.cpp +++ b/builtins/web/abort/abort-controller.cpp @@ -1,9 +1,9 @@ #include "abort-controller.h" #include "abort-signal.h" -namespace builtins { -namespace web { -namespace abort { + + +namespace builtins::web::abort { const JSFunctionSpec AbortController::static_methods[] = { JS_FS_END, @@ -65,6 +65,6 @@ bool AbortController::init_class(JSContext *cx, JS::HandleObject global) { return init_class_impl(cx, global); } -} // namespace abort -} // namespace web -} // namespace builtins +} // namespace builtins::web::abort + + diff --git a/builtins/web/abort/abort-controller.h b/builtins/web/abort/abort-controller.h index 7405aa48..33eacafb 100644 --- a/builtins/web/abort/abort-controller.h +++ b/builtins/web/abort/abort-controller.h @@ -3,9 +3,9 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace abort { + + +namespace builtins::web::abort { class AbortController : public BuiltinImpl { static bool signal_get(JSContext *cx, unsigned argc, JS::Value *vp); @@ -17,7 +17,7 @@ class AbortController : public BuiltinImpl { static constexpr const char *class_name = "AbortController"; static constexpr unsigned ctor_length = 0; - enum Slots { Signal = 0, Count }; + enum Slots : uint8_t { Signal = 0, Count }; static const JSFunctionSpec static_methods[]; static const JSPropertySpec static_properties[]; @@ -28,9 +28,9 @@ class AbortController : public BuiltinImpl { static bool constructor(JSContext *cx, unsigned argc, Value *vp); }; -} // namespace abort -} // namespace web -} // namespace builtins +} // namespace builtins::web::abort + + diff --git a/builtins/web/abort/abort-signal.cpp b/builtins/web/abort/abort-signal.cpp index 16d3d502..0e0c7efd 100644 --- a/builtins/web/abort/abort-signal.cpp +++ b/builtins/web/abort/abort-signal.cpp @@ -5,9 +5,9 @@ #include "../event/event.h" #include "../timers.h" -namespace builtins { -namespace web { -namespace abort { + + +namespace builtins::web::abort { using event::Event; using event::EventTarget; @@ -195,7 +195,7 @@ bool AbortSignal::add_algorithm(JSObject *self, js::UniquePtr al } // 2. Append algorithm to signal's abort algorithms. - auto algorithms = AbortSignal::algorithms(self); + auto *algorithms = AbortSignal::algorithms(self); return algorithms->append(std::move(algorithm)); } @@ -228,7 +228,7 @@ bool AbortSignal::abort(JSContext *cx, HandleObject self, HandleValue reason) { JS::RootedObjectVector dep_signals_to_abort(cx); // 4. For each dependentSignal of signal's dependent signals: - auto dep_signals = dependent_signals(self); + auto *dep_signals = dependent_signals(self); for (auto const &sig : dep_signals->items()) { RootedObject signal(cx, sig); // 1. If dependentSignal is not aborted: @@ -259,9 +259,11 @@ bool AbortSignal::abort(JSContext *cx, HandleObject self, HandleValue reason) { bool AbortSignal::run_abort_steps(JSContext *cx, HandleObject self) { // To run the abort steps for an AbortSignal signal: // 1. For each algorithm of signal's abort algorithms: run algorithm. - auto algorithms = AbortSignal::algorithms(self); + auto *algorithms = AbortSignal::algorithms(self); for (auto &algorithm : *algorithms) { - if (!algorithm->run(cx)) return false; + if (!algorithm->run(cx)) { + return false; + } } // 2. Empty signals's abort algorithms. @@ -274,11 +276,7 @@ bool AbortSignal::run_abort_steps(JSContext *cx, HandleObject self) { RootedObject event(cx, Event::create(cx, type_val, JS::NullHandleValue)); RootedValue event_val(cx, JS::ObjectValue(*event)); - if (!EventTarget::dispatch_event(cx, self, event_val, &res_val)) { - return false; - } - - return true; + return EventTarget::dispatch_event(cx, self, event_val, &res_val); } // Set signal's abort reason to reason if it is given; otherwise to a new "AbortError" DOMException. @@ -420,7 +418,7 @@ JSObject *AbortSignal::create_with_signals(JSContext *cx, HandleValueArray signa // 3. Set resultSignal's dependent to true. SetReservedSlot(self, Slots::Dependent, JS::TrueValue()); - auto our_signals = source_signals(self); + auto *our_signals = source_signals(self); // 4. For each signal of signals: for (size_t i = 0; i < signals.length(); ++i) { @@ -431,12 +429,12 @@ JSObject *AbortSignal::create_with_signals(JSContext *cx, HandleValueArray signa // 1. Append signal to resultSignal's source signals. our_signals->insert(signal); // 2. Append resultSignal to signal's dependent signals. - auto their_signals = dependent_signals(signal); + auto *their_signals = dependent_signals(signal); their_signals->insert(self); } // 2. Otherwise... else { - auto src_signals = source_signals(signal); + auto *src_signals = source_signals(signal); // for each sourceSignal of signal's source signals: for (auto const &source : src_signals->items()) { // 1. Assert: sourceSignal is not aborted and not dependent. @@ -444,7 +442,7 @@ JSObject *AbortSignal::create_with_signals(JSContext *cx, HandleValueArray signa // 2. Append sourceSignal to resultSignal's source signals. our_signals->insert(source); // 3. Append resultSignal to sourceSignal's dependent signals. - auto their_signals = dependent_signals(source); + auto *their_signals = dependent_signals(source); their_signals->insert(self); }; } @@ -469,21 +467,21 @@ void AbortSignal::trace(JSTracer *trc, JSObject *self) { auto has_sources = !JS::GetReservedSlot(self, Slots::SourceSignals).isNullOrUndefined(); if (has_sources) { - auto srcsig = source_signals(self); + auto *srcsig = source_signals(self); srcsig->trace(trc); srcsig->traceWeak(trc); } auto has_deps = !JS::GetReservedSlot(self, Slots::DependentSignals).isNullOrUndefined(); if (has_deps) { - auto depsig = dependent_signals(self); + auto *depsig = dependent_signals(self); depsig->trace(trc); depsig->traceWeak(trc); } auto has_algorithms = !JS::GetReservedSlot(self, Slots::Algorithms).isNullOrUndefined(); if (has_algorithms) { - auto algorithms = AbortSignal::algorithms(self); + auto *algorithms = AbortSignal::algorithms(self); algorithms->trace(trc); } } @@ -515,6 +513,6 @@ bool install(api::Engine *engine) { JSString *AbortSignal::abort_type_atom = nullptr; -} // namespace abort -} // namespace web -} // namespace builtins +} // namespace builtins::web::abort + + diff --git a/builtins/web/abort/abort-signal.h b/builtins/web/abort/abort-signal.h index fd120285..e7c34374 100644 --- a/builtins/web/abort/abort-signal.h +++ b/builtins/web/abort/abort-signal.h @@ -6,15 +6,22 @@ #include "../event/event-target.h" -namespace builtins { -namespace web { -namespace abort { + + +namespace builtins::web::abort { struct AbortAlgorithm { bool virtual run(JSContext *cx) = 0; void virtual trace(JSTracer *trc) { }; + AbortAlgorithm() = default; virtual ~AbortAlgorithm() = default; + + AbortAlgorithm(const AbortAlgorithm &) = default; + AbortAlgorithm(AbortAlgorithm &&) = delete; + + AbortAlgorithm &operator=(const AbortAlgorithm &) = default; + AbortAlgorithm &operator=(AbortAlgorithm &&) = delete; }; class AbortSignal : public BuiltinImpl { @@ -45,7 +52,7 @@ class AbortSignal : public BuiltinImpl { public: static constexpr int ParentSlots = event::EventTarget::Slots::Count; - enum Slots { + enum Slots : uint8_t { Reason = ParentSlots, Algorithms, Dependent, @@ -81,8 +88,8 @@ class AbortSignal : public BuiltinImpl { static void trace(JSTracer *trc, JSObject *self); }; -} // namespace abort -} // namespace web -} // namespace builtins +} // namespace builtins::web::abort + + #endif // BUILTINS_WEB_ABORT_SIGNAL_H_ diff --git a/builtins/web/abort/weak-index-set.h b/builtins/web/abort/weak-index-set.h index 6f1d69bb..0b97ab06 100644 --- a/builtins/web/abort/weak-index-set.h +++ b/builtins/web/abort/weak-index-set.h @@ -13,16 +13,15 @@ class WeakIndexSet { WeakVec items_; public: - WeakIndexSet() : items_() {} + WeakIndexSet() = default; bool insert(JSObject* obj) { - auto it = std::find_if(items_.begin(), items_.end(), [&obj](const auto &item) { return item == obj; }); + auto *it = std::find_if(items_.begin(), items_.end(), [&obj](const auto &item) { return item == obj; }); if (it == items_.end()) { return items_.append(obj); - } else { - return true; } + return true; } bool remove(JSObject* obj) { @@ -31,7 +30,7 @@ class WeakIndexSet { } WeakVec &items() { return items_;} - const WeakVec &items() const { return items_; } + [[nodiscard]] const WeakVec &items() const { return items_; } void trace(JSTracer* trc) { items_.trace(trc); } diff --git a/builtins/web/base64.cpp b/builtins/web/base64.cpp index fee32521..8d4e942a 100644 --- a/builtins/web/base64.cpp +++ b/builtins/web/base64.cpp @@ -4,9 +4,9 @@ DEF_ERR(InvalidCharacterError, JSEXN_RANGEERR, "String contains an invalid character", 0) -namespace builtins { -namespace web { -namespace base64 { + + +namespace builtins::web::base64 { JS::Result valueToJSByteString(JSContext *cx, JS::Handle v) { JS::RootedString s(cx); @@ -22,7 +22,7 @@ JS::Result valueToJSByteString(JSContext *cx, JS::Handle // Conversion from JavaScript string to ByteString is only valid if all // characters < 256. This is always the case for Latin1 strings. - size_t length; + size_t length = 0; UniqueChars result = nullptr; if (!JS::StringHasLatin1Chars(s)) { JS::AutoCheckCannotGC nogc(cx); @@ -57,7 +57,7 @@ JS::Result valueToJSByteString(JSContext *cx, JS::Handle return byteString; } -JS::Result stringToJSByteString(JSContext *cx, std::string v) { +JS::Result stringToJSByteString(JSContext *cx, const std::string& v) { JS::RootedValue s(cx); s.setString(JS_NewStringCopyN(cx, v.c_str(), v.length())); return valueToJSByteString(cx, s); @@ -116,9 +116,9 @@ const char base64EncodeTable[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" bool base64CharacterToValue(char character, uint8_t *value, const uint8_t *decodeTable) { static const size_t mask = 127; - auto index = static_cast(character); + auto index = static_cast(character); - if (index & ~mask) { + if ((index & ~mask) != 0U) { return false; } *value = decodeTable[index & mask]; @@ -128,7 +128,10 @@ bool base64CharacterToValue(char character, uint8_t *value, const uint8_t *decod inline JS::Result base64Decode4to3(std::string_view input, std::string &output, const uint8_t *decodeTable) { - uint8_t w, x, y, z; + uint8_t w = 0; + uint8_t x = 0; + uint8_t y = 0; + uint8_t z = 0; // 8.1 Find the code point pointed to by position in the second column of // Table 1: The Base 64 Alphabet of RFC 4648. Let n be the number given in the // first cell of the same row. [RFC4648] @@ -150,7 +153,9 @@ inline JS::Result base64Decode4to3(std::string_view input, std::str inline JS::Result base64Decode3to2(std::string_view input, std::string &output, const uint8_t *decodeTable) { - uint8_t w, x, y; + uint8_t w = 0; + uint8_t x = 0; + uint8_t y = 0; // 8.1 Find the code point pointed to by position in the second column of // Table 1: The Base 64 Alphabet of RFC 4648. Let n be the number given in the // first cell of the same row. [RFC4648] @@ -172,7 +177,8 @@ inline JS::Result base64Decode3to2(std::string_view input, std::str inline JS::Result base64Decode2to1(std::string_view input, std::string &output, const uint8_t *decodeTable) { - uint8_t w, x; + uint8_t w = 0; + uint8_t x = 0; // 8.1 Find the code point pointed to by position in the second column of // Table 1: The Base 64 Alphabet of RFC 4648. Let n be the number given in the // first cell of the same row. [RFC4648] @@ -212,7 +218,7 @@ JS::Result forgivingBase64Decode(std::string_view data, auto hasWhitespace = std::find_if(data.begin(), data.end(), &isAsciiWhitespace); std::string dataWithoutAsciiWhitespace; - if (*hasWhitespace) { + if (*hasWhitespace != 0) { dataWithoutAsciiWhitespace = data; dataWithoutAsciiWhitespace.erase(std::remove_if(dataWithoutAsciiWhitespace.begin() + std::distance(data.begin(), hasWhitespace), @@ -225,7 +231,7 @@ JS::Result forgivingBase64Decode(std::string_view data, size_t length = data_view.length(); // 2. If data’s code point length divides by 4 leaving no remainder, then: - if (length && (length % 4 == 0)) { + if ((length != 0U) && (length % 4 == 0)) { // 2.1 If data ends with one or two U+003D (=) code points, then remove them // from data. if (data_view.at(length - 1) == '=') { @@ -253,7 +259,7 @@ JS::Result forgivingBase64Decode(std::string_view data, // base64Decode4to3, base64Decode3to2, and base64Decode2to1 // 5. Let output be an empty byte sequence. - std::string output = ""; + std::string output; output.reserve(data_view.length() / 3); // 6. Let buffer be an empty buffer that can have bits appended to it. @@ -326,7 +332,8 @@ bool atob(JSContext *cx, unsigned argc, Value *vp) { inline uint8_t CharTo8Bit(char character) { return uint8_t(character); } inline void base64Encode3to4(std::string_view data, std::string &output, const char *encodeTable) { uint32_t b32 = 0; - int i, j = 18; + int i = 0; + int j = 18; for (i = 0; i < 3; ++i) { b32 <<= 8; @@ -364,7 +371,7 @@ inline void base64Encode1to4(std::string_view data, std::string &output, const c // handling for certain inputs. std::string forgivingBase64Encode(std::string_view data, const char *encodeTable) { int length = data.length(); - std::string output = ""; + std::string output; // The Base64 version of a string will be at least 133% the size of the // string. output.reserve(length * 1.33); @@ -430,6 +437,6 @@ bool install(api::Engine *engine) { return JS_DefineFunctions(engine->cx(), engine->global(), methods); } -} // namespace base64 -} // namespace web -} // namespace builtins +} // namespace builtins::web::base64 + + diff --git a/builtins/web/base64.h b/builtins/web/base64.h index ece79139..012fd7a4 100644 --- a/builtins/web/base64.h +++ b/builtins/web/base64.h @@ -3,9 +3,9 @@ #include "extension-api.h" -namespace builtins { -namespace web { -namespace base64 { + + +namespace builtins::web::base64 { bool install(api::Engine *engine); @@ -18,10 +18,10 @@ std::string forgivingBase64Encode(std::string_view data, const char *encodeTable JS::Result forgivingBase64Decode(std::string_view data, const uint8_t *decodeTable); JS::Result valueToJSByteString(JSContext *cx, HandleValue v); -JS::Result stringToJSByteString(JSContext *cx, std::string v); +JS::Result stringToJSByteString(JSContext *cx, const std::string& v); + +} // namespace builtins::web::base64 + -} // namespace base64 -} // namespace web -} // namespace builtins #endif diff --git a/builtins/web/blob.cpp b/builtins/web/blob.cpp index 18821b75..832a42f1 100644 --- a/builtins/web/blob.cpp +++ b/builtins/web/blob.cpp @@ -42,7 +42,7 @@ JSString *normalize_type(JSContext *cx, HandleValue value) { return JS_GetEmptyString(cx); } - auto str = JS::StringToLinearString(cx, value_str); + auto *str = JS::StringToLinearString(cx, value_str); if (!str) { return nullptr; } @@ -50,13 +50,13 @@ JSString *normalize_type(JSContext *cx, HandleValue value) { std::string normalized; auto strlen = JS::GetLinearStringLength(str); - if (!strlen) { + if (strlen == 0U) { return JS_GetEmptyString(cx); } if (JS::LinearStringHasLatin1Chars(str)) { JS::AutoCheckCannotGC nogc(cx); - auto chars = JS::GetLatin1LinearStringChars(nogc, str); + const auto *chars = JS::GetLatin1LinearStringChars(nogc, str); if (!validate_type(chars, strlen)) { return JS_GetEmptyString(cx); } @@ -64,7 +64,7 @@ JSString *normalize_type(JSContext *cx, HandleValue value) { normalized = std::string(reinterpret_cast(chars), strlen); } else { JS::AutoCheckCannotGC nogc(cx); - auto chars = (JS::GetTwoByteLinearStringChars(nogc, str)); + const auto *chars = (JS::GetTwoByteLinearStringChars(nogc, str)); if (!validate_type(chars, strlen)) { return JS_GetEmptyString(cx); } @@ -122,12 +122,11 @@ std::string convert_line_endings_to_native(std::string_view s) { } // anonymous namespace -namespace builtins { -namespace web { -namespace blob { + + +namespace builtins::web::blob { using js::Vector; -using file::File; using streams::BufReader; using streams::NativeStreamSource; @@ -168,7 +167,7 @@ const JSPropertySpec Blob::properties[] = { }; JSObject *Blob::data_to_owned_array_buffer(JSContext *cx, HandleObject self) { - auto src = Blob::blob(self); + auto *src = Blob::blob(self); auto size = src->length(); auto buf = mozilla::MakeUnique(size); @@ -179,7 +178,7 @@ JSObject *Blob::data_to_owned_array_buffer(JSContext *cx, HandleObject self) { std::copy_n(src->begin(), size, buf.get()); - auto array_buffer = JS::NewArrayBufferWithContents( + auto *array_buffer = JS::NewArrayBufferWithContents( cx, size, buf.get(), JS::NewArrayBufferOutOfMemory::CallerMustFreeMemory); if (!array_buffer) { JS_ReportOutOfMemory(cx); @@ -193,7 +192,7 @@ JSObject *Blob::data_to_owned_array_buffer(JSContext *cx, HandleObject self) { bool Blob::read_blob_slice(JSContext *cx, HandleObject self, std::span buf, size_t start, size_t *read, bool *done) { - auto src = Blob::blob(self); + auto *src = Blob::blob(self); if (start >= src->length()) { *read = 0; @@ -224,7 +223,7 @@ bool Blob::arrayBuffer(JSContext *cx, HandleObject self, MutableHandleValue rval rval.setObject(*promise); - auto buffer = data_to_owned_array_buffer(cx, self); + auto *buffer = data_to_owned_array_buffer(cx, self); if (!buffer) { return RejectPromiseWithPendingError(cx, promise); } @@ -263,7 +262,7 @@ bool Blob::bytes(JSContext *cx, HandleObject self, MutableHandleValue rval) { } bool Blob::slice(JSContext *cx, HandleObject self, const CallArgs &args, MutableHandleValue rval) { - auto src = Blob::blob(self); + auto *src = Blob::blob(self); int64_t size = src->length(); int64_t start = 0; int64_t end = size; @@ -286,7 +285,7 @@ bool Blob::slice(JSContext *cx, HandleObject self, const CallArgs &args, Mutable if (args.hasDefined(2)) { HandleValue contentType_val = args.get(2); - if (!(contentType = normalize_type(cx, contentType_val))) { + if ((contentType = normalize_type(cx, contentType_val)) == nullptr) { return false; } } @@ -332,9 +331,11 @@ bool Blob::text(JSContext *cx, HandleObject self, MutableHandleValue rval) { rval.setObject(*promise); - auto src = Blob::blob(self); - auto encoding = const_cast(jsencoding::encoding_for_label_no_replacement( - reinterpret_cast(const_cast("UTF-8")), 5)); + auto *src = Blob::blob(self); + + const char* utf8_label = "UTF-8"; + const auto *encoding = + jsencoding::encoding_for_label_no_replacement(reinterpret_cast(utf8_label), 5); auto deleter = [&](jsencoding::Decoder *dec) { jsencoding::decoder_free(dec); }; std::unique_ptr decoder( @@ -345,14 +346,14 @@ bool Blob::text(JSContext *cx, HandleObject self, MutableHandleValue rval) { auto src_len = src->length(); auto dst_len = jsencoding::decoder_max_utf16_buffer_length(decoder.get(), src_len); - JS::UniqueTwoByteChars dst(new char16_t[dst_len + 1]); + JS::UniqueTwoByteChars dst(static_cast(js_pod_malloc(dst_len + 1))); if (!dst) { JS_ReportOutOfMemory(cx); return false; } - bool had_replacements; - auto dst_data = reinterpret_cast(dst.get()); + bool had_replacements = false; + auto *dst_data = reinterpret_cast(dst.get()); jsencoding::decoder_decode_to_utf16(decoder.get(), src->begin(), &src_len, dst_data, &dst_len, true, &had_replacements); @@ -388,14 +389,14 @@ bool Blob::type_get(JSContext *cx, unsigned argc, JS::Value *vp) { return api::throw_error(cx, api::Errors::WrongReceiver, "type get", "Blob"); } - auto type = Blob::type(self); + auto *type = Blob::type(self); args.rval().setString(type); return true; } Blob::ByteBuffer *Blob::blob(JSObject *self) { MOZ_ASSERT(is_instance(self)); - auto blob = static_cast( + auto *blob = static_cast( JS::GetReservedSlot(self, static_cast(Blob::Slots::Data)).toPrivate()); MOZ_ASSERT(blob); @@ -418,23 +419,25 @@ Blob::LineEndings Blob::line_endings(JSObject *self) { } bool Blob::append_value(JSContext *cx, HandleObject self, HandleValue val) { - auto blob = Blob::blob(self); + auto *blob = Blob::blob(self); if (val.isObject()) { RootedObject obj(cx, &val.toObject()); if (Blob::is_instance(obj)) { - auto src = Blob::blob(obj); + auto *src = Blob::blob(obj); return blob->append(src->begin(), src->end()); - } else if (JS_IsArrayBufferViewObject(obj) || JS::IsArrayBufferObject(obj)) { + } + + if (JS_IsArrayBufferViewObject(obj) || JS::IsArrayBufferObject(obj)) { auto span = value_to_buffer(cx, val, "Blob Parts"); if (span.has_value()) { - auto src = span->data(); + auto *src = span->data(); auto len = span->size(); return blob->append(src, src + len); - } else { - return true; } + + return true; } } else if (val.isString()) { auto chars = core::encode(cx, val); @@ -444,19 +447,16 @@ bool Blob::append_value(JSContext *cx, HandleObject self, HandleValue val) { if (line_endings(self) == LineEndings::Native) { auto converted = convert_line_endings_to_native(chars); - auto src = converted.data(); + auto *src = converted.data(); auto len = converted.length(); return blob->append(src, src + len); - - } else { - auto src = chars.ptr.get(); - auto len = chars.len; - return blob->append(src, src + len); } + + return blob->append(chars.ptr.get(), chars.ptr.get() + chars.len); } // FALLBACK: if we ever get here convert, to string and call append again - auto str = JS::ToString(cx, val); + auto *str = JS::ToString(cx, val); if (!str) { return false; } @@ -477,7 +477,7 @@ bool Blob::init_blob_parts(JSContext *cx, HandleObject self, HandleValue value) // if the object is an iterable, walk over its elements... JS::Rooted item(cx); while (true) { - bool done; + bool done = false; if (!it.next(&item, &done)) { return false; @@ -492,10 +492,9 @@ bool Blob::init_blob_parts(JSContext *cx, HandleObject self, HandleValue value) } return true; - } else { - // non-objects are not allowed for the blobParts - return api::throw_error(cx, api::Errors::TypeError, "Blob.constructor", "blobParts", "be an object"); } + // non-objects are not allowed for the blobParts + return api::throw_error(cx, api::Errors::TypeError, "Blob.constructor", "blobParts", "be an object"); } bool Blob::init_options(JSContext *cx, HandleObject self, HandleValue initv) { @@ -509,7 +508,8 @@ bool Blob::init_options(JSContext *cx, HandleObject self, HandleValue initv) { // - `type`: the MIME type of the data that will be stored into the blob, // - `endings`: how to interpret newline characters (\n) within the contents. JS::RootedObject opts(cx, init_val.toObjectOrNull()); - bool has_endings, has_type; + bool has_endings = false; + bool has_type = false; if (!JS_HasProperty(cx, opts, "endings", &has_endings) || !JS_HasProperty(cx, opts, "type", &has_type)) { @@ -523,12 +523,13 @@ bool Blob::init_options(JSContext *cx, HandleObject self, HandleValue initv) { if (has_endings) { JS::RootedValue endings_val(cx); - bool is_transparent, is_native; + bool is_transparent = false; + bool is_native = false; if (!JS_GetProperty(cx, opts, "endings", &endings_val)) { return false; } - auto endings_str = JS::ToString(cx, endings_val); + auto *endings_str = JS::ToString(cx, endings_val); if (!JS_StringEqualsLiteral(cx, endings_str, "transparent", &is_transparent) || !JS_StringEqualsLiteral(cx, endings_str, "native", &is_native)) { return false; @@ -546,7 +547,7 @@ bool Blob::init_options(JSContext *cx, HandleObject self, HandleValue initv) { return false; } - auto type_str = normalize_type(cx, type); + auto *type_str = normalize_type(cx, type); if (!type_str) { return false; } @@ -562,22 +563,33 @@ JSObject *Blob::create(JSContext *cx, UniqueChars data, size_t data_len, HandleS return nullptr; } - auto blob = new ByteBuffer; + auto blob = js::MakeUnique(); + if (!blob) { + JS_ReportOutOfMemory(cx); + return nullptr; + } + if (data != nullptr) { // Take the ownership of given data. blob->replaceRawBuffer(reinterpret_cast(data.release()), data_len); } - SetReservedSlot(self, static_cast(Slots::Data), JS::PrivateValue(blob)); + SetReservedSlot(self, static_cast(Slots::Data), JS::PrivateValue(blob.release())); SetReservedSlot(self, static_cast(Slots::Type), JS::StringValue(type)); SetReservedSlot(self, static_cast(Slots::Endings), JS::Int32Value(LineEndings::Transparent)); return self; } bool Blob::init(JSContext *cx, HandleObject self, HandleValue blobParts, HandleValue opts) { + auto blob = js::MakeUnique(); + if (blob == nullptr) { + JS_ReportOutOfMemory(cx); + return false; + } + SetReservedSlot(self, static_cast(Slots::Type), JS_GetEmptyStringValue(cx)); SetReservedSlot(self, static_cast(Slots::Endings), JS::Int32Value(LineEndings::Transparent)); - SetReservedSlot(self, static_cast(Slots::Data), JS::PrivateValue(new ByteBuffer)); + SetReservedSlot(self, static_cast(Slots::Data), JS::PrivateValue(blob.release())); // Walk the blob parts and append them to the blob's buffer. if (blobParts.isNull()) { @@ -620,9 +632,9 @@ bool Blob::init_class(JSContext *cx, JS::HandleObject global) { void Blob::finalize(JS::GCContext *gcx, JSObject *self) { MOZ_ASSERT(is_instance(self)); - auto blob = Blob::blob(self); + auto *blob = Blob::blob(self); if (blob) { - free(blob); + js_delete(blob); } } @@ -630,6 +642,6 @@ bool install(api::Engine *engine) { return Blob::init_class(engine->cx(), engine->global()); } -} // namespace blob -} // namespace web -} // namespace builtins +} // namespace builtins::web::blob + + diff --git a/builtins/web/blob.h b/builtins/web/blob.h index 261470ac..a7b4e4e7 100644 --- a/builtins/web/blob.h +++ b/builtins/web/blob.h @@ -6,9 +6,9 @@ #include "js/AllocPolicy.h" #include "js/Vector.h" -namespace builtins { -namespace web { -namespace blob { + + +namespace builtins::web::blob { class Blob : public BuiltinImpl { static bool arrayBuffer(JSContext *cx, unsigned argc, JS::Value *vp); @@ -29,8 +29,8 @@ class Blob : public BuiltinImpl { static const JSPropertySpec properties[]; static constexpr unsigned ctor_length = 0; - enum Slots { Data, Type, Endings, Readers, Count }; - enum LineEndings { Transparent, Native }; + enum Slots : uint8_t { Data, Type, Endings, Readers, Count }; + enum LineEndings : uint8_t { Transparent, Native }; using ByteBuffer = js::Vector; @@ -46,12 +46,12 @@ class Blob : public BuiltinImpl { static LineEndings line_endings(JSObject *self); static bool append_value(JSContext *cx, HandleObject self, HandleValue val); - static bool init_blob_parts(JSContext *cx, HandleObject self, HandleValue iterable); - static bool init_options(JSContext *cx, HandleObject self, HandleValue opts); + static bool init_blob_parts(JSContext *cx, HandleObject self, HandleValue value); + static bool init_options(JSContext *cx, HandleObject self, HandleValue initv); static bool init(JSContext *cx, HandleObject self, HandleValue blobParts, HandleValue opts); static JSObject *data_to_owned_array_buffer(JSContext *cx, HandleObject self); - static bool read_blob_slice(JSContext *cx, HandleObject self, std::span, + static bool read_blob_slice(JSContext *cx, HandleObject self, std::span buf, size_t start, size_t *read, bool *done); static JSObject *create(JSContext *cx, UniqueChars data, size_t data_len, HandleString type); @@ -63,8 +63,8 @@ class Blob : public BuiltinImpl { bool install(api::Engine *engine); -} // namespace blob -} // namespace web -} // namespace builtins +} // namespace builtins::web::blob + + #endif // BUILTINS_WEB_URL_H diff --git a/builtins/web/console.cpp b/builtins/web/console.cpp index 19086865..386e07b9 100644 --- a/builtins/web/console.cpp +++ b/builtins/web/console.cpp @@ -4,13 +4,9 @@ #include #include -#include "mozilla/Try.h" -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" -#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" #include #include -#pragma clang diagnostic pop +#include "mozilla/Try.h" namespace { using FpMilliseconds = std::chrono::duration; @@ -82,7 +78,7 @@ JS::Result MapToSource(JSContext *cx, std::string &sourceOut, JS::H JS::RootedValue value_val(cx); bool firstValue = true; while (true) { - bool done; + bool done = false; if (!it.next(&entry_val, &done)) { return JS::Result(JS::Error()); } @@ -130,7 +126,7 @@ JS::Result SetToSource(JSContext *cx, std::string &sourceOut, JS::H JS::RootedValue entry_val(cx); bool firstValue = true; while (true) { - bool done; + bool done = false; if (!it.next(&entry_val, &done)) { return JS::Result(JS::Error()); } @@ -152,7 +148,7 @@ JS::Result SetToSource(JSContext *cx, std::string &sourceOut, JS::H JS::Result ArrayToSource(JSContext *cx, std::string &sourceOut, JS::HandleObject obj, JS::MutableHandleObjectVector visitedObjects) { sourceOut += "["; - uint32_t len; + uint32_t len = 0; if (!JS::GetArrayLength(cx, obj, &len)) { return JS::Result(JS::Error()); } @@ -203,7 +199,7 @@ JS::Result ObjectToSource(JSContext *cx, std::string &sourceOut, JS // Skip logging non-own function or getter and setter keys if (getter_setter || (value.isObject() && JS_ObjectIsFunction(&value.toObject()))) { - bool own_prop; + bool own_prop = false; if (!JS_HasOwnPropertyById(cx, obj, id, &own_prop)) { return JS::Result(JS::Error()); } @@ -289,7 +285,6 @@ JS::Result ToSource(JSContext *cx, std::string &sourceOut, JS::Hand if (JS_ObjectIsFunction(obj)) { sourceOut += "["; - std::string source; JS::RootedFunction fun(cx, JS_ValueToFunction(cx, val)); if (fun) { JS::RootedString result(cx, JS_DecompileFunction(cx, fun)); @@ -363,12 +358,11 @@ JS::Result ToSource(JSContext *cx, std::string &sourceOut, JS::Hand return mozilla::Ok(); } default: { - std::string sourceString; if (JS::IsWeakMapObject(obj)) { sourceOut += "WeakMap { }"; return mozilla::Ok(); } - auto cls = JS::GetClass(obj); + const auto *cls = JS::GetClass(obj); std::string className(cls->name); if (className == "WeakSet") { sourceOut += "WeakSet { }"; @@ -413,7 +407,7 @@ namespace builtins::web::console { __attribute__((weak)) void builtin_impl_console_log(Console::LogType log_ty, const char *msg) { - const char *prefix = ""; + const char *prefix = nullptr; switch (log_ty) { case Console::LogType::Log: prefix = "Log"; @@ -430,7 +424,12 @@ void builtin_impl_console_log(Console::LogType log_ty, const char *msg) { case Console::LogType::Error: prefix = "Error"; break; + default: + prefix = ""; + break; } + MOZ_ASSERT(prefix); + fprintf(stdout, "%s: %s\n", prefix, msg); fflush(stdout); } @@ -438,12 +437,12 @@ void builtin_impl_console_log(Console::LogType log_ty, const char *msg) { template static bool console_out(JSContext *cx, unsigned argc, JS::Value *vp) { JS::CallArgs args = CallArgsFromVp(argc, vp); - std::string fullLogLine = ""; + std::string fullLogLine; auto length = args.length(); JS::RootedObjectVector visitedObjects(cx); for (int i = 0; i < length; i++) { JS::HandleValue arg = args.get(i); - std::string source = ""; + std::string source; auto result = ToSource(cx, source, arg, &visitedObjects); if (result.isErr()) { return false; @@ -452,7 +451,7 @@ static bool console_out(JSContext *cx, unsigned argc, JS::Value *vp) { if (source[0] == '"' && source[source.length() - 1] == '"') { source = source.substr(1, source.length() - 2); } - if (fullLogLine.length()) { + if (!fullLogLine.empty()) { fullLogLine += " "; fullLogLine += source; } else { @@ -493,7 +492,7 @@ static bool assert_(JSContext *cx, unsigned argc, JS::Value *vp) { JS::RootedObjectVector visitedObjects(cx); for (int i = 0; i < length; i++) { JS::HandleValue arg = args.get(i); - std::string source = ""; + std::string source; auto result = ToSource(cx, source, arg, &visitedObjects); if (result.isErr()) { return false; @@ -519,8 +518,8 @@ static bool assert_(JSContext *cx, unsigned argc, JS::Value *vp) { static bool count(JSContext *cx, unsigned argc, JS::Value *vp) { JS::CallArgs args = CallArgsFromVp(argc, vp); // 1. Let map be the associated count map. - std::string concat = ""; - std::string label = ""; + std::string concat; + std::string label; if (args.hasDefined(0)) { auto label_val = args.get(0); auto label_string = core::encode(cx, label_val); @@ -653,13 +652,13 @@ static bool timeLog(JSContext *cx, unsigned argc, JS::Value *vp) { concat += std::to_string(duration); concat += "ms"; - std::string data = ""; + std::string data; if (args.length() > 1) { auto length = args.length(); JS::RootedObjectVector visitedObjects(cx); for (int i = 1; i < length; i++) { JS::HandleValue arg = args.get(i); - std::string source = ""; + std::string source; auto result = ToSource(cx, source, arg, &visitedObjects); if (result.isErr()) { return false; @@ -668,7 +667,7 @@ static bool timeLog(JSContext *cx, unsigned argc, JS::Value *vp) { if (source[0] == '"' && source[source.length() - 1] == '"') { source = source.substr(1, source.length() - 2); } - if (data.length()) { + if (static_cast(!data.empty()) != 0U) { data += " "; data += source; } else { @@ -735,10 +734,10 @@ static bool timeEnd(JSContext *cx, unsigned argc, JS::Value *vp) { static bool dir(JSContext *cx, unsigned argc, JS::Value *vp) { JS::CallArgs args = CallArgsFromVp(argc, vp); - std::string fullLogLine = ""; + std::string fullLogLine; JS::RootedObjectVector visitedObjects(cx); JS::HandleValue arg = args.get(0); - std::string source = ""; + std::string source; auto result = ToSource(cx, source, arg, &visitedObjects); if (result.isErr()) { return false; @@ -747,7 +746,7 @@ static bool dir(JSContext *cx, unsigned argc, JS::Value *vp) { if (source[0] == '"' && source[source.length() - 1] == '"') { source = source.substr(1, source.length() - 2); } - if (fullLogLine.length()) { + if (static_cast(!fullLogLine.empty()) != 0U) { fullLogLine += " "; fullLogLine += source; } else { @@ -766,10 +765,10 @@ static bool trace(JSContext *cx, unsigned argc, JS::Value *vp) { // representation of the callstack from where this function was called. JS::RootedObject stack(cx); - if (!CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::MaxFrames(1u << 7)))) { + if (!CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::MaxFrames(1U << 7)))) { return false; } - auto principals = JS::GetRealmPrincipals(JS::GetCurrentRealmOrNull(cx)); + auto *principals = JS::GetRealmPrincipals(JS::GetCurrentRealmOrNull(cx)); JS::RootedString str(cx); if (!BuildStackString(cx, principals, stack, &str)) { return false; @@ -781,11 +780,11 @@ static bool trace(JSContext *cx, unsigned argc, JS::Value *vp) { // 2. Optionally, let formattedData be the result of Formatter(data), and // incorporate formattedData as a label for trace. - std::string fullLogLine = ""; + std::string fullLogLine; JS::RootedObjectVector visitedObjects(cx); for (int i = 0; i < args.length(); i++) { JS::HandleValue arg = args.get(i); - std::string source = ""; + std::string source; auto result = ToSource(cx, source, arg, &visitedObjects); if (result.isErr()) { return false; @@ -794,7 +793,7 @@ static bool trace(JSContext *cx, unsigned argc, JS::Value *vp) { if (source[0] == '"' && source[source.length() - 1] == '"') { source = source.substr(1, source.length() - 2); } - if (fullLogLine.length()) { + if (static_cast(!fullLogLine.empty()) != 0U) { fullLogLine += " "; fullLogLine += source; } else { diff --git a/builtins/web/console.h b/builtins/web/console.h index 89f86a6c..848d4db8 100644 --- a/builtins/web/console.h +++ b/builtins/web/console.h @@ -9,14 +9,14 @@ class Console : public BuiltinNoConstructor { private: public: static constexpr const char *class_name = "Console"; - enum LogType { + enum LogType : uint8_t { Log, Info, Debug, Warn, Error, }; - enum Slots { Count }; + enum Slots : uint8_t { Count }; static const JSFunctionSpec methods[]; static const JSPropertySpec properties[]; }; diff --git a/builtins/web/crypto/crypto-algorithm.cpp b/builtins/web/crypto/crypto-algorithm.cpp index ed61fd22..7538143e 100644 --- a/builtins/web/crypto/crypto-algorithm.cpp +++ b/builtins/web/crypto/crypto-algorithm.cpp @@ -23,7 +23,7 @@ using dom_exception::DOMException; // namespace { -int num_bits_to_bytes(int x) { return (x / 8) + (7 + (x % 8)) / 8; } +int num_bits_to_bytes(int x) { return (x / 8) + ((7 + (x % 8)) / 8); } std::pair, size_t> to_bytes_expand(JSContext *cx, const BIGNUM *bignum, size_t minimumBufferSize) { @@ -35,12 +35,11 @@ to_bytes_expand(JSContext *cx, const BIGNUM *bignum, size_t minimumBufferSize) { size_t paddingLength = bufferSize - length; if (paddingLength > 0) { - uint8_t padding = BN_is_negative(bignum) ? 0xFF : 0x00; + uint8_t padding = (BN_is_negative(bignum) != 0) ? 0xFF : 0x00; std::fill_n(bytes.get(), paddingLength, padding); } BN_bn2bin(bignum, bytes.get() + paddingLength); - return std::pair, size_t>(std::move(bytes), - bufferSize); + return { std::move(bytes), bufferSize }; } const EVP_MD *createDigestAlgorithm(JSContext *cx, CryptoAlgorithmIdentifier hashIdentifier) { @@ -89,28 +88,33 @@ const EVP_MD *createDigestAlgorithm(JSContext *cx, JS::HandleObject key) { std::string_view name = name_chars; if (name == "MD5") { return EVP_md5(); - } else if (name == "SHA-1") { + } + if (name == "SHA-1") { return EVP_sha1(); - } else if (name == "SHA-224") { + } + if (name == "SHA-224") { return EVP_sha224(); - } else if (name == "SHA-256") { + } + if (name == "SHA-256") { return EVP_sha256(); - } else if (name == "SHA-384") { + } + if (name == "SHA-384") { return EVP_sha384(); - } else if (name == "SHA-512") { + } + if (name == "SHA-512") { return EVP_sha512(); - } else { - DOMException::raise(cx, "NotSupportedError", "NotSupportedError"); - return nullptr; } + + DOMException::raise(cx, "NotSupportedError", "NotSupportedError"); + return nullptr; } // This implements https://w3c.github.io/webcrypto/#sha-operations for all // the SHA algorithms that we support. std::optional> rawDigest(JSContext *cx, std::span data, const EVP_MD *algorithm, size_t buffer_size) { - unsigned int size; + unsigned int size = 0; std::vector buf(buffer_size, 0); - if (!EVP_Digest(data.data(), data.size(), buf.data(), &size, algorithm, NULL)) { + if (EVP_Digest(data.data(), data.size(), buf.data(), &size, algorithm, nullptr) == 0) { // 2. If performing the operation results in an error, then throw an OperationError. DOMException::raise(cx, "SubtleCrypto.digest: failed to create digest", "OperationError"); return std::nullopt; @@ -122,14 +126,14 @@ std::optional> rawDigest(JSContext *cx, std::span // the SHA algorithms that we support. JSObject *digest(JSContext *cx, std::span data, const EVP_MD *algorithm, size_t buffer_size) { - unsigned int size; + unsigned int size = 0; mozilla::UniquePtr buf{ static_cast(JS_malloc(cx, buffer_size))}; if (!buf) { JS_ReportOutOfMemory(cx); return nullptr; } - if (!EVP_Digest(data.data(), data.size(), buf.get(), &size, algorithm, NULL)) { + if (EVP_Digest(data.data(), data.size(), buf.get(), &size, algorithm, nullptr) == 0) { // 2. If performing the operation results in an error, then throw an OperationError. DOMException::raise(cx, "SubtleCrypto.digest: failed to create digest", "OperationError"); return nullptr; @@ -250,7 +254,7 @@ std::unique_ptr createRSAPrivateKeyFromJWK(JSContext *cx // then throw a DataError. 2.10.2 Let privateKey represents the RSA private key identified by // interpreting jwk according to Section 6.3.2 of JSON Web Algorithms [JWA]. 2.10.3 If privateKey // is not a valid RSA private key according to [RFC3447], then throw a DataError. - auto modulusResult = base64::forgivingBase64Decode(jwk->n.value(), base64::base64URLDecodeTable); + auto modulusResult = base64::forgivingBase64Decode(jwk->n.value_or(""), base64::base64URLDecodeTable); if (modulusResult.isErr()) { DOMException::raise( cx, "The JWK member 'n' could not be base64url decoded or contained padding", "DataError"); @@ -261,7 +265,7 @@ std::unique_ptr createRSAPrivateKeyFromJWK(JSContext *cx if (modulus.starts_with('0')) { modulus = modulus.erase(0, 1); } - auto dataResult = base64::stringToJSByteString(cx, jwk->e.value()); + auto dataResult = base64::stringToJSByteString(cx, jwk->e.value_or("")); if (dataResult.isErr()) { DOMException::raise(cx, "Data provided to an operation does not meet requirements", "DataError"); @@ -276,7 +280,7 @@ std::unique_ptr createRSAPrivateKeyFromJWK(JSContext *cx } auto exponent = exponentResult.unwrap(); auto privateExponentResult = - base64::forgivingBase64Decode(jwk->d.value(), base64::base64URLDecodeTable); + base64::forgivingBase64Decode(jwk->d.value_or(""), base64::base64URLDecodeTable); if (privateExponentResult.isErr()) { DOMException::raise( cx, "The JWK member 'd' could not be base64url decoded or contained padding", "DataError"); @@ -343,7 +347,7 @@ std::unique_ptr createRSAPrivateKeyFromJWK(JSContext *cx CryptoKeyRSAComponents::PrimeInfo secondPrimeInfo{secondPrimeFactor, secondFactorCRTExponent, secondFactorCRTCoefficient}; - if (!jwk->oth.size()) { + if (jwk->oth.empty()) { auto privateKeyComponents = CryptoKeyRSAComponents::createPrivateWithAdditionalData( modulus, exponent, privateExponent, firstPrimeInfo, secondPrimeInfo, {}); return privateKeyComponents; @@ -388,9 +392,11 @@ JS::Result toHashIdentifier(JSContext *cx, JS::Handle std::optional toNamedCurve(std::string_view name) { if (name == "P-256") { return NamedCurve::P256; - } else if (name == "P-384") { + } + if (name == "P-384") { return NamedCurve::P384; - } else if (name == "P-521") { + } + if (name == "P-521") { return NamedCurve::P521; } @@ -402,9 +408,8 @@ JS::Result toNamedCurve(JSContext *cx, JS::HandleValue value) { auto name = toNamedCurve(nameChars); if (name.has_value()) { return name.value(); - } else { - return JS::Result(JS::Error()); } + return JS::Result(JS::Error()); } JS::Result curveSize(JSContext *cx, JS::HandleObject key) { @@ -420,9 +425,11 @@ JS::Result curveSize(JSContext *cx, JS::HandleObject key) { std::string_view namedCurve = namedCurve_chars; if (namedCurve == "P-256") { return 256; - } else if (namedCurve == "P-384") { + } + if (namedCurve == "P-384") { return 384; - } else if (namedCurve == "P-521") { + } + if (namedCurve == "P-521") { return 521; } @@ -492,43 +499,59 @@ JS::Result normalizeIdentifier(JSContext *cx, JS::Han [](unsigned char c) { return std::toupper(c); }); if (algorithm == "RSASSA-PKCS1-V1_5") { return CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5; - } else if (algorithm == "RSA-PSS") { + } + if (algorithm == "RSA-PSS") { return CryptoAlgorithmIdentifier::RSA_PSS; - } else if (algorithm == "RSA-OAEP") { + } + if (algorithm == "RSA-OAEP") { return CryptoAlgorithmIdentifier::RSA_OAEP; - } else if (algorithm == "ECDSA") { + } + if (algorithm == "ECDSA") { return CryptoAlgorithmIdentifier::ECDSA; - } else if (algorithm == "ECDH") { + } + if (algorithm == "ECDH") { return CryptoAlgorithmIdentifier::ECDH; - } else if (algorithm == "AES-CTR") { + } + if (algorithm == "AES-CTR") { return CryptoAlgorithmIdentifier::AES_CTR; - } else if (algorithm == "AES-CBC") { + } + if (algorithm == "AES-CBC") { return CryptoAlgorithmIdentifier::AES_CBC; - } else if (algorithm == "AES-GCM") { + } + if (algorithm == "AES-GCM") { return CryptoAlgorithmIdentifier::AES_GCM; - } else if (algorithm == "AES-KW") { + } + if (algorithm == "AES-KW") { return CryptoAlgorithmIdentifier::AES_KW; - } else if (algorithm == "HMAC") { + } + if (algorithm == "HMAC") { return CryptoAlgorithmIdentifier::HMAC; - } else if (algorithm == "MD5") { + } + if (algorithm == "MD5") { return CryptoAlgorithmIdentifier::MD5; - } else if (algorithm == "SHA-1") { + } + if (algorithm == "SHA-1") { return CryptoAlgorithmIdentifier::SHA_1; - } else if (algorithm == "SHA-256") { + } + if (algorithm == "SHA-256") { return CryptoAlgorithmIdentifier::SHA_256; - } else if (algorithm == "SHA-384") { + } + if (algorithm == "SHA-384") { return CryptoAlgorithmIdentifier::SHA_384; - } else if (algorithm == "SHA-512") { + } + if (algorithm == "SHA-512") { return CryptoAlgorithmIdentifier::SHA_512; - } else if (algorithm == "HKDF") { + } + if (algorithm == "HKDF") { return CryptoAlgorithmIdentifier::HKDF; - } else if (algorithm == "PBKDF2") { + } + if (algorithm == "PBKDF2") { return CryptoAlgorithmIdentifier::PBKDF2; - } else { - // Otherwise: Return a new NotSupportedError and terminate this algorithm. - DOMException::raise(cx, "Algorithm: Unrecognized name", "NotSupportedError"); - return JS::Result(JS::Error()); } + + // Otherwise: Return a new NotSupportedError and terminate this algorithm. + DOMException::raise(cx, "Algorithm: Unrecognized name", "NotSupportedError"); + return JS::Result(JS::Error()); } // } // namespace @@ -683,7 +706,7 @@ CryptoAlgorithmSignVerify::normalize(JSContext *cx, JS::HandleValue value) { // The value can either be a JS String or a JS Object with a 'name' property which is the algorithm identifier. // Other properties within the object will be the parameters for the algorithm to use. if (value.isString()) { - auto obj = JS_NewPlainObject(cx); + auto *obj = JS_NewPlainObject(cx); params.set(obj); if (!JS_SetProperty(cx, params, "name", value)) { return nullptr; @@ -773,7 +796,7 @@ JSObject *CryptoAlgorithmHMAC_Sign_Verify::sign(JSContext *cx, JS::HandleObject return nullptr; } auto sig = std::move(result.value().first); - auto size = std::move(result.value().second); + auto size = result.value().second; // 2. Return a new ArrayBuffer object, associated with the relevant global object of this [HTML], and containing the bytes of mac. JS::RootedObject array_buffer(cx); @@ -805,7 +828,7 @@ JS::Result CryptoAlgorithmHMAC_Sign_Verify::verify(JSContext *cx, JS::Hand return JS::Result(JS::Error()); } auto sig = std::move(result.value().first); - auto size = std::move(result.value().second); + auto size = result.value().second; // 2. Return true if mac is equal to signature and false otherwise. @@ -839,7 +862,7 @@ JSObject *CryptoAlgorithmECDSA_Sign_Verify::sign(JSContext *cx, JS::HandleObject return nullptr; } - auto digest = digestOption.value(); + const auto& digest = digestOption.value(); // 4. Let d be the ECDSA private key associated with key. EVP_PKEY *pkey = CryptoKey::key(key); @@ -885,7 +908,8 @@ JSObject *CryptoAlgorithmECDSA_Sign_Verify::sign(JSContext *cx, JS::HandleObject // Convert s to an octet string of length n and append this sequence of bytes to result. // Otherwise, the namedCurve attribute of the [[algorithm]] internal slot of key is a value specified in an applicable specification: // Perform the ECDSA signature steps specified in that specification, passing in M, params and d and resulting in result. - const BIGNUM *r_raw, *s_raw; + const BIGNUM *r_raw = nullptr; + const BIGNUM *s_raw = nullptr; ECDSA_SIG_get0(sig.get(), &r_raw, &s_raw); size_t coord_size = num_bits_to_bytes(curveSize(cx, key).unwrap()); @@ -940,7 +964,7 @@ JS::Result CryptoAlgorithmECDSA_Sign_Verify::verify(JSContext *cx, JS::Han DOMException::raise(cx, "OperationError", "OperationError"); return JS::Result(JS::Error()); } - auto digest = digestOption.value(); + const auto& digest = digestOption.value(); // 4. Let Q be the ECDSA public key associated with key. // 5. Let params be the EC domain parameters associated with key. @@ -972,7 +996,7 @@ JS::Result CryptoAlgorithmECDSA_Sign_Verify::verify(JSContext *cx, JS::Han } EcdsaSigPtr sig(ECDSA_SIG_new()); - if (!sig || !ECDSA_SIG_set0(sig.get(), r.release(), s.release())) { + if (!sig || (ECDSA_SIG_set0(sig.get(), r.release(), s.release()) == 0)) { DOMException::raise(cx, "SubtleCrypto.verify: failed to verify", "OperationError"); return JS::Result(JS::Error()); } @@ -1067,7 +1091,7 @@ JSObject *CryptoAlgorithmRSASSA_PKCS1_v1_5_Sign_Verify::sign(JSContext *cx, JS:: return nullptr; } - size_t signature_length; + size_t signature_length = 0; if (EVP_PKEY_sign(ctx.get(), nullptr, &signature_length, digest->data(), digest->size()) <= 0) { DOMException::raise(cx, "OperationError", "OperationError"); return nullptr; @@ -1115,7 +1139,7 @@ JS::Result CryptoAlgorithmRSASSA_PKCS1_v1_5_Sign_Verify::verify(JSContext return JS::Result(JS::Error()); } - auto digest = digestOption.value(); + const auto& digest = digestOption.value(); EvpPkeyCtxPtr ctx(EVP_PKEY_CTX_new(CryptoKey::key(key), nullptr)); if (!ctx) { @@ -1157,7 +1181,7 @@ CryptoAlgorithmImportKey::normalize(JSContext *cx, JS::HandleValue value) { // The value can either be a JS String or a JS Object with a 'name' property which is the algorithm identifier. // Other properties within the object will be the parameters for the algorithm to use. if (value.isString()) { - auto obj = JS_NewPlainObject(cx); + auto *obj = JS_NewPlainObject(cx); params.set(obj); JS_SetProperty(cx, params, "name", value); } else if (value.isObject()) { @@ -1205,8 +1229,8 @@ std::unique_ptr CryptoAlgorithmHMAC_Import::fromPara if (hashIdentifier.isErr()) { return nullptr; } - bool found; - unsigned long length; + bool found = false; + unsigned long length = 0; if (!JS_HasProperty(cx, parameters, "length", &found)) { return nullptr; } @@ -1220,14 +1244,13 @@ std::unique_ptr CryptoAlgorithmHMAC_Import::fromPara } length = length_val.toNumber(); return std::make_unique(hashIdentifier.unwrap(), length); - } else { - return std::make_unique(hashIdentifier.unwrap()); } + return std::make_unique(hashIdentifier.unwrap()); } // https://w3c.github.io/webcrypto/#hmac-operations JSObject *CryptoAlgorithmHMAC_Import::importKey(JSContext *cx, CryptoKeyFormat format, - KeyData keyData, bool extractable, + KeyData key_data, bool extractable, CryptoKeyUsages usages) { MOZ_ASSERT(cx); JS::RootedObject result(cx); @@ -1246,7 +1269,7 @@ JSObject *CryptoAlgorithmHMAC_Import::importKey(JSContext *cx, CryptoKeyFormat f // 5. If format is "raw": case CryptoKeyFormat::Raw: { // 5.1 Let data be the octet string contained in keyData. - data = std::make_unique>(std::get>(keyData)); + data = std::make_unique>(std::get>(key_data)); if (!data) { DOMException::raise(cx, "Supplied keyData must be either an ArrayBuffer, TypedArray, or DataView.", "DataError"); return nullptr; @@ -1262,7 +1285,7 @@ JSObject *CryptoAlgorithmHMAC_Import::importKey(JSContext *cx, CryptoKeyFormat f // 6.2 Let jwk equal keyData. // Otherwise: // 6.3 Throw a DataError. - auto jwk = std::get(keyData); + auto *jwk = std::get(key_data); if (!jwk) { DOMException::raise(cx, "Supplied keyData is not a JSONWebKey", "DataError"); return nullptr; @@ -1274,7 +1297,7 @@ JSObject *CryptoAlgorithmHMAC_Import::importKey(JSContext *cx, CryptoKeyFormat f // 6.6 Let data be the octet string obtained by decoding the k field of jwk. auto dataResult = base64::forgivingBase64Decode( - jwk->k.value(), base64::base64URLDecodeTable); + jwk->k.value_or(""), base64::base64URLDecodeTable); if (dataResult.isErr()) { DOMException::raise(cx, "The JWK member 'k' could not be base64url decoded or contained padding", "DataError"); @@ -1337,7 +1360,7 @@ JSObject *CryptoAlgorithmHMAC_Import::importKey(JSContext *cx, CryptoKeyFormat f return nullptr; } // 6.15 If the key_ops field of jwk is present, and is invalid according to the requirements of JSON Web Key [JWK] or does not contain all of the specified usages values, then throw a DataError. - if (jwk->key_ops.size() > 0) { + if (!jwk->key_ops.empty()) { auto ops = CryptoKeyUsages::from(jwk->key_ops); if (!ops.isSuperSetOf(usages)) { DOMException::raise(cx, @@ -1376,16 +1399,17 @@ JSObject *CryptoAlgorithmHMAC_Import::importKey(JSContext *cx, CryptoKeyFormat f // throw a DataError. DOMException::raise(cx, "The optional HMAC key length must be shorter than the key data, and by no more than 7 bits.", "DataError"); return nullptr; + } + // 12. If the length member of normalizedAlgorithm, is less than or equal to length minus eight: - } else if (this->length.value() <= (length - 8)) { + if (this->length.value() <= (length - 8)) { // throw a DataError. DOMException::raise(cx, "The optional HMAC key length must be shorter than the key data, and by no more than 7 bits.", "DataError"); return nullptr; - // 13. Otherwise: - } else { - // 14. Set length equal to the length member of normalizedAlgorithm. - length = this->length.value(); } + // 13. Otherwise: + // 14. Set length equal to the length member of normalizedAlgorithm. + length = this->length.value(); } else { // This is because we need to capture the the length in the algorithm object which is created in CryptoAlgorithmHMAC_Import::toObject this->length = length; @@ -1401,7 +1425,7 @@ JSObject *CryptoAlgorithmHMAC_Import::importKey(JSContext *cx, CryptoKeyFormat f } JSObject *CryptoAlgorithmHMAC_Import::importKey(JSContext *cx, CryptoKeyFormat format, JS::HandleValue key_data, bool extractable, - CryptoKeyUsages usages) { + CryptoKeyUsages usages) { MOZ_ASSERT(cx); // The only supported formats for HMAC are raw, and jwk. if (format != CryptoKeyFormat::Raw && format != CryptoKeyFormat::Jwk) { @@ -1433,7 +1457,7 @@ JSObject *CryptoAlgorithmHMAC_Import::toObject(JSContext *cx) { JS::RootedObject algorithm(cx, JS_NewPlainObject(cx)); // Set the name attribute of algorithm to "HMAC" - auto alg_name = JS_NewStringCopyZ(cx, this->name()); + auto *alg_name = JS_NewStringCopyZ(cx, this->name()); if (!alg_name) { return nullptr; } @@ -1445,7 +1469,7 @@ JSObject *CryptoAlgorithmHMAC_Import::toObject(JSContext *cx) { // Set the hash attribute of algorithm to the hash member of normalizedAlgorithm. JS::RootedObject hash(cx, JS_NewObject(cx, nullptr)); - auto hash_name = JS_NewStringCopyZ(cx, algorithmName(this->hashIdentifier)); + auto *hash_name = JS_NewStringCopyZ(cx, algorithmName(this->hashIdentifier)); if (!hash_name) { return nullptr; } @@ -1468,7 +1492,7 @@ JSObject *CryptoAlgorithmHMAC_Import::toObject(JSContext *cx) { } JSObject *CryptoAlgorithmECDSA_Import::importKey(JSContext *cx, CryptoKeyFormat format, - KeyData keyData, bool extractable, + KeyData key_data, bool extractable, CryptoKeyUsages usages) { // 1. Let keyData be the key data to be imported. MOZ_ASSERT(cx); @@ -1482,7 +1506,7 @@ JSObject *CryptoAlgorithmECDSA_Import::importKey(JSContext *cx, CryptoKeyFormat // Let jwk equal keyData. // Otherwise: // Throw a DataError. - auto jwk = std::get(keyData); + auto *jwk = std::get(key_data); if (!jwk) { DOMException::raise(cx, "Supplied keyData is not a JSONWebKey", "DataError"); return nullptr; @@ -1508,7 +1532,7 @@ JSObject *CryptoAlgorithmECDSA_Import::importKey(JSContext *cx, CryptoKeyFormat return nullptr; } // 2.5. If the "key_ops" field of jwk is present, and is invalid according to the requirements of JSON Web Key, or it does not contain all of the specified usages values, then throw a DataError. - if (jwk->key_ops.size() > 0) { + if (!jwk->key_ops.empty()) { auto ops = CryptoKeyUsages::from(jwk->key_ops); if (!ops.isSuperSetOf(usages)) { DOMException::raise(cx, @@ -1523,7 +1547,7 @@ JSObject *CryptoAlgorithmECDSA_Import::importKey(JSContext *cx, CryptoKeyFormat return nullptr; } // 2.7. Let namedCurve be a string whose value is equal to the "crv" field of jwk. - auto namedCurve = toNamedCurve(jwk->crv.value()); + auto namedCurve = toNamedCurve(jwk->crv.value_or("")); // 2.8. If namedCurve is not equal to the namedCurve member of normalizedAlgorithm, throw a DataError. if (!namedCurve.has_value() || namedCurve.value() != this->namedCurve) { DOMException::raise(cx, "The JWK's \"crv\" member specifies a different curve than requested", "DataError"); @@ -1544,7 +1568,7 @@ JSObject *CryptoAlgorithmECDSA_Import::importKey(JSContext *cx, CryptoKeyFormat // throw a DataError. // 2.9.3. If algNamedCurve is defined, and is not equal to namedCurve, throw a DataError. if (jwk->alg.has_value()) { - auto algNamedCurve = toNamedCurve(jwk->crv.value()); + auto algNamedCurve = toNamedCurve(jwk->crv.value_or("")); if (!algNamedCurve.has_value() || algNamedCurve.value() != this->namedCurve) { DOMException::raise(cx, "Oopsie", "DataError"); return nullptr; @@ -1629,7 +1653,7 @@ JSObject *CryptoAlgorithmECDSA_Import::importKey(JSContext *cx, CryptoKeyFormat return nullptr; } - auto keyBytes = std::get>(keyData); + auto keyBytes = std::get>(key_data); const uint8_t *data = keyBytes.data(); EvpPkeyPtr pkey(d2i_PrivateKey(EVP_PKEY_NONE, nullptr, &data, keyBytes.size())); @@ -1645,8 +1669,8 @@ JSObject *CryptoAlgorithmECDSA_Import::importKey(JSContext *cx, CryptoKeyFormat char curve_name[64]; size_t curve_name_len = sizeof(curve_name); - if (!EVP_PKEY_get_utf8_string_param(pkey.get(), OSSL_PKEY_PARAM_GROUP_NAME, curve_name, - sizeof(curve_name), &curve_name_len)) { + if (EVP_PKEY_get_utf8_string_param(pkey.get(), OSSL_PKEY_PARAM_GROUP_NAME, curve_name, + sizeof(curve_name), &curve_name_len) == 0) { DOMException::raise(cx, "Failed to get EC curve name", "DataError"); return nullptr; } @@ -1673,9 +1697,9 @@ JSObject *CryptoAlgorithmECDSA_Import::importKey(JSContext *cx, CryptoKeyFormat BIGNUM *y_raw = nullptr; BIGNUM *d_raw = nullptr; - if (!EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_EC_PUB_X, &x_raw) || - !EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_EC_PUB_Y, &y_raw) || - !EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_PRIV_KEY, &d_raw)) { + if ((EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_EC_PUB_X, &x_raw) == 0) || + (EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_EC_PUB_Y, &y_raw) == 0) || + (EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_PRIV_KEY, &d_raw) == 0)) { DOMException::raise(cx, "Failed to extract EC parameters", "DataError"); return nullptr; } @@ -1689,7 +1713,7 @@ JSObject *CryptoAlgorithmECDSA_Import::importKey(JSContext *cx, CryptoKeyFormat return nullptr; } - size_t coordSize; + size_t coordSize = 0; switch (actualCurve) { case NamedCurve::P256: coordSize = 32; @@ -1761,12 +1785,12 @@ JSObject *CryptoAlgorithmECDSA_Import::importKey(JSContext *cx, CryptoKeyFormat return this->importKey(cx, format, data, extractable, usages); } -JSObject *CryptoAlgorithmECDSA_Import::toObject(JSContext *cx) { +JSObject *CryptoAlgorithmECDSA_Import::toObject(JSContext *cx) const { // Let algorithm be a new RsaHashedKeyAlgorithm dictionary. JS::RootedObject algorithm(cx, JS_NewPlainObject(cx)); // Set the name attribute of algorithm to "RSASSA-PKCS1-v1_5" - auto alg_name = JS_NewStringCopyZ(cx, this->name()); + auto *alg_name = JS_NewStringCopyZ(cx, this->name()); if (!alg_name) { return nullptr; } @@ -1778,7 +1802,7 @@ JSObject *CryptoAlgorithmECDSA_Import::toObject(JSContext *cx) { // Set the hash attribute of algorithm to the hash member of normalizedAlgorithm. JS::RootedObject hash(cx, JS_NewObject(cx, nullptr)); - auto curve_name = JS_NewStringCopyZ(cx, curveName(this->namedCurve)); + auto *curve_name = JS_NewStringCopyZ(cx, curveName(this->namedCurve)); if (!curve_name) { return nullptr; } @@ -1832,7 +1856,7 @@ std::unique_ptr CryptoAlgorithmRSASSA_P // https://w3c.github.io/webcrypto/#rsassa-pkcs1-operations JSObject *CryptoAlgorithmRSASSA_PKCS1_v1_5_Import::importKey(JSContext *cx, CryptoKeyFormat format, - KeyData keyData, bool extractable, + KeyData key_data, bool extractable, CryptoKeyUsages usages) { MOZ_ASSERT(cx); JS::RootedObject result(cx); @@ -1843,7 +1867,7 @@ JSObject *CryptoAlgorithmRSASSA_PKCS1_v1_5_Import::importKey(JSContext *cx, Cryp // Let jwk equal keyData. // Otherwise: // Throw a DataError. - auto jwk = std::get(keyData); + auto *jwk = std::get(key_data); if (!jwk) { DOMException::raise(cx, "Supplied keyData is not a JSONWebKey", "DataError"); return nullptr; @@ -1883,7 +1907,7 @@ JSObject *CryptoAlgorithmRSASSA_PKCS1_v1_5_Import::importKey(JSContext *cx, Cryp // 2.5. If the key_ops field of jwk is present, and is invalid according to // the requirements of JSON Web Key [JWK] or does not contain all of the // specified usages values, then throw a DataError. - if (jwk->key_ops.size() > 0) { + if (!jwk->key_ops.empty()) { auto ops = CryptoKeyUsages::from(jwk->key_ops); if (!ops.isSuperSetOf(usages)) { DOMException::raise(cx, @@ -1983,7 +2007,7 @@ JSObject *CryptoAlgorithmRSASSA_PKCS1_v1_5_Import::importKey(JSContext *cx, Cryp return nullptr; } - auto keyBytes = std::get>(keyData); + auto keyBytes = std::get>(key_data); const uint8_t *data = keyBytes.data(); auto pkey_deleter = [](EVP_PKEY *pkey) { EVP_PKEY_free(pkey); }; @@ -2005,9 +2029,9 @@ JSObject *CryptoAlgorithmRSASSA_PKCS1_v1_5_Import::importKey(JSContext *cx, Cryp BIGNUM *e_raw = nullptr; BIGNUM *d_raw = nullptr; - if (!EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_RSA_N, &n_raw) || - !EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_RSA_E, &e_raw) || - !EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_RSA_D, &d_raw)) { + if ((EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_RSA_N, &n_raw) == 0) || + (EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_RSA_E, &e_raw) == 0) || + (EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_RSA_D, &d_raw) == 0)) { DOMException::raise(cx, "Failed to extract RSA parameters", "DataError"); return nullptr; } @@ -2042,51 +2066,51 @@ JSObject *CryptoAlgorithmRSASSA_PKCS1_v1_5_Import::importKey(JSContext *cx, Cryp BIGNUM *iqmp_raw = nullptr; bool has_crt_params = - EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_RSA_FACTOR1, &p_raw) && - EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_RSA_FACTOR2, &q_raw) && - EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_RSA_EXPONENT1, &dmp1_raw) && - EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_RSA_EXPONENT2, &dmq1_raw) && - EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_RSA_COEFFICIENT1, &iqmp_raw); - - if (has_crt_params) { - BignumPtr p(p_raw); - BignumPtr q(q_raw); - BignumPtr dmp1(dmp1_raw); - BignumPtr dmq1(dmq1_raw); - BignumPtr iqmp(iqmp_raw); - - int byte_len = BN_num_bytes(n.get()); - - auto [p_bytes, p_size] = to_bytes_expand(cx, p.get(), byte_len); - auto [q_bytes, q_size] = to_bytes_expand(cx, q.get(), byte_len); - auto [dp_bytes, dp_size] = to_bytes_expand(cx, dmp1.get(), byte_len); - auto [dq_bytes, dq_size] = to_bytes_expand(cx, dmq1.get(), byte_len); - auto [qi_bytes, qi_size] = to_bytes_expand(cx, iqmp.get(), byte_len); - - if (!p_bytes || !q_bytes || !dp_bytes || !dq_bytes || !qi_bytes) { - JS_ReportOutOfMemory(cx); - return nullptr; - } + (EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_RSA_FACTOR1, &p_raw) != 0) && + (EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_RSA_FACTOR2, &q_raw) != 0) && + (EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_RSA_EXPONENT1, &dmp1_raw) != 0) && + (EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_RSA_EXPONENT2, &dmq1_raw) != 0) && + (EVP_PKEY_get_bn_param(pkey.get(), OSSL_PKEY_PARAM_RSA_COEFFICIENT1, &iqmp_raw) != 0); - std::string_view p_sv(reinterpret_cast(p_bytes.get()), p_size); - std::string_view q_sv(reinterpret_cast(q_bytes.get()), q_size); - std::string_view dp_sv(reinterpret_cast(dp_bytes.get()), dp_size); - std::string_view dq_sv(reinterpret_cast(dq_bytes.get()), dq_size); - std::string_view qi_sv(reinterpret_cast(qi_bytes.get()), qi_size); + if (!has_crt_params) { + auto key = CryptoKeyRSAComponents::createPrivate(modulus_sv, exponent_sv, priv_exponent_sv); + return CryptoKey::createRSA(cx, this, std::move(key), extractable, usages); + } - // Create prime info structures - CryptoKeyRSAComponents::PrimeInfo prime1(p_sv, dp_sv); - CryptoKeyRSAComponents::PrimeInfo prime2(q_sv, dq_sv, qi_sv); + BignumPtr p(p_raw); + BignumPtr q(q_raw); + BignumPtr dmp1(dmp1_raw); + BignumPtr dmq1(dmq1_raw); + BignumPtr iqmp(iqmp_raw); - // Create RSA key with CRT parameters - auto rsa_key = CryptoKeyRSAComponents::createPrivateWithAdditionalData( - modulus_sv, exponent_sv, priv_exponent_sv, prime1, prime2, {}); + int byte_len = BN_num_bytes(n.get()); - return CryptoKey::createRSA(cx, this, std::move(rsa_key), extractable, usages); - } else { - auto key = CryptoKeyRSAComponents::createPrivate(modulus_sv, exponent_sv, priv_exponent_sv); - return CryptoKey::createRSA(cx, this, std::move(key), extractable, usages); + auto [p_bytes, p_size] = to_bytes_expand(cx, p.get(), byte_len); + auto [q_bytes, q_size] = to_bytes_expand(cx, q.get(), byte_len); + auto [dp_bytes, dp_size] = to_bytes_expand(cx, dmp1.get(), byte_len); + auto [dq_bytes, dq_size] = to_bytes_expand(cx, dmq1.get(), byte_len); + auto [qi_bytes, qi_size] = to_bytes_expand(cx, iqmp.get(), byte_len); + + if (!p_bytes || !q_bytes || !dp_bytes || !dq_bytes || !qi_bytes) { + JS_ReportOutOfMemory(cx); + return nullptr; } + + std::string_view p_sv(reinterpret_cast(p_bytes.get()), p_size); + std::string_view q_sv(reinterpret_cast(q_bytes.get()), q_size); + std::string_view dp_sv(reinterpret_cast(dp_bytes.get()), dp_size); + std::string_view dq_sv(reinterpret_cast(dq_bytes.get()), dq_size); + std::string_view qi_sv(reinterpret_cast(qi_bytes.get()), qi_size); + + // Create prime info structures + CryptoKeyRSAComponents::PrimeInfo prime1(p_sv, dp_sv); + CryptoKeyRSAComponents::PrimeInfo prime2(q_sv, dq_sv, qi_sv); + + // Create RSA key with CRT parameters + auto rsa_key = CryptoKeyRSAComponents::createPrivateWithAdditionalData( + modulus_sv, exponent_sv, priv_exponent_sv, prime1, prime2, {}); + + return CryptoKey::createRSA(cx, this, std::move(rsa_key), extractable, usages); } case CryptoKeyFormat::Spki: { // TODO: Add implementations for these @@ -2131,12 +2155,12 @@ JSObject *CryptoAlgorithmRSASSA_PKCS1_v1_5_Import::importKey(JSContext *cx, return this->importKey(cx, format, data, extractable, usages); } -JSObject *CryptoAlgorithmRSASSA_PKCS1_v1_5_Import::toObject(JSContext *cx) { +JSObject *CryptoAlgorithmRSASSA_PKCS1_v1_5_Import::toObject(JSContext *cx) const { // Let algorithm be a new RsaHashedKeyAlgorithm dictionary. JS::RootedObject algorithm(cx, JS_NewPlainObject(cx)); // Set the name attribute of algorithm to "RSASSA-PKCS1-v1_5" - auto alg_name = JS_NewStringCopyZ(cx, this->name()); + auto *alg_name = JS_NewStringCopyZ(cx, this->name()); if (!alg_name) { return nullptr; } @@ -2148,7 +2172,7 @@ JSObject *CryptoAlgorithmRSASSA_PKCS1_v1_5_Import::toObject(JSContext *cx) { // Set the hash attribute of algorithm to the hash member of normalizedAlgorithm. JS::RootedObject hash(cx, JS_NewObject(cx, nullptr)); - auto hash_name = JS_NewStringCopyZ(cx, algorithmName(this->hashIdentifier)); + auto *hash_name = JS_NewStringCopyZ(cx, algorithmName(this->hashIdentifier)); if (!hash_name) { return nullptr; } diff --git a/builtins/web/crypto/crypto-algorithm.h b/builtins/web/crypto/crypto-algorithm.h index 70d31aa2..df468d79 100644 --- a/builtins/web/crypto/crypto-algorithm.h +++ b/builtins/web/crypto/crypto-algorithm.h @@ -10,9 +10,9 @@ #include #include -namespace builtins { -namespace web { -namespace crypto { + + +namespace builtins::web::crypto { // We are defining all the algorithms from // https://w3c.github.io/webcrypto/#issue-container-generatedID-15 @@ -47,9 +47,16 @@ const char *algorithmName(CryptoAlgorithmIdentifier algorithm); /// The base class that all algorithm implementations should derive from. class CryptoAlgorithm { public: + CryptoAlgorithm() = default; virtual ~CryptoAlgorithm() = default; - virtual const char *name() const noexcept = 0; + CryptoAlgorithm(const CryptoAlgorithm &) = default; + CryptoAlgorithm(CryptoAlgorithm &&) = default; + + CryptoAlgorithm &operator=(const CryptoAlgorithm &) = default; + CryptoAlgorithm &operator=(CryptoAlgorithm &&) = default; + + [[nodiscard]] virtual const char *name() const noexcept = 0; virtual CryptoAlgorithmIdentifier identifier() = 0; }; @@ -74,15 +81,15 @@ class CryptoAlgorithmSignVerify : public CryptoAlgorithm { class CryptoAlgorithmHMAC_Sign_Verify final : public CryptoAlgorithmSignVerify { public: - const char *name() const noexcept override { return "HMAC"; }; - CryptoAlgorithmHMAC_Sign_Verify(){}; + [[nodiscard]] const char *name() const noexcept override { return "HMAC"; }; + CryptoAlgorithmHMAC_Sign_Verify()= default; CryptoAlgorithmIdentifier identifier() final { return CryptoAlgorithmIdentifier::HMAC; }; JSObject *sign(JSContext *cx, JS::HandleObject key, std::span data) override; JS::Result verify(JSContext *cx, JS::HandleObject key, std::span signature, std::span data) override; static JSObject *exportKey(JSContext *cx, CryptoKeyFormat format, JS::HandleObject key); - JSObject *toObject(JSContext *cx); + static JSObject *toObject(JSContext *cx); }; class CryptoAlgorithmECDSA_Sign_Verify final : public CryptoAlgorithmSignVerify { @@ -90,7 +97,7 @@ class CryptoAlgorithmECDSA_Sign_Verify final : public CryptoAlgorithmSignVerify // The hash member describes the hash algorithm to use. CryptoAlgorithmIdentifier hashIdentifier; - const char *name() const noexcept override { return "ECDSA"; }; + [[nodiscard]] const char *name() const noexcept override { return "ECDSA"; }; CryptoAlgorithmECDSA_Sign_Verify(CryptoAlgorithmIdentifier hashIdentifier) : hashIdentifier{hashIdentifier} {}; @@ -103,7 +110,7 @@ class CryptoAlgorithmECDSA_Sign_Verify final : public CryptoAlgorithmSignVerify JSObject *sign(JSContext *cx, JS::HandleObject key, std::span data) override; JS::Result verify(JSContext *cx, JS::HandleObject key, std::span signature, std::span data) override; - JSObject *toObject(JSContext *cx); + static JSObject *toObject(JSContext *cx); }; class CryptoAlgorithmECDSA_Import final : public CryptoAlgorithmImportKey { @@ -111,7 +118,7 @@ class CryptoAlgorithmECDSA_Import final : public CryptoAlgorithmImportKey { // A named curve. NamedCurve namedCurve; - const char *name() const noexcept override { return "ECDSA"; }; + [[nodiscard]] const char *name() const noexcept override { return "ECDSA"; }; CryptoAlgorithmECDSA_Import(NamedCurve namedCurve) : namedCurve{namedCurve} {}; // https://www.w3.org/TR/WebCryptoAPI/#EcKeyImportParams-dictionary @@ -121,17 +128,17 @@ class CryptoAlgorithmECDSA_Import final : public CryptoAlgorithmImportKey { CryptoAlgorithmIdentifier identifier() final { return CryptoAlgorithmIdentifier::ECDSA; }; - JSObject *importKey(JSContext *cx, CryptoKeyFormat format, JS::HandleValue, bool extractable, + JSObject *importKey(JSContext *cx, CryptoKeyFormat format, JS::HandleValue key_data, bool extractable, CryptoKeyUsages usages) override; - JSObject *importKey(JSContext *cx, CryptoKeyFormat format, KeyData, bool extractable, + JSObject *importKey(JSContext *cx, CryptoKeyFormat format, KeyData key_data, bool extractable, CryptoKeyUsages usages) override; - JSObject *toObject(JSContext *cx); + JSObject *toObject(JSContext *cx) const; }; class CryptoAlgorithmRSASSA_PKCS1_v1_5_Sign_Verify final : public CryptoAlgorithmSignVerify { public: - const char *name() const noexcept override { return "RSASSA-PKCS1-v1_5"; }; - CryptoAlgorithmRSASSA_PKCS1_v1_5_Sign_Verify(){}; + [[nodiscard]] const char *name() const noexcept override { return "RSASSA-PKCS1-v1_5"; }; + CryptoAlgorithmRSASSA_PKCS1_v1_5_Sign_Verify()= default; CryptoAlgorithmIdentifier identifier() final { return CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5; }; @@ -147,7 +154,7 @@ class CryptoAlgorithmRSASSA_PKCS1_v1_5_Import final : public CryptoAlgorithmImpo // The hash member describes the hash algorithm to use. CryptoAlgorithmIdentifier hashIdentifier; - const char *name() const noexcept override { return "RSASSA-PKCS1-v1_5"; }; + [[nodiscard]] const char *name() const noexcept override { return "RSASSA-PKCS1-v1_5"; }; CryptoAlgorithmRSASSA_PKCS1_v1_5_Import(CryptoAlgorithmIdentifier hashIdentifier) : hashIdentifier{hashIdentifier} {}; @@ -160,11 +167,11 @@ class CryptoAlgorithmRSASSA_PKCS1_v1_5_Import final : public CryptoAlgorithmImpo return CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5; }; - JSObject *importKey(JSContext *cx, CryptoKeyFormat format, JS::HandleValue, bool extractable, + JSObject *importKey(JSContext *cx, CryptoKeyFormat format, JS::HandleValue key_data, bool extractable, CryptoKeyUsages usages) override; - JSObject *importKey(JSContext *cx, CryptoKeyFormat format, KeyData, bool extractable, + JSObject *importKey(JSContext *cx, CryptoKeyFormat format, KeyData key_data, bool extractable, CryptoKeyUsages usages) override; - JSObject *toObject(JSContext *cx); + JSObject *toObject(JSContext *cx) const; }; class CryptoAlgorithmHMAC_Import final : public CryptoAlgorithmImportKey { @@ -177,7 +184,7 @@ class CryptoAlgorithmHMAC_Import final : public CryptoAlgorithmImportKey { // hash algorithm defined in hashIdentifier. std::optional length; - const char *name() const noexcept override { return "HMAC"; }; + [[nodiscard]] const char *name() const noexcept override { return "HMAC"; }; CryptoAlgorithmHMAC_Import(CryptoAlgorithmIdentifier hashIdentifier) : hashIdentifier{hashIdentifier} {}; @@ -192,9 +199,9 @@ class CryptoAlgorithmHMAC_Import final : public CryptoAlgorithmImportKey { CryptoAlgorithmIdentifier identifier() final { return CryptoAlgorithmIdentifier::HMAC; }; - JSObject *importKey(JSContext *cx, CryptoKeyFormat format, JS::HandleValue, bool extractable, + JSObject *importKey(JSContext *cx, CryptoKeyFormat format, JS::HandleValue key_data, bool extractable, CryptoKeyUsages usages) override; - JSObject *importKey(JSContext *cx, CryptoKeyFormat format, KeyData, bool extractable, + JSObject *importKey(JSContext *cx, CryptoKeyFormat format, KeyData key_data, bool extractable, CryptoKeyUsages usages) override; JSObject *toObject(JSContext *cx); }; @@ -207,40 +214,40 @@ class CryptoAlgorithmDigest : public CryptoAlgorithm { class CryptoAlgorithmMD5 final : public CryptoAlgorithmDigest { public: - const char *name() const noexcept override { return "MD5"; }; + [[nodiscard]] const char *name() const noexcept override { return "MD5"; }; CryptoAlgorithmIdentifier identifier() override { return CryptoAlgorithmIdentifier::MD5; }; - JSObject *digest(JSContext *cx, std::span) override; + JSObject *digest(JSContext *cx, std::span data) override; }; class CryptoAlgorithmSHA1 final : public CryptoAlgorithmDigest { public: - const char *name() const noexcept override { return "SHA-1"; }; + [[nodiscard]] const char *name() const noexcept override { return "SHA-1"; }; CryptoAlgorithmIdentifier identifier() override { return CryptoAlgorithmIdentifier::SHA_1; }; - JSObject *digest(JSContext *cx, std::span) override; + JSObject *digest(JSContext *cx, std::span data) override; }; class CryptoAlgorithmSHA256 final : public CryptoAlgorithmDigest { public: - const char *name() const noexcept override { return "SHA-256"; }; + [[nodiscard]] const char *name() const noexcept override { return "SHA-256"; }; CryptoAlgorithmIdentifier identifier() override { return CryptoAlgorithmIdentifier::SHA_256; }; - JSObject *digest(JSContext *cx, std::span) override; + JSObject *digest(JSContext *cx, std::span data) override; }; class CryptoAlgorithmSHA384 final : public CryptoAlgorithmDigest { public: - const char *name() const noexcept override { return "SHA-384"; }; + [[nodiscard]] const char *name() const noexcept override { return "SHA-384"; }; CryptoAlgorithmIdentifier identifier() override { return CryptoAlgorithmIdentifier::SHA_384; }; - JSObject *digest(JSContext *cx, std::span) override; + JSObject *digest(JSContext *cx, std::span data) override; }; class CryptoAlgorithmSHA512 final : public CryptoAlgorithmDigest { public: - const char *name() const noexcept override { return "SHA-512"; }; + [[nodiscard]] const char *name() const noexcept override { return "SHA-512"; }; CryptoAlgorithmIdentifier identifier() override { return CryptoAlgorithmIdentifier::SHA_512; }; - JSObject *digest(JSContext *cx, std::span) override; + JSObject *digest(JSContext *cx, std::span data) override; }; -} // namespace crypto -} // namespace web -} // namespace builtins +} // namespace builtins::web::crypto + + #endif diff --git a/builtins/web/crypto/crypto-key-ec-components.h b/builtins/web/crypto/crypto-key-ec-components.h index e6667075..98383ecf 100644 --- a/builtins/web/crypto/crypto-key-ec-components.h +++ b/builtins/web/crypto/crypto-key-ec-components.h @@ -1,19 +1,20 @@ #ifndef BUILTINS_WEB_CRYPTO_CRYPTO_KEY_EC_COMPONENTS_H #define BUILTINS_WEB_CRYPTO_CRYPTO_KEY_EC_COMPONENTS_H + #include #include class CryptoKeyECComponents final { public: enum class Type : uint8_t { Public, Private }; - const Type type; + Type type; // Private and public keys. - const std::string x; - const std::string y; + std::string x; + std::string y; // Only private keys. - const std::string d; + std::string d; static std::unique_ptr createPublic(std::string_view x, std::string_view y); @@ -24,4 +25,5 @@ class CryptoKeyECComponents final { CryptoKeyECComponents(std::string_view x, std::string_view y, std::string_view d); }; -#endif \ No newline at end of file + +#endif diff --git a/builtins/web/crypto/crypto-key-rsa-components.cpp b/builtins/web/crypto/crypto-key-rsa-components.cpp index b669ba64..241939aa 100644 --- a/builtins/web/crypto/crypto-key-rsa-components.cpp +++ b/builtins/web/crypto/crypto-key-rsa-components.cpp @@ -1,5 +1,7 @@ #include "crypto-key-rsa-components.h" +#include + CryptoKeyRSAComponents::CryptoKeyRSAComponents(std::string_view modulus, std::string_view exponent) : type(Type::Public), modulus(modulus), exponent(exponent) {} @@ -10,8 +12,8 @@ CryptoKeyRSAComponents::createPublic(std::string_view modulus, std::string_view CryptoKeyRSAComponents::CryptoKeyRSAComponents(std::string_view modulus, std::string_view exponent, std::string_view privateExponent) - : type(Type::Private), modulus(modulus), exponent(exponent), privateExponent(privateExponent), - hasAdditionalPrivateKeyParameters(false) {} + : type(Type::Private), modulus(modulus), exponent(exponent), privateExponent(privateExponent) + {} std::unique_ptr CryptoKeyRSAComponents::createPrivate(std::string_view modulus, std::string_view exponent, @@ -25,13 +27,13 @@ CryptoKeyRSAComponents::CryptoKeyRSAComponents(std::string_view modulus, std::st std::optional secondPrimeInfo, std::vector otherPrimeInfos) : type(Type::Private), modulus(modulus), exponent(exponent), privateExponent(privateExponent), - hasAdditionalPrivateKeyParameters(true), firstPrimeInfo(firstPrimeInfo), - secondPrimeInfo(secondPrimeInfo), otherPrimeInfos(otherPrimeInfos) {} + hasAdditionalPrivateKeyParameters(true), firstPrimeInfo(std::move(firstPrimeInfo)), + secondPrimeInfo(std::move(secondPrimeInfo)), otherPrimeInfos(std::move(otherPrimeInfos)) {} std::unique_ptr CryptoKeyRSAComponents::createPrivateWithAdditionalData( std::string_view modulus, std::string_view exponent, std::string_view privateExponent, - std::optional firstPrimeInfo, std::optional secondPrimeInfo, - std::vector otherPrimeInfos) { + const std::optional& firstPrimeInfo, const std::optional& secondPrimeInfo, + const std::vector& otherPrimeInfos) { return std::make_unique(modulus, exponent, privateExponent, firstPrimeInfo, secondPrimeInfo, otherPrimeInfos); } diff --git a/builtins/web/crypto/crypto-key-rsa-components.h b/builtins/web/crypto/crypto-key-rsa-components.h index 77c68256..9e6b8e8e 100644 --- a/builtins/web/crypto/crypto-key-rsa-components.h +++ b/builtins/web/crypto/crypto-key-rsa-components.h @@ -1,5 +1,6 @@ #ifndef BUILTINS_WEB_CRYPTO_CRYPTO_KEY_RSA_COMPONENTS_H #define BUILTINS_WEB_CRYPTO_CRYPTO_KEY_RSA_COMPONENTS_H + #include #include #include @@ -20,20 +21,20 @@ class CryptoKeyRSAComponents final { PrimeInfo(std::string_view primeFactor) : primeFactor{primeFactor} {}; }; enum class Type : uint8_t { Public, Private }; - const Type type; + Type type; // Private and public keys. - const std::string modulus; - const std::string exponent; + std::string modulus; + std::string exponent; // Only private keys. - const std::string privateExponent; - const bool hasAdditionalPrivateKeyParameters = false; - const std::optional firstPrimeInfo; - const std::optional secondPrimeInfo; + std::string privateExponent; + bool hasAdditionalPrivateKeyParameters = false; + std::optional firstPrimeInfo; + std::optional secondPrimeInfo; // When three or more primes have been used, the number of array elements // is be the number of primes used minus two. - const std::vector otherPrimeInfos; + std::vector otherPrimeInfos; static std::unique_ptr createPublic(std::string_view modulus, std::string_view exponent); @@ -43,8 +44,8 @@ class CryptoKeyRSAComponents final { static std::unique_ptr createPrivateWithAdditionalData( std::string_view modulus, std::string_view exponent, std::string_view privateExponent, - std::optional firstPrimeInfo, std::optional secondPrimeInfo, - std::vector otherPrimeInfos); + const std::optional& firstPrimeInfo, const std::optional& secondPrimeInfo, + const std::vector& otherPrimeInfos); CryptoKeyRSAComponents(std::string_view modulus, std::string_view exponent); diff --git a/builtins/web/crypto/crypto-key.cpp b/builtins/web/crypto/crypto-key.cpp index eac064ed..1d9ef225 100644 --- a/builtins/web/crypto/crypto-key.cpp +++ b/builtins/web/crypto/crypto-key.cpp @@ -10,15 +10,15 @@ #include #include -namespace builtins { -namespace web { -namespace crypto { -CryptoKeyUsages::CryptoKeyUsages(uint8_t mask) { this->mask = mask; }; + +namespace builtins::web::crypto { + +CryptoKeyUsages::CryptoKeyUsages(uint8_t mask) : mask(mask) { }; CryptoKeyUsages::CryptoKeyUsages(bool encrypt, bool decrypt, bool sign, bool verify, bool derive_key, bool derive_bits, bool wrap_key, bool unwrap_key) { - this->mask = 0; + if (encrypt) { this->mask |= encrypt_flag; } @@ -45,7 +45,7 @@ CryptoKeyUsages::CryptoKeyUsages(bool encrypt, bool decrypt, bool sign, bool ver } }; -CryptoKeyUsages CryptoKeyUsages::from(std::vector key_usages) { +CryptoKeyUsages CryptoKeyUsages::from(const std::vector& key_usages) { uint8_t mask = 0; for (const auto &usage : key_usages) { if (usage == "encrypt") { @@ -66,11 +66,11 @@ CryptoKeyUsages CryptoKeyUsages::from(std::vector key_usages) { mask |= unwrap_key_flag; } } - return CryptoKeyUsages(mask); + return {mask}; } JS::Result CryptoKeyUsages::from(JSContext *cx, JS::HandleValue key_usages) { - bool key_usages_is_array; + bool key_usages_is_array = false; if (!JS::IsArrayObject(cx, key_usages, &key_usages_is_array)) { return JS::Result(JS::Error()); } @@ -84,7 +84,7 @@ JS::Result CryptoKeyUsages::from(JSContext *cx, JS::HandleValue } JS::RootedObject array(cx, &key_usages.toObject()); - uint32_t key_usages_length; + uint32_t key_usages_length = 0; if (!JS::GetArrayLength(cx, array, &key_usages_length)) { return JS::Result(JS::Error()); } @@ -138,7 +138,7 @@ bool CryptoKey::algorithm_get(JSContext *cx, unsigned argc, JS::Value *vp) { return api::throw_error(cx, api::Errors::WrongReceiver, "algorithm get", "CryptoKey"); } - auto algorithm = &JS::GetReservedSlot(self, Slots::Algorithm).toObject(); + auto *algorithm = &JS::GetReservedSlot(self, Slots::Algorithm).toObject(); JS::RootedObject result(cx, algorithm); if (!result) { return false; @@ -176,7 +176,7 @@ bool CryptoKey::type_get(JSContext *cx, unsigned argc, JS::Value *vp) { // convert it into it's JSString representation. switch (type) { case CryptoKeyType::Private: { - auto str = JS_AtomizeString(cx, "private"); + auto *str = JS_AtomizeString(cx, "private"); if (!str) { return false; } @@ -184,7 +184,7 @@ bool CryptoKey::type_get(JSContext *cx, unsigned argc, JS::Value *vp) { return true; } case CryptoKeyType::Public: { - auto str = JS_AtomizeString(cx, "public"); + auto *str = JS_AtomizeString(cx, "public"); if (!str) { return false; } @@ -192,7 +192,7 @@ bool CryptoKey::type_get(JSContext *cx, unsigned argc, JS::Value *vp) { return true; } case CryptoKeyType::Secret: { - auto str = JS_AtomizeString(cx, "secret"); + auto *str = JS_AtomizeString(cx, "secret"); if (!str) { return false; } @@ -336,7 +336,7 @@ BignumPtr make_bignum(std::string_view bytes) { return nullptr; } - auto bn = BN_bin2bn(reinterpret_cast(bytes.data()), + auto *bn = BN_bin2bn(reinterpret_cast(bytes.data()), static_cast(bytes.length()), nullptr); return BignumPtr(bn); } @@ -389,7 +389,7 @@ bool validate_key(JSContext *cx, const EvpPkeyPtr &pkey, bool has_private) { : EVP_PKEY_public_check(check_ctx.get()); if (valid != 1) { - auto reason = ERR_reason_error_string(ERR_get_error()); + const auto *reason = ERR_reason_error_string(ERR_get_error()); dom_exception::DOMException::raise(cx, "KeyValidation", reason); return false; } @@ -407,7 +407,7 @@ EvpPkeyPtr create_ec_key_from_parts(JSContext *cx, CryptoAlgorithmECDSA_Import * auto has_private_key = !private_key.empty(); auto curve_nid = curve_identifier(algorithm->namedCurve); - auto curve_name = get_curve_name(curve_nid); + const auto *curve_name = get_curve_name(curve_nid); MOZ_ASSERT(curve_name); auto group = EcGroupPtr(EC_GROUP_new_by_curve_name(curve_nid)); @@ -431,7 +431,7 @@ EvpPkeyPtr create_ec_key_from_parts(JSContext *cx, CryptoAlgorithmECDSA_Import * return nullptr; } - if (!EC_POINT_set_affine_coordinates(group.get(), point.get(), x_bn.get(), y_bn.get(), nullptr)) { + if (EC_POINT_set_affine_coordinates(group.get(), point.get(), x_bn.get(), y_bn.get(), nullptr) == 0) { return nullptr; } @@ -447,10 +447,10 @@ EvpPkeyPtr create_ec_key_from_parts(JSContext *cx, CryptoAlgorithmECDSA_Import * return nullptr; } - if (!OSSL_PARAM_BLD_push_utf8_string(bld.get(), OSSL_PKEY_PARAM_GROUP_NAME, curve_name, 0) || - !OSSL_PARAM_BLD_push_BN(bld.get(), OSSL_PKEY_PARAM_EC_PUB_X, x_bn.get()) || - !OSSL_PARAM_BLD_push_BN(bld.get(), OSSL_PKEY_PARAM_EC_PUB_Y, y_bn.get()) || - !OSSL_PARAM_BLD_push_octet_string(bld.get(), OSSL_PKEY_PARAM_PUB_KEY, pub_key, pub_key_len)) { + if ((OSSL_PARAM_BLD_push_utf8_string(bld.get(), OSSL_PKEY_PARAM_GROUP_NAME, curve_name, 0) == 0) || + (OSSL_PARAM_BLD_push_BN(bld.get(), OSSL_PKEY_PARAM_EC_PUB_X, x_bn.get()) == 0) || + (OSSL_PARAM_BLD_push_BN(bld.get(), OSSL_PKEY_PARAM_EC_PUB_Y, y_bn.get()) == 0) || + (OSSL_PARAM_BLD_push_octet_string(bld.get(), OSSL_PKEY_PARAM_PUB_KEY, pub_key, pub_key_len) == 0)) { return nullptr; } @@ -461,7 +461,7 @@ EvpPkeyPtr create_ec_key_from_parts(JSContext *cx, CryptoAlgorithmECDSA_Import * return nullptr; } - if (!OSSL_PARAM_BLD_push_BN(bld.get(), OSSL_PKEY_PARAM_PRIV_KEY, d_bn.get())) { + if (OSSL_PARAM_BLD_push_BN(bld.get(), OSSL_PKEY_PARAM_PRIV_KEY, d_bn.get()) == 0) { return nullptr; } } @@ -508,12 +508,12 @@ EvpPkeyPtr create_rsa_key_from_parts( } auto n_bn = make_bignum(modulus); - if (!n_bn || !OSSL_PARAM_BLD_push_BN(param_bld.get(), OSSL_PKEY_PARAM_RSA_N, n_bn.get())) { + if (!n_bn || (OSSL_PARAM_BLD_push_BN(param_bld.get(), OSSL_PKEY_PARAM_RSA_N, n_bn.get()) == 0)) { return nullptr; } auto e_bn = make_bignum(public_exponent); - if (!e_bn || !OSSL_PARAM_BLD_push_BN(param_bld.get(), OSSL_PKEY_PARAM_RSA_E, e_bn.get())) { + if (!e_bn || (OSSL_PARAM_BLD_push_BN(param_bld.get(), OSSL_PKEY_PARAM_RSA_E, e_bn.get()) == 0)) { return nullptr; } @@ -528,37 +528,37 @@ EvpPkeyPtr create_rsa_key_from_parts( bool is_private = !private_exponent.empty(); if (is_private) { d_bn = make_bignum(private_exponent); - if (!d_bn || !OSSL_PARAM_BLD_push_BN(param_bld.get(), OSSL_PKEY_PARAM_RSA_D, d_bn.get())) { + if (!d_bn || (OSSL_PARAM_BLD_push_BN(param_bld.get(), OSSL_PKEY_PARAM_RSA_D, d_bn.get()) == 0)) { return nullptr; } p_bn = make_bignum(prime1); if (!p_bn || - !OSSL_PARAM_BLD_push_BN(param_bld.get(), OSSL_PKEY_PARAM_RSA_FACTOR1, p_bn.get())) { + (OSSL_PARAM_BLD_push_BN(param_bld.get(), OSSL_PKEY_PARAM_RSA_FACTOR1, p_bn.get()) == 0)) { return nullptr; } q_bn = make_bignum(prime2); if (!q_bn || - !OSSL_PARAM_BLD_push_BN(param_bld.get(), OSSL_PKEY_PARAM_RSA_FACTOR2, q_bn.get())) { + (OSSL_PARAM_BLD_push_BN(param_bld.get(), OSSL_PKEY_PARAM_RSA_FACTOR2, q_bn.get()) == 0)) { return nullptr; } dmp1_bn = make_bignum(exponent1); if (!dmp1_bn || - !OSSL_PARAM_BLD_push_BN(param_bld.get(), OSSL_PKEY_PARAM_RSA_EXPONENT1, dmp1_bn.get())) { + (OSSL_PARAM_BLD_push_BN(param_bld.get(), OSSL_PKEY_PARAM_RSA_EXPONENT1, dmp1_bn.get()) == 0)) { return nullptr; } dmq1_bn = make_bignum(exponent2); if (!dmq1_bn || - !OSSL_PARAM_BLD_push_BN(param_bld.get(), OSSL_PKEY_PARAM_RSA_EXPONENT2, dmq1_bn.get())) { + (OSSL_PARAM_BLD_push_BN(param_bld.get(), OSSL_PKEY_PARAM_RSA_EXPONENT2, dmq1_bn.get()) == 0)) { return nullptr; } iqmp_bn = make_bignum(coefficient); if (!iqmp_bn || - !OSSL_PARAM_BLD_push_BN(param_bld.get(), OSSL_PKEY_PARAM_RSA_COEFFICIENT1, iqmp_bn.get())) { + (OSSL_PARAM_BLD_push_BN(param_bld.get(), OSSL_PKEY_PARAM_RSA_COEFFICIENT1, iqmp_bn.get()) == 0)) { return nullptr; } } @@ -717,26 +717,25 @@ JSObject *CryptoKey::createRSA(JSContext *cx, CryptoAlgorithmRSASSA_PKCS1_v1_5_I } // For private keys, we require the private exponent, as well as p and q prime information. - if (is_private) { - if (keyData->privateExponent.empty() || keyData->firstPrimeInfo->primeFactor.empty() || - keyData->secondPrimeInfo->primeFactor.empty()) { - return nullptr; - } - } - - const auto get_param = [=](std::string_view value) { - return is_private ? value : std::string_view{}; - }; - const auto get_param2 = [=](auto &&info, auto &&member) { - return (is_private && info) ? member : std::string_view{}; - }; - - auto private_exponent = get_param(keyData->privateExponent); - auto prime1 = get_param2(keyData->firstPrimeInfo, keyData->firstPrimeInfo->primeFactor); - auto prime2 = get_param2(keyData->secondPrimeInfo, keyData->secondPrimeInfo->primeFactor); - auto exponent1 = get_param2(keyData->firstPrimeInfo, keyData->firstPrimeInfo->factorCRTExponent); - auto exponent2 = get_param2(keyData->secondPrimeInfo, keyData->secondPrimeInfo->factorCRTExponent); - auto coeff = get_param2(keyData->secondPrimeInfo, keyData->secondPrimeInfo->factorCRTCoefficient); + // + // Linter is confused about unwrapping optional here, but we check that + // prime info has value for private keys before accessing its value. + // NOLINTBEGIN(bugprone-unchecked-optional-access) + if (is_private && + (keyData->privateExponent.empty() || !keyData->firstPrimeInfo.has_value() || + keyData->firstPrimeInfo->primeFactor.empty() || !keyData->secondPrimeInfo.has_value() || + keyData->secondPrimeInfo->primeFactor.empty())) { + return nullptr; + } + + auto none = std::string_view{}; + auto private_exponent = is_private ? keyData->privateExponent : none; + auto prime1 = is_private ? keyData->firstPrimeInfo.value().primeFactor : none; + auto prime2 = is_private ? keyData->secondPrimeInfo.value().primeFactor : none; + auto exponent1 = is_private ? keyData->firstPrimeInfo.value().factorCRTExponent : none; + auto exponent2 = is_private ? keyData->secondPrimeInfo.value().factorCRTExponent : none; + auto coeff = is_private ? keyData->secondPrimeInfo.value().factorCRTCoefficient : none; + // NOLINTEND(bugprone-unchecked-optional-access) auto pkey = create_rsa_key_from_parts(cx, keyData->modulus, keyData->exponent, private_exponent, prime1, prime2, exponent1, exponent2, coeff); @@ -811,7 +810,7 @@ CryptoKeyType CryptoKey::type(JSObject *self) { JSObject *CryptoKey::get_algorithm(JS::HandleObject self) { MOZ_ASSERT(is_instance(self)); - auto algorithm = JS::GetReservedSlot(self, Slots::Algorithm).toObjectOrNull(); + auto *algorithm = JS::GetReservedSlot(self, Slots::Algorithm).toObjectOrNull(); return algorithm; } @@ -822,9 +821,9 @@ EVP_PKEY *CryptoKey::key(JSObject *self) { std::span CryptoKey::hmacKeyData(JSObject *self) { MOZ_ASSERT(is_instance(self)); - return std::span( + return { static_cast(JS::GetReservedSlot(self, Slots::KeyData).toPrivate()), - JS::GetReservedSlot(self, Slots::KeyDataLength).toInt32()); + static_cast(JS::GetReservedSlot(self, Slots::KeyDataLength).toInt32())}; } JS::Result CryptoKey::is_algorithm(JSContext *cx, JS::HandleObject self, @@ -845,7 +844,7 @@ JS::Result CryptoKey::is_algorithm(JSContext *cx, JS::HandleObject self, if (!chars) { return JS::Result(JS::Error()); } - bool match; + bool match = false; if (!JS_StringEqualsAscii(cx, JS::ToString(cx, name_val), algorithmName(algorithm), &match)) { return JS::Result(JS::Error()); } @@ -868,6 +867,6 @@ bool CryptoKey::canVerify(JS::HandleObject self) { return usage.canVerify(); } -} // namespace crypto -} // namespace web -} // namespace builtins +} // namespace builtins::web::crypto + + diff --git a/builtins/web/crypto/crypto-key.h b/builtins/web/crypto/crypto-key.h index b0a358ba..632c7220 100644 --- a/builtins/web/crypto/crypto-key.h +++ b/builtins/web/crypto/crypto-key.h @@ -7,9 +7,9 @@ #include "crypto-key-rsa-components.h" #include "openssl/evp.h" -namespace builtins { -namespace web { -namespace crypto { + + +namespace builtins::web::crypto { enum class CryptoAlgorithmIdentifier : uint8_t; class CryptoAlgorithmRSASSA_PKCS1_v1_5_Import; class CryptoAlgorithmHMAC_Import; @@ -36,32 +36,32 @@ class CryptoKeyUsages { CryptoKeyUsages(uint8_t mask); CryptoKeyUsages(bool encrypt, bool decrypt, bool sign, bool verify, bool derive_key, bool derive_bits, bool wrap_key, bool unwrap_key); - static CryptoKeyUsages from(std::vector key_usages); + static CryptoKeyUsages from(const std::vector& key_usages); static JS::Result from(JSContext *cx, JS::HandleValue key_usages); - uint8_t toInt() { return this->mask; }; - - bool isEmpty() { return this->mask == 0; }; - bool isSuperSetOf(CryptoKeyUsages &other) { return this->mask & other.mask; }; - - bool canEncrypt() { return this->mask & encrypt_flag; }; - bool canDecrypt() { return this->mask & decrypt_flag; }; - bool canSign() { return this->mask & sign_flag; }; - bool canVerify() { return this->mask & verify_flag; }; - bool canDeriveKey() { return this->mask & derive_key_flag; }; - bool canDeriveBits() { return this->mask & derive_bits_flag; }; - bool canWrapKey() { return this->mask & wrap_key_flag; }; - bool canUnwrapKey() { return this->mask & unwrap_key_flag; }; - - bool canOnlyEncrypt() { return this->mask == encrypt_flag; }; - bool canOnlyDecrypt() { return this->mask == decrypt_flag; }; - bool canOnlySign() { return this->mask == sign_flag; }; - bool canOnlyVerify() { return this->mask == verify_flag; }; - bool canOnlySignOrVerify() { return this->mask & (sign_flag | verify_flag); }; - bool canOnlyDeriveKey() { return this->mask == derive_key_flag; }; - bool canOnlyDeriveBits() { return this->mask == derive_bits_flag; }; - bool canOnlyWrapKey() { return this->mask == wrap_key_flag; }; - bool canOnlyUnwrapKey() { return this->mask == unwrap_key_flag; }; + [[nodiscard]] uint8_t toInt() const { return this->mask; }; + + [[nodiscard]] bool isEmpty() const { return this->mask == 0; }; + bool isSuperSetOf(CryptoKeyUsages &other) const { return (this->mask & other.mask) != 0; }; + + [[nodiscard]] bool canEncrypt() const { return (this->mask & encrypt_flag) != 0; }; + [[nodiscard]] bool canDecrypt() const { return (this->mask & decrypt_flag) != 0; }; + [[nodiscard]] bool canSign() const { return (this->mask & sign_flag) != 0; }; + [[nodiscard]] bool canVerify() const { return (this->mask & verify_flag) != 0; }; + [[nodiscard]] bool canDeriveKey() const { return (this->mask & derive_key_flag) != 0; }; + [[nodiscard]] bool canDeriveBits() const { return (this->mask & derive_bits_flag) != 0; }; + [[nodiscard]] bool canWrapKey() const { return (this->mask & wrap_key_flag) != 0; }; + [[nodiscard]] bool canUnwrapKey() const { return (this->mask & unwrap_key_flag) != 0; }; + + [[nodiscard]] bool canOnlyEncrypt() const { return this->mask == encrypt_flag; }; + [[nodiscard]] bool canOnlyDecrypt() const { return this->mask == decrypt_flag; }; + [[nodiscard]] bool canOnlySign() const { return this->mask == sign_flag; }; + [[nodiscard]] bool canOnlyVerify() const { return this->mask == verify_flag; }; + [[nodiscard]] bool canOnlySignOrVerify() const { return (this->mask & (sign_flag | verify_flag)) != 0; }; + [[nodiscard]] bool canOnlyDeriveKey() const { return this->mask == derive_key_flag; }; + [[nodiscard]] bool canOnlyDeriveBits() const { return this->mask == derive_bits_flag; }; + [[nodiscard]] bool canOnlyWrapKey() const { return this->mask == wrap_key_flag; }; + [[nodiscard]] bool canOnlyUnwrapKey() const { return this->mask == unwrap_key_flag; }; }; class CryptoKey : public BuiltinNoConstructor { @@ -87,7 +87,7 @@ class CryptoKey : public BuiltinNoConstructor { // indicates which cryptographic operations are permissible to be used with this key. static bool usages_get(JSContext *cx, unsigned argc, JS::Value *vp); - enum Slots { + enum Slots : uint8_t { // https://w3c.github.io/webcrypto/#ref-for-dfn-CryptoKey-slot-algorithm-1 // The contents of the [[algorithm]] internal slot shall be, or be derived from, a KeyAlgorithm. // We store a JS::ObjectValue within this slot which contains a JS Object representation of the @@ -139,7 +139,7 @@ class CryptoKey : public BuiltinNoConstructor { CryptoAlgorithmIdentifier algorithm); }; -} // namespace crypto -} // namespace web -} // namespace builtins +} // namespace builtins::web::crypto + + #endif diff --git a/builtins/web/crypto/crypto-raii.h b/builtins/web/crypto/crypto-raii.h index c1c08417..a1d6f63a 100644 --- a/builtins/web/crypto/crypto-raii.h +++ b/builtins/web/crypto/crypto-raii.h @@ -13,55 +13,55 @@ namespace builtins::web::crypto { namespace detail { struct BignumDeleter { void operator()(BIGNUM *bn) const { - if (bn) BN_free(bn); + if (bn) { BN_free(bn); } } }; struct EvpPkeyDeleter { void operator()(EVP_PKEY *pkey) const { - if (pkey) EVP_PKEY_free(pkey); + if (pkey) { EVP_PKEY_free(pkey); } } }; struct EvpPkeyCtxDeleter { void operator()(EVP_PKEY_CTX *ctx) const { - if (ctx) EVP_PKEY_CTX_free(ctx); + if (ctx) { EVP_PKEY_CTX_free(ctx); } } }; struct ParamBldDeleter { void operator()(OSSL_PARAM_BLD *bld) const { - if (bld) OSSL_PARAM_BLD_free(bld); + if (bld) { OSSL_PARAM_BLD_free(bld); } } }; struct ParamDeleter { void operator()(OSSL_PARAM *params) const { - if (params) OSSL_PARAM_free(params); + if (params) { OSSL_PARAM_free(params); } } }; struct EvpMdCtxDeleter { void operator()(EVP_MD_CTX *ctx) const { - if (ctx) EVP_MD_CTX_free(ctx); + if (ctx) { EVP_MD_CTX_free(ctx); } } }; struct EcdsaSigDeleter { void operator()(ECDSA_SIG *sig) const { - if (sig) ECDSA_SIG_free(sig); + if (sig) { ECDSA_SIG_free(sig); } } }; struct EcGroupDeleter { void operator()(EC_GROUP *group) const { - if (group) EC_GROUP_free(group); + if (group) { EC_GROUP_free(group); } } }; struct EcPointDeleter { void operator()(EC_POINT *point) const { - if (point) EC_POINT_free(point); + if (point) { EC_POINT_free(point); } } }; } diff --git a/builtins/web/crypto/crypto.cpp b/builtins/web/crypto/crypto.cpp index 7464e6cd..d1a660de 100644 --- a/builtins/web/crypto/crypto.cpp +++ b/builtins/web/crypto/crypto.cpp @@ -43,11 +43,11 @@ bool Crypto::get_random_values(JSContext *cx, unsigned argc, JS::Value *vp) { } JS::AutoCheckCannotGC noGC(cx); - bool is_shared; + bool is_shared = false; auto *buffer = static_cast(JS_GetArrayBufferViewData(typed_array, &is_shared, noGC)); auto res = host_api::Random::get_bytes(byte_length); - if (auto *err = res.to_err()) { + if (const auto *err = res.to_err()) { noGC.reset(); HANDLE_ERROR(cx, *err); return false; @@ -68,7 +68,7 @@ bool Crypto::random_uuid(JSContext *cx, unsigned argc, JS::Value *vp) { return false; } - auto uuid = maybe_uuid.value(); + const auto& uuid = maybe_uuid.value(); MOZ_ASSERT(uuid.size() == 36); JS::RootedString str(cx, JS_NewStringCopyN(cx, uuid.data(), uuid.size())); @@ -138,12 +138,15 @@ bool Crypto::init_class(JSContext *cx, JS::HandleObject global) { } bool install(api::Engine *engine) { - if (!SubtleCrypto::init_class(engine->cx(), engine->global())) + if (!SubtleCrypto::init_class(engine->cx(), engine->global())) { return false; - if (!Crypto::init_class(engine->cx(), engine->global())) + } + if (!Crypto::init_class(engine->cx(), engine->global())) { return false; - if (!CryptoKey::init_class(engine->cx(), engine->global())) + } + if (!CryptoKey::init_class(engine->cx(), engine->global())) { return false; + } return true; } diff --git a/builtins/web/crypto/crypto.h b/builtins/web/crypto/crypto.h index 254b0a8e..c5fb1868 100644 --- a/builtins/web/crypto/crypto.h +++ b/builtins/web/crypto/crypto.h @@ -3,9 +3,9 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace crypto { + + +namespace builtins::web::crypto { class Crypto : public BuiltinNoConstructor { private: @@ -15,7 +15,7 @@ class Crypto : public BuiltinNoConstructor { static JS::PersistentRooted subtle; - enum Slots { Count }; + enum Slots : uint8_t { Count }; static const JSFunctionSpec static_methods[]; static const JSPropertySpec static_properties[]; static const JSFunctionSpec methods[]; @@ -30,8 +30,8 @@ class Crypto : public BuiltinNoConstructor { bool install(api::Engine *engine); -} // namespace crypto -} // namespace web -} // namespace builtins +} // namespace builtins::web::crypto + + #endif diff --git a/builtins/web/crypto/json-web-key.cpp b/builtins/web/crypto/json-web-key.cpp index f663d59a..c889f9fa 100644 --- a/builtins/web/crypto/json-web-key.cpp +++ b/builtins/web/crypto/json-web-key.cpp @@ -1,7 +1,3 @@ -// TODO: remove these once the warnings are fixed -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" -#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" #include "js/ArrayBuffer.h" #include "js/Conversions.h" #include "js/experimental/TypedData.h" @@ -10,7 +6,6 @@ #include "js/Promise.h" #include "jsapi.h" #include "jsfriendapi.h" -#pragma clang diagnostic pop #include "../dom-exception.h" #include "builtin.h" @@ -19,22 +14,20 @@ #include -namespace builtins { -namespace web { -namespace crypto { +namespace builtins::web::crypto { namespace { JS::Result> -extractStringPropertyFromObject(JSContext *cx, JS::HandleObject object, std::string_view property) { - bool has_property; - if (!JS_HasProperty(cx, object, property.data(), &has_property)) { +extractStringPropertyFromObject(JSContext *cx, JS::HandleObject object, const char* property) { + bool has_property = false; + if (!JS_HasProperty(cx, object, property, &has_property)) { return JS::Result>(JS::Error()); } if (!has_property) { return std::optional(std::nullopt); } JS::RootedValue value(cx); - if (!JS_GetProperty(cx, object, property.data(), &value)) { + if (!JS_GetProperty(cx, object, property, &value)) { return JS::Result>(JS::Error()); } // Convert into a String following https://tc39.es/ecma262/#sec-tostring @@ -175,7 +168,7 @@ std::unique_ptr JsonWebKey::parse(JSContext *cx, JS::HandleValue val // boolean ext; std::optional ext = std::nullopt; { - bool has_ext; + bool has_ext = false; if (!JS_HasProperty(cx, object, "ext", &has_ext)) { return nullptr; } @@ -190,7 +183,7 @@ std::unique_ptr JsonWebKey::parse(JSContext *cx, JS::HandleValue val // sequence key_ops; std::vector key_ops; { - bool has_key_ops; + bool has_key_ops = false; if (!JS_HasProperty(cx, object, "key_ops", &has_key_ops)) { return nullptr; } @@ -199,7 +192,7 @@ std::unique_ptr JsonWebKey::parse(JSContext *cx, JS::HandleValue val if (!JS_GetProperty(cx, object, "key_ops", &key_ops_val)) { return nullptr; } - bool key_ops_is_array; + bool key_ops_is_array = false; if (!JS::IsArrayObject(cx, key_ops_val, &key_ops_is_array)) { return nullptr; } @@ -210,7 +203,7 @@ std::unique_ptr JsonWebKey::parse(JSContext *cx, JS::HandleValue val "DataError"); return nullptr; } - uint32_t length; + uint32_t length = 0; JS::RootedObject key_ops_array(cx, &key_ops_val.toObject()); if (!JS::GetArrayLength(cx, key_ops_array, &length)) { return nullptr; @@ -267,7 +260,7 @@ std::unique_ptr JsonWebKey::parse(JSContext *cx, JS::HandleValue val std::vector oth; { - bool has_oth; + bool has_oth = false; if (!JS_HasProperty(cx, object, "oth", &has_oth)) { return nullptr; } @@ -276,7 +269,7 @@ std::unique_ptr JsonWebKey::parse(JSContext *cx, JS::HandleValue val if (!JS_GetProperty(cx, object, "oth", &oth_val)) { return nullptr; } - bool oth_is_array; + bool oth_is_array = false; if (!JS::IsArrayObject(cx, oth_val, &oth_is_array)) { return nullptr; } @@ -287,7 +280,7 @@ std::unique_ptr JsonWebKey::parse(JSContext *cx, JS::HandleValue val "DataError"); return nullptr; } - uint32_t length; + uint32_t length = 0; JS::RootedObject oth_array(cx, &oth_val.toObject()); if (!JS::GetArrayLength(cx, oth_array, &length)) { return nullptr; @@ -364,6 +357,6 @@ std::unique_ptr JsonWebKey::parse(JSContext *cx, JS::HandleValue val return std::make_unique(kty, use, key_ops, alg, ext, crv, x, y, n, e, d, p, q, dp, dq, qi, oth, k); } -} // namespace crypto -} // namespace web -} // namespace builtins +} // namespace builtins::web::crypto + + diff --git a/builtins/web/crypto/json-web-key.h b/builtins/web/crypto/json-web-key.h index fad2ae67..cfa156a4 100644 --- a/builtins/web/crypto/json-web-key.h +++ b/builtins/web/crypto/json-web-key.h @@ -5,11 +5,12 @@ #include #include #include +#include #include -namespace builtins { -namespace web { -namespace crypto { + + +namespace builtins::web::crypto { // https://datatracker.ietf.org/doc/html/rfc7518#section-6.3.2.7 // 6.3.2.7. "oth" (Other Primes Info) Parameter @@ -35,7 +36,7 @@ class RsaOtherPrimesInfo { // member represents the CRT coefficient of the corresponding prime // factor. It is represented as a Base64urlUInt-encoded value. std::string t; - RsaOtherPrimesInfo(std::string r, std::string d, std::string t) : r{r}, d{d}, t{t} {} + RsaOtherPrimesInfo(std::string r, std::string d, std::string t) : r{std::move(r)}, d{std::move(d)}, t{std::move(t)} {} }; // https://datatracker.ietf.org/doc/html/rfc7517#section-4 @@ -149,38 +150,38 @@ class JsonWebKey { JsonWebKey(std::string kty, std::vector key_ops, std::optional ext, std::optional n, std::optional e) - : kty{kty}, key_ops{key_ops}, ext{ext}, n{n}, e{e} {} + : kty{std::move(kty)}, key_ops{std::move(key_ops)}, ext{ext}, n{std::move(n)}, e{std::move(e)} {} - JsonWebKey RSAPublicKey(std::string kty, std::vector key_ops, + static JsonWebKey RSAPublicKey(std::string kty, std::vector key_ops, std::optional ext, std::optional n, std::optional e) { - return JsonWebKey(kty, key_ops, ext, n, e); + return {std::move(kty), std::move(key_ops), ext, std::move(n), std::move(e)}; } JsonWebKey(std::string kty, std::vector key_ops, std::optional ext, std::optional n, std::optional e, std::optional d) - : kty{kty}, key_ops{key_ops}, ext{ext}, d{d}, n{n}, e{e} {} + : kty{std::move(kty)}, key_ops{std::move(key_ops)}, ext{ext}, d{std::move(d)}, n{std::move(n)}, e{std::move(e)} {} - JsonWebKey RSAPrivateKey(std::string kty, std::vector key_ops, + static JsonWebKey RSAPrivateKey(std::string kty, std::vector key_ops, std::optional ext, std::optional n, std::optional e, std::optional d) { - return JsonWebKey(kty, key_ops, ext, n, e, d); + return {std::move(kty), std::move(key_ops), ext, std::move(n), std::move(e), std::move(d)}; } JsonWebKey(std::string kty, std::vector key_ops, std::optional ext, std::optional n, std::optional e, std::optional d, std::optional p, std::optional q, std::optional dp, std::optional dq, std::optional qi) - : kty{kty}, key_ops{key_ops}, ext{ext}, d{d}, n{n}, e{e}, p{p}, q{q}, dp{dp}, dq{dq}, qi{qi} { + : kty{std::move(kty)}, key_ops{std::move(key_ops)}, ext{ext}, d{std::move(d)}, n{std::move(n)}, e{std::move(e)}, p{std::move(p)}, q{std::move(q)}, dp{std::move(dp)}, dq{std::move(dq)}, qi{std::move(qi)} { } - JsonWebKey RSAPrivateKeyWithAdditionalPrimes( + static JsonWebKey RSAPrivateKeyWithAdditionalPrimes( std::string kty, std::vector key_ops, std::optional ext, std::optional n, std::optional e, std::optional d, std::optional p, std::optional q, std::optional dp, std::optional dq, std::optional qi) { - return JsonWebKey(kty, key_ops, ext, n, e, d, p, q, dp, dq, qi); + return {std::move(kty), std::move(key_ops), ext, std::move(n), std::move(e), std::move(d), std::move(p), std::move(q), std::move(dp), std::move(dq), std::move(qi)}; } JsonWebKey(std::string kty, std::optional use, std::vector key_ops, @@ -192,13 +193,13 @@ class JsonWebKey { std::optional dp, std::optional dq, std::optional qi, std::vector oth, std::optional k) - : kty{kty}, use{use}, key_ops{key_ops}, alg{alg}, ext{ext}, crv{crv}, x{x}, y{y}, d{d}, n{n}, - e{e}, p{p}, q{q}, dp{dp}, dq{dq}, qi{qi}, oth{oth}, k{k} {} + : kty{std::move(kty)}, use{std::move(use)}, key_ops{std::move(key_ops)}, alg{std::move(alg)}, ext{ext}, crv{std::move(crv)}, x{std::move(x)}, y{std::move(y)}, d{std::move(d)}, n{std::move(n)}, + e{std::move(e)}, p{std::move(p)}, q{std::move(q)}, dp{std::move(dp)}, dq{std::move(dq)}, qi{std::move(qi)}, oth{std::move(oth)}, k{std::move(k)} {} static std::unique_ptr parse(JSContext *cx, JS::HandleValue value, std::string_view required_kty_value); }; -} // namespace crypto -} // namespace web -} // namespace builtins +} // namespace builtins::web::crypto + + #endif diff --git a/builtins/web/crypto/subtle-crypto.cpp b/builtins/web/crypto/subtle-crypto.cpp index b98955c0..5e2deb4c 100644 --- a/builtins/web/crypto/subtle-crypto.cpp +++ b/builtins/web/crypto/subtle-crypto.cpp @@ -52,7 +52,7 @@ bool SubtleCrypto::digest(JSContext *cx, unsigned argc, JS::Value *vp) { // the returned error and then terminate the algorithm. // 8. Let result be the result of performing the digest operation specified by normalizedAlgorithm // using algorithm, with data as message. - auto array_buffer = normalizedAlgorithm->digest(cx, data.value()); + auto *array_buffer = normalizedAlgorithm->digest(cx, data.value()); if (!array_buffer) { return RejectPromiseWithPendingError(cx, promise); } @@ -244,7 +244,7 @@ bool SubtleCrypto::sign(JSContext *cx, unsigned argc, JS::Value *vp) { // 10. Let result be the result of performing the sign operation specified by normalizedAlgorithm // using key and algorithm and with data as message. - auto signature = normalizedAlgorithm->sign(cx, key, data); + auto *signature = normalizedAlgorithm->sign(cx, key, data); if (!signature) { return RejectPromiseWithPendingError(cx, promise); } diff --git a/builtins/web/crypto/subtle-crypto.h b/builtins/web/crypto/subtle-crypto.h index 5f9354cd..8c8ca72c 100644 --- a/builtins/web/crypto/subtle-crypto.h +++ b/builtins/web/crypto/subtle-crypto.h @@ -4,9 +4,9 @@ #include "builtin.h" #include "crypto-algorithm.h" -namespace builtins { -namespace web { -namespace crypto { + + +namespace builtins::web::crypto { enum class Operations : uint8_t { Encrypt, @@ -28,7 +28,7 @@ class SubtleCrypto : public BuiltinNoConstructor { static constexpr const char *class_name = "SubtleCrypto"; static const int ctor_length = 0; - enum Slots { Count }; + enum Slots : uint8_t { Count }; static const JSFunctionSpec static_methods[]; static const JSPropertySpec static_properties[]; static const JSFunctionSpec methods[]; @@ -41,7 +41,7 @@ class SubtleCrypto : public BuiltinNoConstructor { static bool init_class(JSContext *cx, JS::HandleObject global); }; -} // namespace crypto -} // namespace web -} // namespace builtins +} // namespace builtins::web::crypto + + #endif diff --git a/builtins/web/crypto/uuid.cpp b/builtins/web/crypto/uuid.cpp index 771b0596..d54946ee 100644 --- a/builtins/web/crypto/uuid.cpp +++ b/builtins/web/crypto/uuid.cpp @@ -1,9 +1,9 @@ #include "uuid.h" #include "host_api.h" -namespace builtins { -namespace web { -namespace crypto { + + +namespace builtins::web::crypto { // FROM RFC 4122 // The formal definition of the UUID string representation is @@ -62,11 +62,11 @@ struct UUID { // specified in this document // that uses SHA-1 hashing. std::optional random_uuid_v4(JSContext *cx) { - UUID id; + UUID id{}; { auto res = host_api::Random::get_bytes(sizeof(id)); - if (auto *err = res.to_err()) { + if (const auto *err = res.to_err()) { HANDLE_ERROR(cx, *err); return std::nullopt; } @@ -94,5 +94,5 @@ std::optional random_uuid_v4(JSContext *cx) { } } // namespace uuid -} // namespace web -} // namespace builtins + + diff --git a/builtins/web/crypto/uuid.h b/builtins/web/crypto/uuid.h index fbef920d..a54bf2c6 100644 --- a/builtins/web/crypto/uuid.h +++ b/builtins/web/crypto/uuid.h @@ -3,9 +3,9 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace crypto { + + +namespace builtins::web::crypto { // FROM RFC 4122 // The version 4 UUID is meant for generating UUIDs from truly-random or @@ -22,8 +22,8 @@ namespace crypto { // Set all the other bits to randomly (or pseudo-randomly) chosen values. std::optional random_uuid_v4(JSContext *cx); -} // namespace crypto -} // namespace web -} // namespace builtins +} // namespace builtins::web::crypto + + #endif // BUILTINS_WEB_CRYPTO_UUID_H diff --git a/builtins/web/dom-exception.cpp b/builtins/web/dom-exception.cpp index 37ea9def..0ffff7b5 100644 --- a/builtins/web/dom-exception.cpp +++ b/builtins/web/dom-exception.cpp @@ -168,12 +168,12 @@ JSObject *DOMException::create(JSContext *cx, std::string_view message, std::str if (!instance) { return nullptr; } - auto message_str = JS_NewStringCopyN(cx, message.data(), message.size()); + auto *message_str = JS_NewStringCopyN(cx, message.data(), message.size()); if (!message_str) { return nullptr; } JS::SetReservedSlot(instance, Slots::Message, JS::StringValue(message_str)); - auto name_str = JS_NewStringCopyN(cx, name.data(), name.size()); + auto *name_str = JS_NewStringCopyN(cx, name.data(), name.size()); if (!name_str) { return nullptr; } @@ -199,7 +199,7 @@ bool DOMException::constructor(JSContext *cx, unsigned argc, JS::Value *vp) { return false; } if (args.hasDefined(0)) { - auto message = JS::ToString(cx, args.get(0)); + auto *message = JS::ToString(cx, args.get(0)); if (!message) { return false; } @@ -208,7 +208,7 @@ bool DOMException::constructor(JSContext *cx, unsigned argc, JS::Value *vp) { JS::SetReservedSlot(instance, Slots::Message, JS_GetEmptyStringValue(cx)); } if (args.hasDefined(1)) { - auto name = JS::ToString(cx, args.get(1)); + auto *name = JS::ToString(cx, args.get(1)); if (!name) { return false; } diff --git a/builtins/web/dom-exception.h b/builtins/web/dom-exception.h index 11569cb9..aac568cd 100644 --- a/builtins/web/dom-exception.h +++ b/builtins/web/dom-exception.h @@ -9,7 +9,7 @@ class DOMException : public BuiltinImpl { private: public: static constexpr const char *class_name = "DOMException"; - enum Slots { Name, Message, Code, Count }; + enum Slots : uint8_t { Name, Message, Code, Count }; static const JSFunctionSpec static_methods[]; static const JSPropertySpec static_properties[]; static const JSFunctionSpec methods[]; diff --git a/builtins/web/event/custom-event.cpp b/builtins/web/event/custom-event.cpp index 1e35480a..d970b14a 100644 --- a/builtins/web/event/custom-event.cpp +++ b/builtins/web/event/custom-event.cpp @@ -1,8 +1,8 @@ #include "custom-event.h" -namespace builtins { -namespace web { -namespace event { + + +namespace builtins::web::event { const JSFunctionSpec CustomEvent::static_methods[] = { JS_FS_END, @@ -68,6 +68,6 @@ bool CustomEvent::init_class(JSContext *cx, JS::HandleObject global) { return init_class_impl(cx, global, Event::proto_obj); } -} // namespace event -} // namespace web -} // namespace builtins +} // namespace builtins::web::event + + diff --git a/builtins/web/event/custom-event.h b/builtins/web/event/custom-event.h index 0df3c8e8..ee5df126 100644 --- a/builtins/web/event/custom-event.h +++ b/builtins/web/event/custom-event.h @@ -4,16 +4,16 @@ #include "builtin.h" #include "event.h" -namespace builtins { -namespace web { -namespace event { + + +namespace builtins::web::event { class CustomEvent : public BuiltinImpl { static bool detail_get(JSContext *cx, unsigned argc, JS::Value *vp); public: static constexpr int ParentSlots = Event::Slots::Count; - enum Slots { Detail = ParentSlots, Count }; + enum Slots : uint8_t { Detail = ParentSlots, Count }; static constexpr const char *class_name = "CustomEvent"; static constexpr unsigned ctor_length = 2; @@ -29,8 +29,8 @@ class CustomEvent : public BuiltinImpl { static bool constructor(JSContext *cx, unsigned argc, Value *vp); }; -} // namespace event -} // namespace web -} // namespace builtins +} // namespace builtins::web::event + + #endif // BUILTINS_WEB_CUSTOM_EVENT_H_ diff --git a/builtins/web/event/event-target.cpp b/builtins/web/event/event-target.cpp index 844d8b3d..34a40fde 100644 --- a/builtins/web/event/event-target.cpp +++ b/builtins/web/event/event-target.cpp @@ -127,9 +127,9 @@ template struct GCPolicy> { } // namespace JS -namespace builtins { -namespace web { -namespace event { + + +namespace builtins::web::event { using EventFlag = Event::EventFlag; using dom_exception::DOMException; @@ -184,7 +184,7 @@ const JSPropertySpec EventTarget::properties[] = { EventTarget::ListenerList *EventTarget::listeners(JSObject *self) { MOZ_ASSERT(is_instance(self)); - auto list = static_cast( + auto *list = static_cast( JS::GetReservedSlot(self, static_cast(EventTarget::Slots::Listeners)).toPrivate()); MOZ_ASSERT(list); @@ -226,7 +226,9 @@ bool EventTarget::add_listener(JSContext *cx, HandleObject self, HandleValue typ MOZ_ASSERT(is_instance(self)); // 1. Let capture, passive, once, and signal be the result of flattening more options. - bool capture = false, once = false, passive = false; + bool capture = false; + bool once = false; + bool passive = false; RootedValue passive_val(cx); RootedValue signal_val(cx); @@ -277,9 +279,9 @@ bool EventTarget::add_listener(JSContext *cx, HandleObject self, HandleValue typ } auto type = std::string_view(encoded); - auto list = listeners(self); + auto *list = listeners(self); - auto it = std::find_if(list->begin(), list->end(), [&](const auto &listener) { + auto *it = std::find_if(list->begin(), list->end(), [&](const auto &listener) { return type == listener->type && callback_val == listener->callback.get() && capture == listener->capture; }); @@ -335,9 +337,9 @@ bool EventTarget::remove_listener(JSContext *cx, HandleObject self, HandleValue } auto type = std::string_view(encoded); - auto list = listeners(self); + auto *list = listeners(self); - auto it = std::find_if(list->begin(), list->end(), [&](const auto &listener) { + auto *it = std::find_if(list->begin(), list->end(), [&](const auto &listener) { return type == listener->type && callback_val == listener->callback.get() && capture == listener->capture; }); @@ -374,11 +376,7 @@ bool EventTarget::dispatch_event(JSContext *cx, HandleObject self, HandleValue e Event::set_flag(event, EventFlag::Trusted, false); // 3. Return the result of dispatching event to this. - if (!dispatch(cx, self, event, nullptr, rval)) { - return false; - } - - return true; + return dispatch(cx, self, event, nullptr, rval); } // https://dom.spec.whatwg.org/#concept-event-dispatch @@ -454,7 +452,7 @@ bool EventTarget::invoke_listeners(JSContext *cx, HandleObject target, HandleObj // 5. Initialize event's currentTarget attribute to struct's invocation target. Event::set_current_target(event, target); // 6. Let listeners be a clone of event's currentTarget attribute value's event listener list. - auto list = listeners(target); + auto *list = listeners(target); JS::RootedVector list_clone(cx); if (!list_clone.reserve(list->length())) { return false; @@ -494,7 +492,7 @@ bool EventTarget::inner_invoke(JSContext *cx, HandleObject event, bool listeners_removed = false; // 2. For each listener of listeners, whose removed is false: - for (auto &listener : list) { + for (const auto &listener : list) { if (listener->removed) { continue; } @@ -536,7 +534,7 @@ bool EventTarget::inner_invoke(JSContext *cx, HandleObject event, // 11. Call a user object's operation with listener's callback, "handleEvent", event, // and event's currentTarget attribute value. - auto engine = api::Engine::get(cx); + auto *engine = api::Engine::get(cx); RootedValue callback_val(cx, listener->callback); RootedObject callback_obj(cx, &callback_val.toObject()); @@ -576,10 +574,10 @@ bool EventTarget::inner_invoke(JSContext *cx, HandleObject event, } if (listeners_removed) { - auto current_target = Event::current_target(event); + auto *current_target = Event::current_target(event); MOZ_ASSERT(is_instance(current_target)); - auto target_list = listeners(current_target); + auto *target_list = listeners(current_target); MOZ_ASSERT(target_list); target_list->eraseIf([](const auto &listener) { return listener->removed; }); } @@ -593,12 +591,14 @@ JSObject *EventTarget::create(JSContext *cx) { return nullptr; } - SetReservedSlot(self, Slots::Listeners, JS::PrivateValue(new ListenerList)); + auto list = js::MakeUnique(); + SetReservedSlot(self, Slots::Listeners, JS::PrivateValue(list.release())); return self; } bool EventTarget::init(JSContext *cx, HandleObject self) { - SetReservedSlot(self, Slots::Listeners, JS::PrivateValue(new ListenerList)); + auto list = js::MakeUnique(); + SetReservedSlot(self, Slots::Listeners, JS::PrivateValue(list.release())); return true; } @@ -610,7 +610,8 @@ bool EventTarget::constructor(JSContext *cx, unsigned argc, JS::Value *vp) { return false; } - SetReservedSlot(self, Slots::Listeners, JS::PrivateValue(new ListenerList)); + auto list = js::MakeUnique(); + SetReservedSlot(self, Slots::Listeners, JS::PrivateValue(list.release())); args.rval().setObject(*self); return true; @@ -618,9 +619,9 @@ bool EventTarget::constructor(JSContext *cx, unsigned argc, JS::Value *vp) { void EventTarget::finalize(JS::GCContext *gcx, JSObject *self) { MOZ_ASSERT(is_instance(self)); - auto list = listeners(self); + auto *list = listeners(self); if (list) { - delete list; + js_delete(list); } } @@ -633,7 +634,7 @@ void EventTarget::trace(JSTracer *trc, JSObject *self) { return; } - auto list = listeners(self); + auto *list = listeners(self); list->trace(trc); } @@ -641,6 +642,6 @@ bool EventTarget::init_class(JSContext *cx, JS::HandleObject global) { return init_class_impl(cx, global); } -} // namespace event -} // namespace web -} // namespace builtins +} // namespace builtins::web::event + + diff --git a/builtins/web/event/event-target.h b/builtins/web/event/event-target.h index 54d3a53b..e40b1ed4 100644 --- a/builtins/web/event/event-target.h +++ b/builtins/web/event/event-target.h @@ -7,9 +7,9 @@ #include "js/RefCounted.h" #include "mozilla/RefPtr.h" -namespace builtins { -namespace web { -namespace event { + + +namespace builtins::web::event { struct EventListener : public js::RefCounted { void trace(JSTracer *trc) { @@ -22,10 +22,10 @@ struct EventListener : public js::RefCounted { std::string type; - bool passive; - bool capture; - bool once; - bool removed; + bool passive{}; + bool capture{}; + bool once{}; + bool removed{}; // Define equality: only callback, type, and capture matter. bool operator==(const EventListener &other) const { @@ -51,8 +51,6 @@ class EventTarget : public BuiltinImpl { static bool invoke_listeners(JSContext *cx, HandleObject target, HandleObject event); - static bool on_abort(JSContext *cx, std::span args); - public: static constexpr const char *class_name = "EventTarget"; static constexpr unsigned ctor_length = 0; @@ -62,7 +60,7 @@ class EventTarget : public BuiltinImpl { static const JSFunctionSpec methods[]; static const JSPropertySpec properties[]; - enum Slots { Listeners, Count }; + enum Slots : uint8_t { Listeners, Count }; static bool add_listener(JSContext *cx, HandleObject self, HandleValue type, HandleValue callback, HandleValue opts); @@ -80,8 +78,8 @@ class EventTarget : public BuiltinImpl { static void trace(JSTracer *trc, JSObject *self); }; -} // namespace event -} // namespace web -} // namespace builtins +} // namespace builtins::web::event + + #endif // BUILTINS_WEB_EVENT_TARGET_H_ diff --git a/builtins/web/event/event.cpp b/builtins/web/event/event.cpp index 1fc01a47..6ad983ed 100644 --- a/builtins/web/event/event.cpp +++ b/builtins/web/event/event.cpp @@ -43,9 +43,9 @@ bool read_event_init(JSContext *cx, HandleValue initv, } // namespace -namespace builtins { -namespace web { -namespace event { + + +namespace builtins::web::event { const JSFunctionSpec Event::static_methods[] = { JS_FS_END, @@ -240,7 +240,7 @@ void Event::set_canceled(JSObject *self, bool val) { // https://dom.spec.whatwg.org/#inner-event-creation-steps bool Event::init(JSContext *cx, HandleObject self, HandleValue type, HandleValue init) { - auto type_str = JS::ToString(cx, type); + auto *type_str = JS::ToString(cx, type); if (!type_str) { return false; } @@ -256,7 +256,7 @@ bool Event::init(JSContext *cx, HandleObject self, HandleValue type, HandleValue // To initialize an event, with type, bubbles, and cancelable, run these steps: // - Set event's initialized flag. // - Unset event's stop propagation flag, stop immediate propagation flag, and canceled flag. - uint32_t flags = static_cast(EventFlag::Initialized); + auto flags = static_cast(EventFlag::Initialized); set_event_flag(&flags, EventFlag::Bubbles, bubbles); set_event_flag(&flags, EventFlag::Composed, composed); set_event_flag(&flags, EventFlag::Cancelable, cancelable); @@ -324,11 +324,7 @@ bool Event::initEvent(JSContext *cx, unsigned argc, JS::Value *vp) { RootedValue type(cx, args.get(0)); RootedValue init(cx, args.get(1)); - if (!Event::init(cx, self, type, init)) { - return false; - } - - return true; + return Event::init(cx, self, type, init); } bool Event::init_class(JSContext *cx, JS::HandleObject global) { @@ -352,6 +348,6 @@ bool install(api::Engine *engine) { return true; } -} // namespace event -} // namespace web -} // namespace builtins +} // namespace builtins::web::event + + diff --git a/builtins/web/event/event.h b/builtins/web/event/event.h index c6e65862..6e0d77c6 100644 --- a/builtins/web/event/event.h +++ b/builtins/web/event/event.h @@ -3,9 +3,9 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace event { + + +namespace builtins::web::event { class Event : public BuiltinImpl { static bool type_get(JSContext *cx, unsigned argc, JS::Value *vp); @@ -55,7 +55,7 @@ class Event : public BuiltinImpl { // - Bubbles // - Cancelable // clang-format off - enum class EventFlag : uint32_t { + enum class EventFlag : uint16_t { // Event type flags: StopPropagation = 1 << 0, StopImmediatePropagation = 1 << 1, @@ -94,7 +94,7 @@ class Event : public BuiltinImpl { static void set_related_target(JSObject *self, HandleObject target); static constexpr unsigned ctor_length = 1; - enum Slots { + enum Slots : uint8_t { Flags, Target, RelatedTarget, @@ -115,8 +115,8 @@ class Event : public BuiltinImpl { bool install(api::Engine *engine); -} // namespace event -} // namespace web -} // namespace builtins +} // namespace builtins::web::event + + #endif // BUILTINS_WEB_EVENT_H_ diff --git a/builtins/web/event/global-event-target.cpp b/builtins/web/event/global-event-target.cpp index f942d1f5..caf00c67 100644 --- a/builtins/web/event/global-event-target.cpp +++ b/builtins/web/event/global-event-target.cpp @@ -5,9 +5,9 @@ namespace { JS::PersistentRootedObject GLOBAL_EVENT_TARGET; } -namespace builtins { -namespace web { -namespace event { + + +namespace builtins::web::event { JSObject *global_event_target() { return GLOBAL_EVENT_TARGET; @@ -75,6 +75,6 @@ bool global_event_target_init(JSContext *cx, HandleObject global) { return true; } -} // namespace event -} // namespace web -} // namespace builtins +} // namespace builtins::web::event + + diff --git a/builtins/web/event/global-event-target.h b/builtins/web/event/global-event-target.h index cfdefb5e..02354651 100644 --- a/builtins/web/event/global-event-target.h +++ b/builtins/web/event/global-event-target.h @@ -3,16 +3,16 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace event { + + +namespace builtins::web::event { JSObject *global_event_target(); bool global_event_target_init(JSContext *cx, HandleObject global); -} // namespace event -} // namespace web -} // namespace builtins +} // namespace builtins::web::event + + #endif // BUILTINS_WEB_GLOBAL_EVENT_TARGET_H_ diff --git a/builtins/web/fetch/fetch-api.cpp b/builtins/web/fetch/fetch-api.cpp index b5c5f006..5f1104f5 100644 --- a/builtins/web/fetch/fetch-api.cpp +++ b/builtins/web/fetch/fetch-api.cpp @@ -24,7 +24,7 @@ using host_api::HostString; static api::Engine *ENGINE; -enum class FetchScheme { +enum class FetchScheme : uint8_t { About, Blob, Data, @@ -36,10 +36,10 @@ enum class FetchScheme { struct Terminator : AbortAlgorithm { mozilla::WeakPtr task; - Terminator(mozilla::WeakPtr task) : task(std::move(task)) {} + Terminator(const mozilla::WeakPtr& task) : task(task) {} bool run(JSContext *cx) override { - if (auto t = task.get()) { + if (auto *t = task.get()) { return t->abort(ENGINE); } return true; @@ -49,19 +49,24 @@ struct Terminator : AbortAlgorithm { std::optional scheme_from_url(const std::string_view &url) { if (url.starts_with("about:")) { return FetchScheme::About; - } else if (url.starts_with("blob:")) { + } + if (url.starts_with("blob:")) { return FetchScheme::Blob; - } else if (url.starts_with("data:")) { + } + if (url.starts_with("data:")) { return FetchScheme::Data; - } else if (url.starts_with("file:")) { + } + if (url.starts_with("file:")) { return FetchScheme::File; - } else if (url.starts_with("http")) { + } + if (url.starts_with("http")) { return FetchScheme::Http; - } else if (url.starts_with("https")) { + } + if (url.starts_with("https")) { return FetchScheme::Https; - } else { - return std::nullopt; } + + return std::nullopt; } // https://fetch.spec.whatwg.org/#concept-network-error @@ -92,7 +97,7 @@ bool fetch_https(JSContext *cx, HandleObject request_obj, HandleObject response_ return false; } - auto request = host_api::HttpOutgoingRequest::make(method, std::move(url), std::move(headers)); + auto *request = host_api::HttpOutgoingRequest::make(method, std::move(url), std::move(headers)); MOZ_RELEASE_ASSERT(request); JS_SetReservedSlot(request_obj, static_cast(Request::Slots::Request), PrivateValue(request)); @@ -106,10 +111,10 @@ bool fetch_https(JSContext *cx, HandleObject request_obj, HandleObject response_ request->body(); } - host_api::FutureHttpIncomingResponse *pending_handle; + host_api::FutureHttpIncomingResponse *pending_handle = nullptr; { auto res = request->send(); - if (auto *err = res.to_err()) { + if (const auto *err = res.to_err()) { HANDLE_ERROR(cx, *err); return false; } @@ -121,10 +126,9 @@ bool fetch_https(JSContext *cx, HandleObject request_obj, HandleObject response_ // before marking the request as pending. if (!streaming) { // TODO: what about non streaming? - auto task = mozilla::MakeRefPtr(request_obj, pending_handle); - auto weak = mozilla::WeakPtr(task); - - ENGINE->queue_async_task(task); + auto task = js::MakeUnique(request_obj, pending_handle); + auto weak = mozilla::WeakPtr(task.get()); + ENGINE->queue_async_task(task.release()); RootedObject signal(cx, Request::signal(request_obj)); MOZ_ASSERT(signal); @@ -283,7 +287,7 @@ bool fetch_blob(JSContext *cx, HandleObject request_obj, HandleObject response_p return false; } - auto type_str = JS::GetStringLength(type) ? chars.ptr.get() : ""; + const auto *type_str = (JS::GetStringLength(type) != 0U) ? chars.ptr.get() : ""; if (!Headers::set_valid_if_undefined(cx, resp_headers, "Content-Type", type_str)) { return false; } @@ -387,13 +391,15 @@ const JSFunctionSpec methods[] = {JS_FN("fetch", fetch, 2, JSPROP_ENUMERATE), JS bool install(api::Engine *engine) { ENGINE = engine; - if (!JS_DefineFunctions(engine->cx(), engine->global(), methods)) + if (!JS_DefineFunctions(engine->cx(), engine->global(), methods)) { return false; + } if (!request_response::install(engine)) { return false; } - if (!Headers::init_class(engine->cx(), engine->global())) + if (!Headers::init_class(engine->cx(), engine->global())) { return false; + } return true; } diff --git a/builtins/web/fetch/fetch-api.h b/builtins/web/fetch/fetch-api.h index 9d6807e6..fa2cf29e 100644 --- a/builtins/web/fetch/fetch-api.h +++ b/builtins/web/fetch/fetch-api.h @@ -3,14 +3,14 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace fetch { + + +namespace builtins::web::fetch { bool install(api::Engine *engine); -} // namespace fetch -} // namespace web -} // namespace builtins +} // namespace builtins::web::fetch + + #endif diff --git a/builtins/web/fetch/fetch-utils.cpp b/builtins/web/fetch/fetch-utils.cpp index 2d08a6ab..2a92f79c 100644 --- a/builtins/web/fetch/fetch-utils.cpp +++ b/builtins/web/fetch/fetch-utils.cpp @@ -74,7 +74,7 @@ std::optional parse_mime_type(std::string_view str) { auto value = trim(param.substr(pos + 1)); if (!key.empty()) { - mime.params.push_back({as_string(key), as_string(value)}); + mime.params.emplace_back(as_string(key), as_string(value)); } } } @@ -132,7 +132,7 @@ mozilla::Result extract_mime_type(std::string_view qu [&](const auto &kv) { return std::get<0>(kv) == "charset"; }); if (it == mime.params.end() && !charset.empty()) { - mime.params.push_back({"charset", charset}); + mime.params.emplace_back("charset", charset); } } } @@ -159,7 +159,7 @@ std::optional> extract_range(std::string_view range_q auto end_str = range_query.substr(dash_pos + 1); auto to_size = [](std::string_view s) -> std::optional { - size_t v; + size_t v = 0; auto [ptr, ec] = std::from_chars(&*s.begin(), &*s.end(), v); return ec == std::errc() ? std::optional(v) : std::nullopt; }; diff --git a/builtins/web/fetch/fetch_event.cpp b/builtins/web/fetch/fetch_event.cpp index dbd1a074..7cfd1929 100644 --- a/builtins/web/fetch/fetch_event.cpp +++ b/builtins/web/fetch/fetch_event.cpp @@ -97,10 +97,14 @@ bool add_pending_promise(JSContext *cx, JS::HandleObject self, JS::HandleObject } else { reject_handler = resolve_handler; } - if (!reject_handler) + + if (!reject_handler) { return false; - if (!JS::AddPromiseReactions(cx, promise, resolve_handler, reject_handler)) + } + + if (!JS::AddPromiseReactions(cx, promise, resolve_handler, reject_handler)) { return false; + } inc_pending_promise_count(self); return true; @@ -110,8 +114,10 @@ bool add_pending_promise(JSContext *cx, JS::HandleObject self, JS::HandleObject JSObject *FetchEvent::prepare_downstream_request(JSContext *cx) { JS::RootedObject request(cx, Request::create(cx)); - if (!request) + if (!request) { return nullptr; + } + Request::init_slots(request); return request; } @@ -166,16 +172,12 @@ bool FetchEvent::init_incoming_request(JSContext *cx, JS::HandleObject self, return false; } - auto uri_bytes = new uint8_t[uri_str.size() + 1]; + auto *uri_bytes = new uint8_t[uri_str.size() + 1]; std::copy(uri_str.begin(), uri_str.end(), uri_bytes); jsurl::SpecString spec(uri_bytes, uri_str.size(), uri_str.size()); worker_location::WorkerLocation::url = url::URL::create(cx, url_instance, spec); - if (!worker_location::WorkerLocation::url) { - return false; - } - - return true; + return worker_location::WorkerLocation::url != nullptr; } bool FetchEvent::request_get(JSContext *cx, unsigned argc, JS::Value *vp) { @@ -194,7 +196,7 @@ bool send_response(host_api::HttpOutgoingResponse *response, JS::HandleObject se auto result = response->send(); FetchEvent::set_state(self, new_state); - if (auto *err = result.to_err()) { + if (const auto *err = result.to_err()) { HANDLE_ERROR(ENGINE->cx(), *err); return false; } @@ -212,7 +214,7 @@ bool start_response(JSContext *cx, JS::HandleObject response_obj) { host_api::HttpOutgoingResponse* response = host_api::HttpOutgoingResponse::make(status, std::move(headers)); - auto existing_handle = Response::maybe_response_handle(response_obj); + auto *existing_handle = Response::maybe_response_handle(response_obj); if (existing_handle) { MOZ_ASSERT(existing_handle->is_incoming()); } else { @@ -248,8 +250,9 @@ bool response_promise_then_handler(JSContext *cx, JS::HandleObject event, JS::Ha if (!Response::is_instance(args.get(0))) { api::throw_error(cx, FetchErrors::InvalidRespondWithArg); JS::RootedObject rejection(cx, PromiseRejectedWithPendingError(cx)); - if (!rejection) + if (!rejection) { return false; + } args.rval().setObject(*rejection); return FetchEvent::respondWithError(cx, event); } @@ -283,8 +286,9 @@ bool FetchEvent::respondWith(JSContext *cx, unsigned argc, JS::Value *vp) { // Coercion of argument `r` to a Promise JS::RootedObject response_promise(cx, JS::CallOriginalPromiseResolve(cx, args.get(0))); - if (!response_promise) + if (!response_promise) { return false; + } // Step 2 if (!Event::has_flag(self, EventFlag::Dispatch)) { @@ -309,17 +313,20 @@ bool FetchEvent::respondWith(JSContext *cx, unsigned argc, JS::Value *vp) { JS::RootedObject catch_handler(cx); JS::RootedValue extra(cx, JS::ObjectValue(*response_promise)); catch_handler = create_internal_method(cx, self, extra); - if (!catch_handler) + if (!catch_handler) { return false; + } // Step 10 (continued in `response_promise_then_handler` above) JS::RootedObject then_handler(cx); then_handler = create_internal_method(cx, self); - if (!then_handler) + if (!then_handler) { return false; + } - if (!JS::AddPromiseReactions(cx, response_promise, then_handler, catch_handler)) + if (!JS::AddPromiseReactions(cx, response_promise, then_handler, catch_handler)) { return false; + } args.rval().setUndefined(); return true; @@ -331,7 +338,7 @@ bool FetchEvent::respondWith(JSContext *cx, unsigned argc, JS::Value *vp) { auto headers = std::make_unique(); if (body_text) { auto header_set_res = headers->set("content-type", "text/plain"); - if (auto *err = header_set_res.to_err()) { + if (const auto *err = header_set_res.to_err()) { HANDLE_ERROR(cx, *err); return false; } @@ -340,13 +347,13 @@ bool FetchEvent::respondWith(JSContext *cx, unsigned argc, JS::Value *vp) { auto *response = host_api::HttpOutgoingResponse::make(500, std::move(headers)); auto body_res = response->body(); - if (auto *err = body_res.to_err()) { + if (const auto *err = body_res.to_err()) { HANDLE_ERROR(cx, *err); return false; } if (body_text) { - auto body = std::move(body_res.unwrap()); + auto *body = body_res.unwrap(); body->write(reinterpret_cast(body_text->data()), body_text->length()); } @@ -359,8 +366,9 @@ bool FetchEvent::waitUntil(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER(1) JS::RootedObject promise(cx, JS::CallOriginalPromiseResolve(cx, args.get(0))); - if (!promise) + if (!promise) { return false; + } // Step 2 if (!is_active(self)) { diff --git a/builtins/web/fetch/fetch_event.h b/builtins/web/fetch/fetch_event.h index 951c0a7b..87da40e6 100644 --- a/builtins/web/fetch/fetch_event.h +++ b/builtins/web/fetch/fetch_event.h @@ -19,7 +19,7 @@ class FetchEvent final : public BuiltinNoConstructor { public: static constexpr const char *class_name = "FetchEvent"; - enum class State { + enum class State : uint8_t { unhandled, waitToRespond, responseStreaming, @@ -29,7 +29,7 @@ class FetchEvent final : public BuiltinNoConstructor { static constexpr int ParentSlots = event::Event::Slots::Count; - enum Slots { + enum Slots : uint8_t { Request = ParentSlots, CurrentState, PendingPromiseCount, diff --git a/builtins/web/fetch/headers.cpp b/builtins/web/fetch/headers.cpp index 394edfe4..ac5e14cb 100644 --- a/builtins/web/fetch/headers.cpp +++ b/builtins/web/fetch/headers.cpp @@ -11,7 +11,7 @@ namespace builtins::web::fetch { namespace { -const char VALID_NAME_CHARS[128] = { +const std::array VALID_NAME_CHARS = { 0, 0, 0, 0, 0, 0, 0, 0, // 0 0, 0, 0, 0, 0, 0, 0, 0, // 8 0, 0, 0, 0, 0, 0, 0, 0, // 16 @@ -37,7 +37,7 @@ host_api::HostString set_cookie_str; host_api::HttpHeadersReadOnly *get_handle(JSObject *self) { MOZ_ASSERT(Headers::is_instance(self)); - auto handle = + auto *handle = JS::GetReservedSlot(self, static_cast(Headers::Slots::Handle)).toPrivate(); return static_cast(handle); } @@ -115,10 +115,10 @@ host_api::HostString normalize_and_validate_header_value(JSContext *cx, HandleVa return value; } -static const std::vector *forbidden_request_headers; -static const std::vector *forbidden_response_headers; +const std::vector *forbidden_request_headers; +const std::vector *forbidden_response_headers; -enum class Ordering { Less, Equal, Greater }; +enum class Ordering : uint8_t { Less, Equal, Greater }; inline char header_lowercase(const char c) { return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c; } @@ -130,7 +130,8 @@ inline Ordering header_compare(const std::string_view a, const std::string_view char cb = header_lowercase(*it_b); if (ca < cb) { return Ordering::Less; - } else if (ca > cb) { + } + if (ca > cb) { return Ordering::Greater; } ++it_a; @@ -138,9 +139,8 @@ inline Ordering header_compare(const std::string_view a, const std::string_view } if (it_a == a.end()) { return it_b == b.end() ? Ordering::Equal : Ordering::Less; - } else { - return Ordering::Greater; } + return Ordering::Greater; } struct HeaderCompare { @@ -156,8 +156,8 @@ class HeadersSortListCompare { HeadersSortListCompare(const Headers::HeadersList *headers) : headers_(headers) {} bool operator()(size_t a, size_t b) { - auto header_a = &std::get<0>(headers_->at(a)); - auto header_b = &std::get<0>(headers_->at(b)); + const auto *header_a = &std::get<0>(headers_->at(a)); + const auto *header_b = &std::get<0>(headers_->at(b)); return header_compare(*header_a, *header_b) == Ordering::Less; } }; @@ -169,7 +169,7 @@ class HeadersSortListLookupCompare { HeadersSortListLookupCompare(const Headers::HeadersList *headers) : headers_(headers) {} bool operator()(size_t a, string_view b) { - auto header_a = &std::get<0>(headers_->at(a)); + const auto *header_a = &std::get<0>(headers_->at(a)); return header_compare(*header_a, b) == Ordering::Less; } }; @@ -179,10 +179,10 @@ JS::PersistentRooted comma; bool retrieve_value_for_header_from_handle(JSContext *cx, JS::HandleObject self, const host_api::HostString &name, MutableHandleValue value) { - auto handle = get_handle(self); + auto *handle = get_handle(self); auto ret = handle->get(name); - if (auto *err = ret.to_err()) { + if (const auto *err = ret.to_err()) { HANDLE_ERROR(cx, *err); return false; } @@ -223,10 +223,10 @@ bool retrieve_value_for_header_from_handle(JSContext *cx, JS::HandleObject self, bool retrieve_values_for_header_from_handle(JSContext *cx, JS::HandleObject self, const host_api::HostString &name, JS::MutableHandleObject out_arr) { - auto handle = get_handle(self); + auto *handle = get_handle(self); auto ret = handle->get(name); - if (auto *err = ret.to_err()) { + if (const auto *err = ret.to_err()) { HANDLE_ERROR(cx, *err); return false; } @@ -240,10 +240,12 @@ bool retrieve_values_for_header_from_handle(JSContext *cx, JS::HandleObject self size_t i = 0; for (auto &str : values.value()) { val_str = core::decode_byte_string(cx, str); - if (!val_str) + if (!val_str) { return false; - if (!JS_SetElement(cx, out_arr, i, val_str)) + } + if (!JS_SetElement(cx, out_arr, i, val_str)) { return false; + } i++; } @@ -255,7 +257,7 @@ bool retrieve_value_for_header_from_list(JSContext *cx, JS::HandleObject self, s JS::MutableHandleValue value, bool is_iterator) { MOZ_ASSERT(Headers::is_instance(self)); Headers::HeadersList *headers_list = Headers::headers_list(self); - const auto entry = Headers::get_index(cx, self, *index); + auto *const entry = Headers::get_index(cx, self, *index); const host_api::HostString *key = &std::get<0>(*entry); const host_api::HostString *val = &std::get<1>(*entry); // check if we need to join with the next value if it is the same key, comma-separated @@ -270,7 +272,7 @@ bool retrieve_value_for_header_from_list(JSContext *cx, JS::HandleObject self, s } size_t len = headers_list->size(); while (*index + 1 < len) { - const auto entry = Headers::get_index(cx, self, *index + 1); + auto *const entry = Headers::get_index(cx, self, *index + 1); const host_api::HostString *next_key = &std::get<0>(*entry); if (header_compare(*next_key, *key) != Ordering::Equal) { break; @@ -308,8 +310,9 @@ bool retrieve_values_for_header_from_list(JSContext *cx, JS::HandleObject self, } size_t i = 0; size_t len = headers_list->size(); - if (!JS_SetElement(cx, out_arr, i, str)) + if (!JS_SetElement(cx, out_arr, i, str)) { return false; + } while (++i < len - index) { const host_api::HostString *next_key = &std::get<0>(*Headers::get_index(cx, self, index + i)); val = &std::get<1>(*Headers::get_index(cx, self, index + i)); @@ -320,8 +323,9 @@ bool retrieve_values_for_header_from_list(JSContext *cx, JS::HandleObject self, if (!str) { return false; } - if (!JS_SetElement(cx, out_arr, i, str)) + if (!JS_SetElement(cx, out_arr, i, str)) { return false; + } } return true; } @@ -349,6 +353,8 @@ void skip_values_for_header_from_list(JSContext *cx, JS::HandleObject self, size bool validate_guard(JSContext *cx, HandleObject self, string_view header_name, const char *fun_name, bool *is_valid) { MOZ_ASSERT(Headers::is_instance(self)); + *is_valid = false; + Headers::HeadersGuard guard = Headers::guard(self); switch (guard) { case Headers::HeadersGuard::None: @@ -357,7 +363,7 @@ bool validate_guard(JSContext *cx, HandleObject self, string_view header_name, c case Headers::HeadersGuard::Immutable: return api::throw_error(cx, FetchErrors::HeadersImmutable, fun_name); case Headers::HeadersGuard::Request: - for (auto forbidden_header_name : *forbidden_request_headers) { + for (const auto *forbidden_header_name : *forbidden_request_headers) { if (header_compare(header_name, forbidden_header_name) == Ordering::Equal) { *is_valid = false; return true; @@ -366,7 +372,7 @@ bool validate_guard(JSContext *cx, HandleObject self, string_view header_name, c *is_valid = true; return true; case Headers::HeadersGuard::Response: - for (auto forbidden_header_name : *forbidden_response_headers) { + for (const auto *forbidden_header_name : *forbidden_response_headers) { if (header_compare(header_name, forbidden_header_name) == Ordering::Equal) { *is_valid = false; return true; @@ -385,7 +391,7 @@ void ensure_updated_sort_list(const Headers::HeadersList *headers_list, MOZ_ASSERT(headers_list); MOZ_ASSERT(headers_sort_list); // Empty length means we need to recompute. - if (headers_sort_list->size() == 0) { + if (headers_sort_list->empty()) { headers_sort_list->resize(headers_list->size()); std::iota(headers_sort_list->begin(), headers_sort_list->end(), 0); std::sort(headers_sort_list->begin(), headers_sort_list->end(), @@ -406,10 +412,10 @@ bool append_valid_normalized_header(JSContext *cx, HandleObject self, string_vie string_view header_val) { Headers::Mode mode = Headers::mode(self); if (mode == Headers::Mode::HostOnly) { - auto handle = get_handle(self)->as_writable(); + auto *handle = get_handle(self)->as_writable(); MOZ_ASSERT(handle); auto res = handle->append(header_name, header_val); - if (auto *err = res.to_err()) { + if (const auto *err = res.to_err()) { HANDLE_ERROR(cx, *err); return false; } @@ -426,7 +432,7 @@ bool append_valid_normalized_header(JSContext *cx, HandleObject self, string_vie return true; } -static bool switch_mode(JSContext *cx, HandleObject self, const Headers::Mode mode) { +bool switch_mode(JSContext *cx, HandleObject self, const Headers::Mode mode) { auto current_mode = Headers::mode(self); if (mode == current_mode) { return true; @@ -434,60 +440,58 @@ static bool switch_mode(JSContext *cx, HandleObject self, const Headers::Mode mo if (current_mode == Headers::Mode::Uninitialized) { MOZ_ASSERT(mode == Headers::Mode::ContentOnly); - RootedObject map(cx, JS::NewMapObject(cx)); - if (!map) { - return false; - } - MOZ_ASSERT(static_cast( - JS::GetReservedSlot(self, static_cast(Headers::Slots::HeadersList)) - .toPrivate()) == nullptr); + MOZ_ASSERT(JS::GetReservedSlot(self, static_cast(Headers::Slots::HeadersList)) + .toPrivate() == nullptr); + MOZ_ASSERT(JS::GetReservedSlot(self, static_cast(Headers::Slots::HeadersSortList)) + .toPrivate() == nullptr); + SetReservedSlot(self, static_cast(Headers::Slots::HeadersList), - PrivateValue(new Headers::HeadersList())); - MOZ_ASSERT(static_cast *>( - JS::GetReservedSlot(self, static_cast(Headers::Slots::HeadersSortList)) - .toPrivate()) == nullptr); + PrivateValue(js_new())); SetReservedSlot(self, static_cast(Headers::Slots::HeadersSortList), - PrivateValue(new std::vector())); + PrivateValue(js_new>())); SetReservedSlot(self, static_cast(Headers::Slots::Mode), JS::Int32Value(static_cast(Headers::Mode::ContentOnly))); + return true; } if (current_mode == Headers::Mode::ContentOnly) { MOZ_ASSERT(mode == Headers::Mode::CachedInContent, "Switching from ContentOnly to HostOnly is wasteful and not implemented"); + Headers::HeadersList *list = Headers::headers_list(self); auto handle = host_api::HttpHeaders::FromEntries(*list); if (handle.is_err()) { return api::throw_error(cx, FetchErrors::HeadersCloningFailed); } - SetReservedSlot(self, static_cast(Headers::Slots::Handle), - PrivateValue(handle.unwrap())); + SetReservedSlot(self, static_cast(Headers::Slots::Handle), PrivateValue(handle.unwrap())); } if (current_mode == Headers::Mode::HostOnly) { MOZ_ASSERT(mode == Headers::Mode::CachedInContent); - MOZ_ASSERT(static_cast( - JS::GetReservedSlot(self, static_cast(Headers::Slots::HeadersList)) - .toPrivate()) == nullptr); - Headers::HeadersList *list = new Headers::HeadersList(); - SetReservedSlot(self, static_cast(Headers::Slots::HeadersList), PrivateValue(list)); - MOZ_ASSERT(static_cast *>( - JS::GetReservedSlot(self, static_cast(Headers::Slots::HeadersSortList)) - .toPrivate()) == nullptr); + MOZ_ASSERT(JS::GetReservedSlot(self, static_cast(Headers::Slots::HeadersList)) + .toPrivate() == nullptr); + MOZ_ASSERT(JS::GetReservedSlot(self, static_cast(Headers::Slots::HeadersSortList)) + .toPrivate() == nullptr); + + SetReservedSlot(self, static_cast(Headers::Slots::HeadersList), + PrivateValue(js_new())); SetReservedSlot(self, static_cast(Headers::Slots::HeadersSortList), - PrivateValue(new std::vector())); + PrivateValue(js_new>())); SetReservedSlot(self, static_cast(Headers::Slots::Mode), JS::Int32Value(static_cast(Headers::Mode::ContentOnly))); - auto handle = get_handle(self); + + auto *handle = get_handle(self); MOZ_ASSERT(handle); + auto res = handle->entries(); if (res.is_err()) { HANDLE_ERROR(cx, *res.to_err()); return false; } + Headers::HeadersList *list = Headers::headers_list(self); for (auto &entry : std::move(res.unwrap())) { list->emplace_back(std::move(std::get<0>(entry)), std::move(std::get<1>(entry))); } @@ -495,7 +499,7 @@ static bool switch_mode(JSContext *cx, HandleObject self, const Headers::Mode mo if (mode == Headers::Mode::ContentOnly) { MOZ_ASSERT(current_mode == Headers::Mode::CachedInContent); - auto handle = get_handle(self); + auto *handle = get_handle(self); delete handle; SetReservedSlot(self, static_cast(Headers::Slots::Handle), PrivateValue(nullptr)); } @@ -508,9 +512,9 @@ static bool switch_mode(JSContext *cx, HandleObject self, const Headers::Mode mo bool prepare_for_entries_modification(JSContext *cx, JS::HandleObject self) { auto mode = Headers::mode(self); if (mode == Headers::Mode::HostOnly) { - auto handle = get_handle(self); + auto *handle = get_handle(self); if (!handle->is_writable()) { - auto new_handle = handle->clone(); + auto *new_handle = handle->clone(); if (!new_handle) { return api::throw_error(cx, FetchErrors::HeadersCloningFailed); } @@ -533,14 +537,14 @@ bool prepare_for_entries_modification(JSContext *cx, JS::HandleObject self) { } // namespace Headers::HeadersList *Headers::headers_list(JSObject *self) { - Headers::HeadersList *list = static_cast( + auto *list = static_cast( JS::GetReservedSlot(self, static_cast(Headers::Slots::HeadersList)).toPrivate()); MOZ_ASSERT(list); return list; } Headers::HeadersSortList *Headers::headers_sort_list(JSObject *self) { - Headers::HeadersSortList *list = static_cast( + auto *list = static_cast( JS::GetReservedSlot(self, static_cast(Headers::Slots::HeadersSortList)).toPrivate()); MOZ_ASSERT(list); return list; @@ -588,7 +592,7 @@ host_api::HostString Headers::validate_header_name(JSContext *cx, HandleValue na char *name_chars = name.begin(); for (size_t i = 0; i < name.len; i++) { const unsigned char ch = name_chars[i]; - if (ch > 127 || !VALID_NAME_CHARS[ch]) { + if (ch > 127 || (VALID_NAME_CHARS.at(ch) == 0)) { api::throw_error(cx, FetchErrors::InvalidHeaderName, fun_name, name_chars); return host_api::HostString{}; } @@ -701,16 +705,19 @@ bool Headers::getSetCookie(JSContext *cx, unsigned argc, JS::Value *vp) { args.rval().setObject(*out_arr); Mode mode = Headers::mode(self); - if (mode == Headers::Mode::Uninitialized) + if (mode == Headers::Mode::Uninitialized) { return true; +} if (mode == Mode::HostOnly) { - if (!retrieve_values_for_header_from_handle(cx, self, set_cookie_str, &out_arr)) + if (!retrieve_values_for_header_from_handle(cx, self, set_cookie_str, &out_arr)) { return false; +} } else { auto idx = Headers::lookup(cx, self, set_cookie_str); - if (idx && !retrieve_values_for_header_from_list(cx, self, idx.value(), &out_arr)) + if (idx && !retrieve_values_for_header_from_list(cx, self, idx.value(), &out_arr)) { return false; +} } return true; @@ -720,31 +727,35 @@ bool Headers::set(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER(2) auto name_chars = validate_header_name(cx, args[0], "Headers.set"); - if (!name_chars) + if (!name_chars) { return false; + } auto value_chars = normalize_and_validate_header_value(cx, args[1], "headers.set"); - if (!value_chars.ptr) + if (!value_chars.ptr) { return false; + } - bool is_valid; - if (!validate_guard(cx, self, name_chars, "Headers.append", &is_valid)) + bool is_valid = false; + if (!validate_guard(cx, self, name_chars, "Headers.append", &is_valid)) { return false; + } if (!is_valid) { args.rval().setUndefined(); return true; } - if (!prepare_for_entries_modification(cx, self)) + if (!prepare_for_entries_modification(cx, self)) { return false; + } Mode mode = Headers::mode(self); if (mode == Mode::HostOnly) { - auto handle = get_handle(self)->as_writable(); + auto *handle = get_handle(self)->as_writable(); MOZ_ASSERT(handle); auto res = handle->set(name_chars, value_chars); - if (auto *err = res.to_err()) { + if (const auto *err = res.to_err()) { HANDLE_ERROR(cx, *err); return false; } @@ -753,39 +764,53 @@ bool Headers::set(JSContext *cx, unsigned argc, JS::Value *vp) { auto idx = Headers::lookup(cx, self, name_chars); if (!idx) { - if (!append_valid_normalized_header(cx, self, std::move(name_chars), std::move(value_chars))) - return false; - } else { - size_t index = idx.value(); - // The lookup above will guarantee that sort_list is up to date. - std::vector *headers_sort_list = Headers::headers_sort_list(self); - HeadersList *headers_list = Headers::headers_list(self); - - // Update the first entry in place to the new value - host_api::HostString *header_val = - &std::get<1>(headers_list->at(headers_sort_list->at(index))); - - // Swap in the new value respecting the disposal semantics - header_val->ptr.swap(value_chars.ptr); - header_val->len = value_chars.len; - - // Delete all subsequent entries for this header excluding the first, - // as a variation of Headers::delete. - size_t len = headers_list->size(); - size_t delete_cnt = 0; - while (index + delete_cnt + 1 < len && - headers_sort_list->at(index + delete_cnt + 1) >= delete_cnt && - (header_compare(std::get<0>(headers_list->at( - headers_sort_list->at(index + delete_cnt + 1) - delete_cnt)), - name_chars) == Ordering::Equal)) { - headers_list->erase(headers_list->begin() + headers_sort_list->at(index + delete_cnt + 1) - - delete_cnt); - delete_cnt++; + args.rval().setUndefined(); + return append_valid_normalized_header(cx, self, std::move(name_chars), std::move(value_chars)); + } + + size_t index = idx.value(); + // The lookup above will guarantee that sort_list is up to date. + std::vector *headers_sort_list = Headers::headers_sort_list(self); + HeadersList *headers_list = Headers::headers_list(self); + + // Update the first entry in place to the new value + host_api::HostString *header_val = + &std::get<1>(headers_list->at(headers_sort_list->at(index))); + + // Swap in the new value respecting the disposal semantics + header_val->ptr.swap(value_chars.ptr); + header_val->len = value_chars.len; + + // Delete all subsequent entries for this header excluding the first, + // as a variation of Headers::delete. + size_t len = headers_list->size(); + size_t delete_cnt = 0; + + while (true) { + size_t next_index = index + delete_cnt + 1; + if (next_index >= len) { + break; } - // Reset the sort list if we performed additional deletions. - if (delete_cnt > 0) { - headers_sort_list->clear(); + + size_t sorted_pos = headers_sort_list->at(next_index); + if (sorted_pos < delete_cnt) { + break; } + + size_t actual_pos = sorted_pos - delete_cnt; + const auto& header_name = std::get<0>(headers_list->at(actual_pos)); + + if (header_compare(header_name, name_chars) != Ordering::Equal) { + break; + } + + headers_list->erase(headers_list->begin() + actual_pos); + delete_cnt++; + } + + // Reset the sort list if we performed additional deletions. + if (delete_cnt > 0) { + headers_sort_list->clear(); } } @@ -797,8 +822,9 @@ bool Headers::has(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER(1) auto name_chars = validate_header_name(cx, args[0], "Headers.has"); - if (!name_chars) + if (!name_chars) { return false; + } Mode mode = Headers::mode(self); if (mode == Mode::Uninitialized) { @@ -807,7 +833,7 @@ bool Headers::has(JSContext *cx, unsigned argc, JS::Value *vp) { } if (mode == Mode::HostOnly) { - auto handle = get_handle(self); + auto *handle = get_handle(self); MOZ_ASSERT(handle); auto res = handle->has(name_chars); MOZ_ASSERT(!res.is_err()); @@ -823,64 +849,67 @@ bool Headers::append(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER(2) auto name_chars = validate_header_name(cx, args[0], "Headers.append"); - if (!name_chars) + if (!name_chars) { return false; + } auto value_chars = normalize_and_validate_header_value(cx, args[1], "Headers.append"); - if (!value_chars) + if (!value_chars) { return false; + } - bool is_valid; + bool is_valid = false; if (!validate_guard(cx, self, name_chars, "Headers.append", &is_valid)) { return false; } - if (is_valid) { - // name casing must come from existing name match if there is one. - auto idx = Headers::lookup(cx, self, name_chars); + if (!is_valid) { + args.rval().setUndefined(); + return true; + } - if (!prepare_for_entries_modification(cx, self)) - return false; + // name casing must come from existing name match if there is one. + auto idx = Headers::lookup(cx, self, name_chars); - if (idx) { - // set-cookie doesn't combine - if (header_compare(name_chars, set_cookie_str) == Ordering::Equal) { - if (!append_valid_normalized_header(cx, self, - std::get<0>(*Headers::get_index(cx, self, idx.value())), - std::move(value_chars))) - return false; - } else { - // walk to the last name if multiple to do the combining into - size_t index = idx.value(); - skip_values_for_header_from_list(cx, self, &index, false); - host_api::HostString *header_val = &std::get<1>(*Headers::get_index(cx, self, index)); - size_t combined_len = header_val->len + value_chars.len + 2; - char *combined = static_cast(malloc(combined_len)); - memcpy(combined, header_val->ptr.get(), header_val->len); - memcpy(combined + header_val->len, ", ", 2); - memcpy(combined + header_val->len + 2, value_chars.ptr.get(), value_chars.len); - JS::UniqueChars combined_chars(combined); - header_val->ptr.swap(combined_chars); - header_val->len = combined_len; - } - } else { - if (!append_valid_normalized_header(cx, self, std::move(name_chars), std::move(value_chars))) - return false; - } - return true; + if (!prepare_for_entries_modification(cx, self)) { + return false; + } + + if (!idx) { + args.rval().setUndefined(); + return append_valid_normalized_header(cx, self, std::move(name_chars), std::move(value_chars)); } + // set-cookie doesn't combine + if (header_compare(name_chars, set_cookie_str) == Ordering::Equal) { + return append_valid_normalized_header(cx, self, std::get<0>(*Headers::get_index(cx, self, idx.value())), std::move(value_chars)); + } + + // walk to the last name if multiple to do the combining into + size_t index = idx.value(); + skip_values_for_header_from_list(cx, self, &index, false); + host_api::HostString *header_val = &std::get<1>(*Headers::get_index(cx, self, index)); + size_t combined_len = header_val->len + value_chars.len + 2; + auto combined = JS::UniqueChars(static_cast(js_malloc(combined_len))); + memcpy(combined.get(), header_val->ptr.get(), header_val->len); + memcpy(combined.get() + header_val->len, ", ", 2); + memcpy(combined.get() + header_val->len + 2, value_chars.ptr.get(), value_chars.len); + header_val->ptr.swap(combined); + header_val->len = combined_len; + args.rval().setUndefined(); return true; } + bool Headers::set_valid_if_undefined(JSContext *cx, HandleObject self, string_view name, string_view value) { - if (!prepare_for_entries_modification(cx, self)) + if (!prepare_for_entries_modification(cx, self)) { return false; +} if (mode(self) == Mode::HostOnly) { - auto handle = get_handle(self)->as_writable(); + auto *handle = get_handle(self)->as_writable(); auto has = handle->has(name); MOZ_ASSERT(!has.is_err()); if (has.unwrap()) { @@ -888,7 +917,7 @@ bool Headers::set_valid_if_undefined(JSContext *cx, HandleObject self, string_vi } auto res = handle->append(name, value); - if (auto *err = res.to_err()) { + if (const auto *err = res.to_err()) { HANDLE_ERROR(cx, *err); return false; } @@ -907,60 +936,83 @@ bool Headers::delete_(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER_WITH_NAME(1, "delete") auto name_chars = validate_header_name(cx, args[0], "Headers.delete"); - if (!name_chars) + if (!name_chars) { return false; + } - bool is_valid; - if (!validate_guard(cx, self, name_chars, "Headers.delete", &is_valid)) + bool is_valid = false; + if (!validate_guard(cx, self, name_chars, "Headers.delete", &is_valid)) { return false; + } if (!is_valid) { args.rval().setUndefined(); return true; } - if (!prepare_for_entries_modification(cx, self)) + if (!prepare_for_entries_modification(cx, self)) { return false; + } Mode mode = Headers::mode(self); if (mode == Mode::HostOnly) { - auto handle = get_handle(self)->as_writable(); + auto *handle = get_handle(self)->as_writable(); MOZ_ASSERT(handle); std::string_view name = name_chars; auto res = handle->remove(name); - if (auto *err = res.to_err()) { + if (const auto *err = res.to_err()) { HANDLE_ERROR(cx, *err); return false; } - } else { - MOZ_ASSERT(mode == Mode::ContentOnly); + args.rval().setUndefined(); + return true; + } - auto idx = Headers::lookup(cx, self, name_chars); - if (idx) { - size_t index = idx.value(); - // The lookup above will guarantee that sort_list is up to date. - std::vector *headers_sort_list = Headers::headers_sort_list(self); - HeadersList *headers_list = Headers::headers_list(self); - - // Delete all case-insensitively equal names. - // The ordering guarantee for sort_list is that equal names will come later in headers_list - // so that we can continue to use sort list during the delete operation, only recomputing it - // after. - size_t delete_cnt = 0; - size_t len = headers_sort_list->size(); - do { - headers_list->erase(headers_list->begin() + headers_sort_list->at(index + delete_cnt) - - delete_cnt); - delete_cnt++; - } while ( - index + delete_cnt < len && headers_sort_list->at(index + delete_cnt) >= delete_cnt && - header_compare( - std::get<0>(headers_list->at(headers_sort_list->at(index + delete_cnt) - delete_cnt)), - name_chars) == Ordering::Equal); - headers_sort_list->clear(); + MOZ_ASSERT(mode == Mode::ContentOnly); + + auto idx = Headers::lookup(cx, self, name_chars); + if (!idx) { + args.rval().setUndefined(); + return true; + } + + size_t index = idx.value(); + // The lookup above will guarantee that sort_list is up to date. + std::vector *headers_sort_list = Headers::headers_sort_list(self); + HeadersList *headers_list = Headers::headers_list(self); + + // Delete all case-insensitively equal names. + // The ordering guarantee for sort_list is that equal names will come later in headers_list + // so that we can continue to use sort list during the delete operation, only recomputing it + // after. + size_t delete_cnt = 0; + size_t len = headers_sort_list->size(); + + while (true) { + size_t current_index = index + delete_cnt; + + if (current_index >= len) { + break; + } + + size_t sorted_pos = headers_sort_list->at(current_index); + if (sorted_pos < delete_cnt) { + break; } + + size_t actual_pos = sorted_pos - delete_cnt; + const auto& header_name = std::get<0>(headers_list->at(actual_pos)); + + if (header_compare(header_name, name_chars) != Ordering::Equal) { + break; + } + + headers_list->erase(headers_list->begin() + actual_pos); + delete_cnt++; } + headers_sort_list->clear(); + args.rval().setUndefined(); return true; } @@ -968,32 +1020,33 @@ bool Headers::delete_(JSContext *cx, unsigned argc, JS::Value *vp) { bool Headers::append_valid_header(JSContext *cx, JS::HandleObject self, host_api::HostString valid_key, JS::HandleValue value, const char *fun_name) { - bool is_valid; + bool is_valid = false; if (!validate_guard(cx, self, valid_key, "Headers constructor", &is_valid)) { return false; } + if (!is_valid) { return true; } auto value_chars = normalize_and_validate_header_value(cx, value, fun_name); - if (!value_chars.ptr) + if (!value_chars.ptr) { return false; + } - if (!prepare_for_entries_modification(cx, self)) + if (!prepare_for_entries_modification(cx, self)) { return false; + } // name casing must come from existing name match if there is one. auto idx = Headers::lookup(cx, self, valid_key); + if (idx) { - if (!append_valid_normalized_header( - cx, self, std::get<0>(*Headers::get_index(cx, self, idx.value())), value_chars)) { - return false; - } - } else if (!append_valid_normalized_header(cx, self, valid_key, value_chars)) { - return false; + return append_valid_normalized_header( + cx, self, std::get<0>(*Headers::get_index(cx, self, idx.value())), value_chars); } - return true; + + return append_valid_normalized_header(cx, self, valid_key, value_chars); } const JSFunctionSpec Headers::static_methods[] = { @@ -1046,17 +1099,17 @@ bool Headers::constructor(JSContext *cx, unsigned argc, JS::Value *vp) { } void Headers::finalize(JS::GCContext *gcx, JSObject *self) { - HeadersList *list = static_cast( - JS::GetReservedSlot(self, static_cast(Headers::Slots::HeadersList)).toPrivate()); + auto *list = static_cast( + JS::GetReservedSlot(self, static_cast(Slots::HeadersList)).toPrivate()); if (list != nullptr) { list->clear(); - free(list); + js_delete(list); } - HeadersSortList *sort_list = static_cast( + auto *sort_list = static_cast( JS::GetReservedSlot(self, static_cast(Slots::HeadersSortList)).toPrivate()); if (sort_list != nullptr) { sort_list->clear(); - free(sort_list); + js_delete(sort_list); } } @@ -1079,7 +1132,7 @@ bool Headers::init_class(JSContext *cx, JS::HandleObject global) { set_cookie_str = host_api::HostString("set-cookie"); - auto comma_str = JS_NewStringCopyN(cx, ", ", 2); + auto *comma_str = JS_NewStringCopyN(cx, ", ", 2); if (!comma_str) { return false; } @@ -1090,8 +1143,9 @@ bool Headers::init_class(JSContext *cx, JS::HandleObject global) { } JS::RootedValue entries(cx); - if (!JS_GetProperty(cx, proto_obj, "entries", &entries)) + if (!JS_GetProperty(cx, proto_obj, "entries", &entries)) { return false; + } JS::SymbolCode code = JS::SymbolCode::iterator; JS::RootedId iteratorId(cx, JS::GetWellKnownSymbolKey(cx, code)); @@ -1165,11 +1219,13 @@ const JSPropertySpec HeadersIterator::properties[] = { bool HeadersIterator::init_class(JSContext *cx, JS::HandleObject global) { JS::RootedObject iterator_proto(cx, JS::GetRealmIteratorPrototype(cx)); - if (!iterator_proto) + if (!iterator_proto) { return false; + } - if (!init_class_impl(cx, global, iterator_proto)) + if (!init_class_impl(cx, global, iterator_proto)) { return false; + } // Delete both the `HeadersIterator` global property and the // `constructor` property on `HeadersIterator.prototype`. The latter @@ -1215,11 +1271,12 @@ bool HeadersIterator::next(JSContext *cx, unsigned argc, Value *vp) { size_t index = JS::GetReservedSlot(self, Slots::Cursor).toInt32(); size_t len = list->size(); - uint8_t type = static_cast(JS::GetReservedSlot(self, Slots::Type).toInt32()); + auto type = static_cast(JS::GetReservedSlot(self, Slots::Type).toInt32()); JS::RootedObject result(cx, JS_NewPlainObject(cx)); - if (!result) + if (!result) { return false; + } if (index >= len) { JS_DefineProperty(cx, result, "done", JS::TrueHandleValue, JSPROP_ENUMERATE); @@ -1237,11 +1294,11 @@ bool HeadersIterator::next(JSContext *cx, unsigned argc, Value *vp) { if (type != ITER_TYPE_VALUES) { const host_api::HostString *key = &std::get<0>(*Headers::get_index(cx, headers, index)); size_t len = key->len; - JS::Latin1Char *chars = reinterpret_cast(malloc(len)); + auto chars = JS::UniqueLatin1Chars(static_cast(js_malloc(len))); for (int i = 0; i < len; ++i) { const unsigned char ch = key->ptr[i]; // headers should already be validated by here - MOZ_ASSERT(ch <= 127 && VALID_NAME_CHARS[ch]); + MOZ_ASSERT(ch <= 127 && VALID_NAME_CHARS.at(ch)); // we store header keys with casing, so getter itself lowercases if (ch >= 'A' && ch <= 'Z') { chars[i] = ch - 'A' + 'a'; @@ -1249,7 +1306,7 @@ bool HeadersIterator::next(JSContext *cx, unsigned argc, Value *vp) { chars[i] = ch; } } - key_val = JS::StringValue(JS_NewLatin1String(cx, JS::UniqueLatin1Chars(chars), len)); + key_val = JS::StringValue(JS_NewLatin1String(cx, std::move(chars), len)); } if (type != ITER_TYPE_KEYS) { @@ -1265,8 +1322,9 @@ bool HeadersIterator::next(JSContext *cx, unsigned argc, Value *vp) { switch (type) { case ITER_TYPE_ENTRIES: { JS::RootedObject pair(cx, JS::NewArrayObject(cx, 2)); - if (!pair) + if (!pair) { return false; + } JS_DefineElement(cx, pair, 0, key_val, JSPROP_ENUMERATE); JS_DefineElement(cx, pair, 1, val_val, JSPROP_ENUMERATE); result_val = JS::ObjectValue(*pair); diff --git a/builtins/web/fetch/headers.h b/builtins/web/fetch/headers.h index 77992000..a64600aa 100644 --- a/builtins/web/fetch/headers.h +++ b/builtins/web/fetch/headers.h @@ -4,9 +4,9 @@ #include "builtin.h" #include "host_api.h" -namespace builtins { -namespace web { -namespace fetch { + + +namespace builtins::web::fetch { class Headers final : public BuiltinImpl { static bool append(JSContext *cx, unsigned argc, JS::Value *vp); @@ -53,7 +53,7 @@ class Headers final : public BuiltinImpl { /// /// If a header is added, deleted, or replaced on an instance in `CachedInContent` mode, the /// instance transitions to `ContentOnly` mode, and the underlying resource handle is discarded. - enum class Mode { + enum class Mode : uint8_t { HostOnly, // Headers are stored in the host. CachedInContent, // Host holds canonical headers, content a cached copy. ContentOnly, // Headers are stored in a Map held by the `Entries` slot. @@ -70,7 +70,7 @@ class Headers final : public BuiltinImpl { // example, it is cleared after an insertion. It is recomputed lazily for every lookup. using HeadersSortList = std::vector; - enum class Slots { + enum class Slots : uint8_t { Handle, HeadersList, HeadersSortList, @@ -80,7 +80,7 @@ class Headers final : public BuiltinImpl { Count, }; - enum class HeadersGuard { + enum class HeadersGuard : uint8_t { None, Request, Response, @@ -112,7 +112,7 @@ class Headers final : public BuiltinImpl { /// Get the header entry for a given index, ensuring that HeadersSortList is recomputed if /// necessary in the process. static std::tuple * - get_index(JSContext *cx, JS::HandleObject self, size_t idx); + get_index(JSContext *cx, JS::HandleObject self, size_t index); static const JSFunctionSpec static_methods[]; static const JSPropertySpec static_properties[]; @@ -128,9 +128,9 @@ class Headers final : public BuiltinImpl { static JSObject *create(JSContext *cx, HandleValue init_headers, HeadersGuard guard); static JSObject *create(JSContext *cx, host_api::HttpHeadersReadOnly *handle, HeadersGuard guard); - static void finalize(JS::GCContext *gcx, JSObject *obj); + static void finalize(JS::GCContext *gcx, JSObject *self); - static bool init_entries(JSContext *cx, HandleObject self, HandleValue init_headers); + static bool init_entries(JSContext *cx, HandleObject self, HandleValue initv); /// Returns the headers list of entries, constructing it if necessary. /// Depending on the `Mode` the instance is in, this can be a cache or the canonical store for @@ -151,7 +151,7 @@ class Headers final : public BuiltinImpl { * * The handle is guaranteed to be uniquely owned by the caller. */ - static unique_ptr handle_clone(JSContext *, HandleObject self); + static unique_ptr handle_clone(JSContext *cx, HandleObject self); }; class HeadersIterator final : public BuiltinNoConstructor { @@ -160,7 +160,7 @@ class HeadersIterator final : public BuiltinNoConstructor { public: static constexpr const char *class_name = "Headers Iterator"; - enum Slots { + enum Slots : uint8_t { Type, Cursor, Headers, @@ -177,8 +177,8 @@ class HeadersIterator final : public BuiltinNoConstructor { static JSObject *create(JSContext *cx, JS::HandleObject headers, uint8_t iter_type); }; -} // namespace fetch -} // namespace web -} // namespace builtins +} // namespace builtins::web::fetch + + #endif diff --git a/builtins/web/fetch/request-response.cpp b/builtins/web/fetch/request-response.cpp index 42d38b9a..d86a95d2 100644 --- a/builtins/web/fetch/request-response.cpp +++ b/builtins/web/fetch/request-response.cpp @@ -21,13 +21,10 @@ #include "js/Conversions.h" #include "js/JSON.h" #include "js/Stream.h" +#include "js/experimental/TypedData.h" #include "mozilla/ResultVariant.h" -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" #include "../worker-location.h" -#include "js/experimental/TypedData.h" -#pragma clang diagnostic pop namespace builtins::web::streams { @@ -53,8 +50,9 @@ static api::Engine *ENGINE; bool error_stream_controller_with_pending_exception(JSContext *cx, HandleObject stream) { RootedValue exn(cx); - if (!JS_GetPendingException(cx, &exn)) + if (!JS_GetPendingException(cx, &exn)) { return false; + } JS_ClearPendingException(cx); RootedValue args(cx); @@ -70,7 +68,7 @@ class BodyFutureTask final : public api::AsyncTask { public: explicit BodyFutureTask(const HandleObject body_source) : body_source_(body_source) { - auto owner = streams::NativeStreamSource::owner(body_source_); + auto *owner = streams::NativeStreamSource::owner(body_source_); incoming_body_ = RequestOrResponse::incoming_body_handle(owner); auto res = incoming_body_->subscribe(); MOZ_ASSERT(!res.is_err(), "Subscribing to a future should never fail"); @@ -82,11 +80,11 @@ class BodyFutureTask final : public api::AsyncTask { JSContext *cx = engine->cx(); RootedObject owner(cx, streams::NativeStreamSource::owner(body_source_)); RootedObject stream(cx, streams::NativeStreamSource::stream(body_source_)); - auto body = RequestOrResponse::incoming_body_handle(owner); + auto *body = RequestOrResponse::incoming_body_handle(owner); auto read_res = body->read(HANDLE_READ_CHUNK_SIZE); if (read_res.to_err()) { - auto receiver = Request::is_instance(owner) ? "request" : "response"; + const auto *receiver = Request::is_instance(owner) ? "request" : "response"; api::throw_error(cx, FetchErrors::IncomingBodyStreamError, receiver); return error_stream_controller_with_pending_exception(cx, stream); } @@ -139,7 +137,7 @@ namespace { bool normalize_http_method(char *method) { static const char *names[6] = {"DELETE", "GET", "HEAD", "OPTIONS", "POST", "PUT"}; - for (const auto name : names) { + for (const auto *const name : names) { if (strcasecmp(method, name) == 0) { if (strcmp(method, name) == 0) { return false; @@ -147,7 +145,7 @@ bool normalize_http_method(char *method) { // Note: Safe because `strcasecmp` returning 0 above guarantees // same-length strings. - strcpy(method, name); + strcpy(method, name); // NOLINT return true; } } @@ -169,7 +167,7 @@ host_api::HttpRequestResponseBase *RequestOrResponse::maybe_handle(JSObject *obj } host_api::HttpRequestResponseBase *RequestOrResponse::handle(JSObject *obj) { - auto handle = maybe_handle(obj); + auto *handle = maybe_handle(obj); MOZ_ASSERT(handle); return handle; } @@ -179,12 +177,12 @@ bool RequestOrResponse::is_instance(JSObject *obj) { } bool RequestOrResponse::is_incoming(JSObject *obj) { - auto handle = RequestOrResponse::maybe_handle(obj); - return handle && handle->is_incoming(); + auto *handle = RequestOrResponse::maybe_handle(obj); + return (handle != nullptr) && handle->is_incoming(); } host_api::HttpHeadersReadOnly *RequestOrResponse::maybe_headers_handle(JSObject *obj) { - auto handle = maybe_handle(obj); + auto *handle = maybe_handle(obj); if (!handle) { return nullptr; } @@ -200,22 +198,18 @@ bool RequestOrResponse::has_body(JSObject *obj) { host_api::HttpIncomingBody *RequestOrResponse::incoming_body_handle(JSObject *obj) { MOZ_ASSERT(is_incoming(obj)); - auto handle = RequestOrResponse::handle(obj); - if (handle->is_request()) { - return reinterpret_cast(handle)->body().unwrap(); - } else { - return reinterpret_cast(handle)->body().unwrap(); - } + auto *handle = RequestOrResponse::handle(obj); + return handle->is_request() ? + reinterpret_cast(handle)->body().unwrap() : + reinterpret_cast(handle)->body().unwrap(); } host_api::HttpOutgoingBody *RequestOrResponse::outgoing_body_handle(JSObject *obj) { MOZ_ASSERT(!is_incoming(obj)); - auto handle = RequestOrResponse::handle(obj); - if (handle->is_request()) { - return reinterpret_cast(handle)->body().unwrap(); - } else { - return reinterpret_cast(handle)->body().unwrap(); - } + auto *handle = RequestOrResponse::handle(obj); + return handle->is_request() ? + reinterpret_cast(handle)->body().unwrap() : + reinterpret_cast(handle)->body().unwrap(); } JSObject *RequestOrResponse::body_stream(JSObject *obj) { @@ -230,7 +224,7 @@ JSObject *RequestOrResponse::body_all_promise(JSObject *obj) { JSObject *RequestOrResponse::take_body_all_promise(JSObject *obj) { MOZ_ASSERT(is_instance(obj)); - auto promise = body_all_promise(obj); + auto *promise = body_all_promise(obj); JS::SetReservedSlot(obj, static_cast(Slots::BodyAllPromise), JS::NullValue()); return promise; } @@ -287,8 +281,8 @@ void RequestOrResponse::set_url(JSObject *obj, JS::Value url) { */ bool RequestOrResponse::body_unusable(JSContext *cx, JS::HandleObject body) { MOZ_ASSERT(JS::IsReadableStream(body)); - bool disturbed; - bool locked; + bool disturbed = false; + bool locked = false; MOZ_RELEASE_ASSERT(JS::ReadableStreamIsDisturbed(cx, body, &disturbed) && JS::ReadableStreamIsLocked(cx, body, &locked)); return disturbed || locked; @@ -396,9 +390,9 @@ bool RequestOrResponse::extract_body(JSContext *cx, JS::HandleObject self, return false; } - bool is_shared; + bool is_shared = false; JS::AutoCheckCannotGC noGC(cx); - auto temp_buf = JS_GetArrayBufferViewData(body_obj, &is_shared, noGC); + auto *temp_buf = JS_GetArrayBufferViewData(body_obj, &is_shared, noGC); memcpy(buf, temp_buf, length); } else if (body_obj && IsArrayBufferObject(body_obj)) { buffer = CopyArrayBuffer(cx, body_obj); @@ -447,7 +441,7 @@ bool RequestOrResponse::extract_body(JSContext *cx, JS::HandleObject self, return false; } - mozilla::DebugOnly disturbed; + mozilla::DebugOnly disturbed{}; MOZ_ASSERT(ReadableStreamIsDisturbed(cx, body_stream, &disturbed)); MOZ_ASSERT(!disturbed); @@ -497,13 +491,13 @@ unique_ptr RequestOrResponse::headers_handle_clone(JSCont return Headers::handle_clone(cx, headers); } - auto handle = RequestOrResponse::maybe_handle(self); + auto *handle = RequestOrResponse::maybe_handle(self); if (!handle) { return std::make_unique(); } auto res = handle->headers(); - if (auto *err = res.to_err()) { + if (const auto *err = res.to_err()) { HANDLE_ERROR(cx, *err); return nullptr; } @@ -524,20 +518,20 @@ bool finish_outgoing_body_streaming(JSContext *cx, HandleObject body_owner) { return true; } - auto body = RequestOrResponse::outgoing_body_handle(body_owner); + auto *body = RequestOrResponse::outgoing_body_handle(body_owner); auto res = body->close(); - if (auto *err = res.to_err()) { + if (const auto *err = res.to_err()) { HANDLE_ERROR(cx, *err); return false; } if (Request::is_instance(body_owner)) { - auto pending_handle = static_cast( + auto *pending_handle = static_cast( GetReservedSlot(body_owner, static_cast(Request::Slots::PendingResponseHandle)) .toPrivate()); SetReservedSlot(body_owner, static_cast(Request::Slots::PendingResponseHandle), PrivateValue(nullptr)); - ENGINE->queue_async_task(new ResponseFutureTask(body_owner, pending_handle)); + ENGINE->queue_async_task(js_new(body_owner, pending_handle)); } return true; @@ -550,7 +544,7 @@ bool RequestOrResponse::append_body(JSContext *cx, JS::HandleObject self, JS::Ha host_api::HttpIncomingBody *source_body = incoming_body_handle(source); host_api::HttpOutgoingBody *dest_body = outgoing_body_handle(self); auto res = dest_body->append(ENGINE, source_body, callback, callback_receiver); - if (auto *err = res.to_err()) { + if (const auto *err = res.to_err()) { HANDLE_ERROR(cx, *err); return false; } @@ -569,19 +563,25 @@ bool RequestOrResponse::append_body(JSContext *cx, JS::HandleObject self, JS::Ha JSObject *RequestOrResponse::headers(JSContext *cx, JS::HandleObject obj) { JSObject *headers = maybe_headers(obj); - if (!headers) { + if (headers == nullptr) { // Incoming request and incoming response headers are immutable per service worker // and fetch specs respectively. - Headers::HeadersGuard guard = is_incoming(obj) ? Headers::HeadersGuard::Immutable - : Request::is_instance(obj) ? Headers::HeadersGuard::Request - : Headers::HeadersGuard::Response; - host_api::HttpHeadersReadOnly *handle; - if (is_incoming(obj) && (handle = maybe_headers_handle(obj))) { + Headers::HeadersGuard guard; + if (is_incoming(obj)) { + guard = Headers::HeadersGuard::Immutable; + } else if (Request::is_instance(obj)) { + guard = Headers::HeadersGuard::Request; + } else { + guard = Headers::HeadersGuard::Response; + } + + host_api::HttpHeadersReadOnly *handle = nullptr; + if (is_incoming(obj) && ((handle = maybe_headers_handle(obj)) != nullptr)) { headers = Headers::create(cx, handle, guard); } else { headers = Headers::create(cx, guard); } - if (!headers) { + if (headers == nullptr) { return nullptr; } @@ -634,7 +634,7 @@ bool RequestOrResponse::parse_body(JSContext *cx, JS::HandleObject self, JS::Uni return throw_invalid_header(); } - auto values = Headers::get_index(cx, headers, idx.value()); + auto *values = Headers::get_index(cx, headers, idx.value()); auto maybe_mime = extract_mime_type(std::get<1>(*values)); if (maybe_mime.isErr()) { return throw_invalid_header(); @@ -680,7 +680,7 @@ bool RequestOrResponse::content_stream_read_then_handler(JSContext *cx, JS::Hand MOZ_ASSERT(extra.isObject()); JS::RootedObject catch_handler(cx, &extra.toObject()); #ifdef DEBUG - bool foundContents; + bool foundContents = false; if (!JS_HasElement(cx, catch_handler, 1, &foundContents)) { return false; } @@ -696,7 +696,7 @@ bool RequestOrResponse::content_stream_read_then_handler(JSContext *cx, JS::Hand return false; } #ifdef DEBUG - bool contentsIsArray; + bool contentsIsArray = false; if (!JS::IsArrayObject(cx, contents, &contentsIsArray)) { return false; } @@ -715,7 +715,7 @@ bool RequestOrResponse::content_stream_read_then_handler(JSContext *cx, JS::Hand JS::RootedValue done_val(cx); JS::RootedValue value(cx); #ifdef DEBUG - bool hasValue; + bool hasValue = false; if (!JS_HasProperty(cx, chunk_obj, "value", &hasValue)) { return false; } @@ -725,7 +725,7 @@ bool RequestOrResponse::content_stream_read_then_handler(JSContext *cx, JS::Hand return false; } #ifdef DEBUG - bool hasDone; + bool hasDone = false; if (!JS_HasProperty(cx, chunk_obj, "done", &hasDone)) { return false; } @@ -738,7 +738,7 @@ bool RequestOrResponse::content_stream_read_then_handler(JSContext *cx, JS::Hand if (done_val.toBoolean()) { // We finished reading the stream // Now we need to iterate/reduce `contents` JS Array into UniqueChars - uint32_t contentsLength; + uint32_t contentsLength = 0; if (!JS::GetArrayLength(cx, contents, &contentsLength)) { return false; } @@ -768,10 +768,10 @@ bool RequestOrResponse::content_stream_read_then_handler(JSContext *cx, JS::Hand return false; } JSObject *array = &val.toObject(); - bool is_shared; + bool is_shared = false; size_t length = JS_GetTypedArrayByteLength(array); JS::AutoCheckCannotGC nogc(cx); - auto bytes = reinterpret_cast(JS_GetUint8ArrayData(array, &is_shared, nogc)); + auto *bytes = reinterpret_cast(JS_GetUint8ArrayData(array, &is_shared, nogc)); memcpy(buf.get() + offset, bytes, length); offset += length; } @@ -803,7 +803,7 @@ bool RequestOrResponse::content_stream_read_then_handler(JSContext *cx, JS::Hand } { - uint32_t contentsLength; + uint32_t contentsLength = 0; if (!JS::GetArrayLength(cx, contents, &contentsLength)) { return false; } @@ -814,8 +814,9 @@ bool RequestOrResponse::content_stream_read_then_handler(JSContext *cx, JS::Hand // Read the next chunk. JS::RootedObject promise(cx, JS::ReadableStreamDefaultReaderRead(cx, reader)); - if (!promise) + if (!promise) { return false; +} return JS::AddPromiseReactions(cx, promise, then_handler, catch_handler); } @@ -837,7 +838,7 @@ bool RequestOrResponse::content_stream_read_catch_handler(JSContext *cx, JS::Han } MOZ_ASSERT(JS::IsReadableStream(stream)); #ifdef DEBUG - bool isError; + bool isError = false; if (!JS::ReadableStreamIsErrored(cx, stream, &isError)) { return false; } @@ -950,9 +951,9 @@ bool RequestOrResponse::bodyAll(JSContext *cx, JS::CallArgs args, JS::HandleObje // TODO(performance): don't reify a ReadableStream for body handles—use an AsyncTask instead JS::RootedObject stream(cx, body_stream(self)); if (!stream) { - stream = create_body_stream(cx, self); - if (!stream) + if (!(stream = create_body_stream(cx, self))) { return false; + } } if (!JS_SetElement(cx, stream, 1, body_parser)) { @@ -1004,7 +1005,7 @@ bool do_body_source_pull(JSContext *cx, HandleObject source, HandleObject body_o return true; } - ENGINE->queue_async_task(new BodyFutureTask(source)); + ENGINE->queue_async_task(js_new(source)); return true; } @@ -1077,23 +1078,25 @@ bool write_all_finish_callback(JSContext *cx, HandleObject then_handler) { bool reader_for_outgoing_body_then_handler(JSContext *cx, JS::HandleObject body_owner, JS::HandleValue extra, JS::CallArgs args) { JS::RootedObject then_handler(cx, &args.callee()); - auto body = RequestOrResponse::outgoing_body_handle(body_owner); + auto *body = RequestOrResponse::outgoing_body_handle(body_owner); // We're guaranteed to work with a native ReadableStreamDefaultReader here, // which in turn is guaranteed to vend {done: bool, value: any} objects to // read promise then callbacks. JS::RootedObject chunk_obj(cx, &args[0].toObject()); JS::RootedValue done_val(cx); - if (!JS_GetProperty(cx, chunk_obj, "done", &done_val)) + if (!JS_GetProperty(cx, chunk_obj, "done", &done_val)) { return false; + } if (done_val.toBoolean()) { return finish_outgoing_body_streaming(cx, body_owner); } JS::RootedValue val(cx); - if (!JS_GetProperty(cx, chunk_obj, "value", &val)) + if (!JS_GetProperty(cx, chunk_obj, "value", &val)) { return false; + } // The read operation returned something that's not a Uint8Array, or an array whose buffer has // been detached. @@ -1139,26 +1142,26 @@ bool reader_for_outgoing_body_then_handler(JSContext *cx, JS::HandleObject body_ return false; } { - bool is_shared; + bool is_shared = false; JS::AutoCheckCannotGC nogc(cx); - auto data = JS_GetUint8ArrayData(array, &is_shared, nogc); + auto *data = JS_GetUint8ArrayData(array, &is_shared, nogc); MOZ_ASSERT(data); MOZ_ASSERT(!is_shared); memcpy(ptr.get(), data, length); } bytes = host_api::HostBytes(std::move(ptr), length); } else { - bool is_shared; + bool is_shared = false; RootedObject buffer(cx, JS_GetArrayBufferViewBuffer(cx, array, &is_shared)); MOZ_ASSERT(!is_shared); - auto ptr = static_cast(StealArrayBufferContents(cx, buffer)); + auto *ptr = static_cast(StealArrayBufferContents(cx, buffer)); MOZ_ASSERT(ptr); bytes = host_api::HostBytes(unique_ptr(ptr), length); } auto res = body->write_all(ENGINE, std::move(bytes), write_all_finish_callback, then_handler); - if (auto *err = res.to_err()) { + if (const auto *err = res.to_err()) { HANDLE_ERROR(cx, *err); return false; } @@ -1195,7 +1198,7 @@ bool RequestOrResponse::maybe_stream_body(JSContext *cx, JS::HandleObject body_o auto *source_body = incoming_body_handle(body_owner); auto *dest_body = destination->body().unwrap(); auto res = dest_body->append(ENGINE, source_body, finish_outgoing_body_streaming, nullptr); - if (auto *err = res.to_err()) { + if (const auto *err = res.to_err()) { HANDLE_ERROR(cx, *err); return false; } @@ -1216,8 +1219,9 @@ bool RequestOrResponse::maybe_stream_body(JSContext *cx, JS::HandleObject body_o JS::RootedObject reader( cx, JS::ReadableStreamGetReader(cx, stream, JS::ReadableStreamReaderMode::Default)); - if (!reader) + if (!reader) { return false; + } // Create handlers for both `then` and `catch`. // These are functions with two reserved slots, in which we store all @@ -1230,21 +1234,25 @@ bool RequestOrResponse::maybe_stream_body(JSContext *cx, JS::HandleObject body_o JS::RootedValue extra(cx, JS::ObjectValue(*reader)); catch_handler = create_internal_method(cx, body_owner, extra); - if (!catch_handler) + if (!catch_handler) { return false; + } JS::RootedObject then_handler(cx); extra.setObject(*catch_handler); then_handler = create_internal_method(cx, body_owner, extra); - if (!then_handler) + if (!then_handler) { return false; + } JS::RootedObject promise(cx, JS::ReadableStreamDefaultReaderRead(cx, reader)); - if (!promise) + if (!promise) { return false; - if (!JS::AddPromiseReactions(cx, promise, then_handler, catch_handler)) + } + if (!JS::AddPromiseReactions(cx, promise, then_handler, catch_handler)) { return false; + } *requires_streaming = true; return true; @@ -1257,8 +1265,9 @@ JSObject *RequestOrResponse::create_body_stream(JSContext *cx, JS::HandleObject JS::RootedObject source(cx, streams::NativeStreamSource::create( cx, owner, JS::UndefinedHandleValue, body_source_pull_algorithm, body_source_cancel_algorithm)); - if (!source) + if (!source) { return nullptr; + } JS::RootedObject body_stream(cx, streams::NativeStreamSource::stream(source)); if (!body_stream) { @@ -1287,8 +1296,9 @@ bool RequestOrResponse::body_get(JSContext *cx, JS::CallArgs args, JS::HandleObj JS::RootedObject body_stream(cx, RequestOrResponse::body_stream(self)); if (!body_stream && create_if_undefined) { body_stream = create_body_stream(cx, self); - if (!body_stream) + if (!body_stream) { return false; + } } args.rval().setObjectOrNull(body_stream); @@ -1329,8 +1339,9 @@ bool Request::headers_get(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER(0) JSObject *headers = RequestOrResponse::headers(cx, self); - if (!headers) + if (!headers) { return false; + } args.rval().setObject(*headers); return true; @@ -1494,7 +1505,7 @@ bool Request::init_class(JSContext *cx, JS::HandleObject global) { // Initialize a pinned (i.e., never-moved, living forever) atom for the // default HTTP method. GET_atom = JS_AtomizeAndPinString(cx, "GET"); - return !!GET_atom; + return !(GET_atom == nullptr); } void Request::init_slots(JSObject *requestInstance) { @@ -1575,7 +1586,7 @@ bool Request::initialize(JSContext *cx, JS::HandleObject request, JS::HandleValu // internally as a handle (e.g. because the input is an incoming request), we would in // principle not need to ever reify it just to get a clone. // Applying these optimizations is somewhat complex though, so for now we're not doing so. - if (!(input_headers = RequestOrResponse::headers(cx, input_request))) { + if ((input_headers = RequestOrResponse::headers(cx, input_request)) == nullptr) { return false; } @@ -1601,8 +1612,9 @@ bool Request::initialize(JSContext *cx, JS::HandleObject request, JS::HandleValu // 1. Let `parsedURL` be the result of parsing `input` with `baseURL`. JS::RootedObject url_instance( cx, JS_NewObjectWithGivenProto(cx, &url::URL::class_, url::URL::proto_obj)); - if (!url_instance) + if (!url_instance) { return false; + } JS::RootedObject parsedURL( cx, url::URL::create(cx, url_instance, input, worker_location::WorkerLocation::url)); @@ -1782,7 +1794,8 @@ bool Request::initialize(JSContext *cx, JS::HandleObject request, JS::HandleValu JS::RootedValueVector signals(cx); if (signal_obj) { auto res = signals.append(JS::ObjectValue(*signal_obj)); - if (!res) return false; + if (!res) { return false; +} } // 30. Set this's signal to the result of creating a dependent abort signal from signals, @@ -1967,8 +1980,9 @@ static_assert((int)Response::Slots::Headers == (int)Request::Slots::Headers); static_assert((int)Response::Slots::Response == (int)Request::Slots::Request); host_api::HttpResponse *Response::maybe_response_handle(JSObject *obj) { - auto base = RequestOrResponse::maybe_handle(obj); + auto *base = RequestOrResponse::maybe_handle(obj); MOZ_ASSERT_IF(base, base->is_response()); + // NOLINTNEXTLINE: dynamic_cast requires RTTI, which we don't use. return static_cast(base); } @@ -2009,7 +2023,7 @@ Value Response::aborted(JSObject *obj) { // TODO(jake): Remove this when the reason phrase host-call is implemented void Response::set_status_message_from_code(JSContext *cx, JSObject *obj, uint16_t code) { - auto phrase = ""; + const char *phrase = nullptr; switch (code) { case 100: // 100 Continue - https://tools.ietf.org/html/rfc7231#section-6.2.1 @@ -2196,6 +2210,9 @@ void Response::set_status_message_from_code(JSContext *cx, JSObject *obj, uint16 phrase = ""; break; } + + MOZ_ASSERT(phrase); + JS::SetReservedSlot(obj, static_cast(Slots::StatusMessage), JS::StringValue(JS_NewStringCopyN(cx, phrase, strlen(phrase)))); } @@ -2271,8 +2288,9 @@ bool Response::headers_get(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER(0) JSObject *headers = RequestOrResponse::headers(cx, self); - if (!headers) + if (!headers) { return false; + } args.rval().setObject(*headers); return true; @@ -2338,7 +2356,7 @@ bool Response::redirect(JSContext *cx, unsigned argc, Value *vp) { // 3. If status is not a redirect status, then throw a RangeError. // A redirect status is a status that is 301, 302, 303, 307, or 308. auto statusVal = args.get(1); - uint16_t status; + uint16_t status = 0; if (statusVal.isUndefined()) { status = 302; } else { @@ -2437,7 +2455,7 @@ bool Response::json(JSContext *cx, unsigned argc, JS::Value *vp) { return api::throw_error(cx, FetchErrors::NonBodyResponseWithBody, status_str.c_str()); } - if (!statusText_val.isUndefined() && !(statusText = JS::ToString(cx, statusText_val))) { + if (!statusText_val.isUndefined() && ((statusText = JS::ToString(cx, statusText_val)) == nullptr)) { return false; } @@ -2448,20 +2466,20 @@ bool Response::json(JSContext *cx, unsigned argc, JS::Value *vp) { // 3. Create the Response JS object first JS::RootedObject response_obj(cx, Response::create(cx)); - if (!response_obj) { + if (response_obj == nullptr) { return false; } // Convert JSON string to a proper body value JS::RootedString json_string(cx, JS_NewUCStringCopyN(cx, json_callback.output.c_str(), json_callback.output.length())); - if (!json_string) { + if (json_string == nullptr) { return false; } JS::RootedValue body_val(cx, JS::StringValue(json_string)); // Create init object with headers that include content-type JS::RootedObject init_obj(cx, JS_NewPlainObject(cx)); - if (!init_obj) { + if (init_obj == nullptr) { return false; } @@ -2482,7 +2500,7 @@ bool Response::json(JSContext *cx, unsigned argc, JS::Value *vp) { } else { headers_obj = Headers::create(cx, Headers::HeadersGuard::Response); } - if (!headers_obj) { + if (headers_obj == nullptr) { return false; } @@ -2563,7 +2581,7 @@ bool Response::initialize(JSContext *cx, JS::HandleObject response, JS::HandleVa return false; } - if (!statusText_val.isUndefined() && !(statusText = JS::ToString(cx, statusText_val))) { + if (!statusText_val.isUndefined() && ((statusText = JS::ToString(cx, statusText_val)) == nullptr)) { return false; } @@ -2678,12 +2696,12 @@ bool Response::init_class(JSContext *cx, JS::HandleObject global) { // Initialize a pinned (i.e., never-moved, living forever) atom for the // response type values. - return (type_basic_atom = JS_AtomizeAndPinString(cx, "basic")) && - (type_cors_atom = JS_AtomizeAndPinString(cx, "cors")) && - (type_default_atom = JS_AtomizeAndPinString(cx, "default")) && - (type_error_atom = JS_AtomizeAndPinString(cx, "error")) && - (type_opaque_atom = JS_AtomizeAndPinString(cx, "opaque")) && - (type_opaque_redirect_atom = JS_AtomizeAndPinString(cx, "opaqueredirect")); + return ((type_basic_atom = JS_AtomizeAndPinString(cx, "basic")) != nullptr) && + ((type_cors_atom = JS_AtomizeAndPinString(cx, "cors")) != nullptr) && + ((type_default_atom = JS_AtomizeAndPinString(cx, "default")) != nullptr) && + ((type_error_atom = JS_AtomizeAndPinString(cx, "error")) != nullptr) && + ((type_opaque_atom = JS_AtomizeAndPinString(cx, "opaque")) != nullptr) && + ((type_opaque_redirect_atom = JS_AtomizeAndPinString(cx, "opaqueredirect")) != nullptr); } JSObject *Response::create(JSContext *cx) { @@ -2782,7 +2800,7 @@ bool ResponseFutureTask::run(api::Engine *engine) { return cancel(engine); } - auto response = maybe_response.value(); + auto *response = maybe_response.value(); RootedObject response_obj(cx, Response::create_incoming(cx, response)); if (!response_obj) { return false; @@ -2829,10 +2847,12 @@ namespace request_response { bool install(api::Engine *engine) { ENGINE = engine; - if (!Request::init_class(engine->cx(), engine->global())) + if (!Request::init_class(engine->cx(), engine->global())) { return false; - if (!Response::init_class(engine->cx(), engine->global())) + } + if (!Response::init_class(engine->cx(), engine->global())) { return false; + } return true; } diff --git a/builtins/web/fetch/request-response.h b/builtins/web/fetch/request-response.h index efedc6ed..3f641fc6 100644 --- a/builtins/web/fetch/request-response.h +++ b/builtins/web/fetch/request-response.h @@ -5,9 +5,9 @@ #include "headers.h" #include "host_api.h" -namespace builtins { -namespace web { -namespace fetch { + + +namespace builtins::web::fetch { namespace request_response { @@ -18,7 +18,7 @@ bool install(api::Engine *engine); class RequestOrResponse final { public: - enum class Slots { + enum class Slots : uint8_t { RequestOrResponse, BodyStream, BodyAllPromise, @@ -62,7 +62,7 @@ class RequestOrResponse final { * * The handle is guaranteed to be uniquely owned by the caller. */ - static unique_ptr headers_handle_clone(JSContext *, HandleObject self); + static unique_ptr headers_handle_clone(JSContext *cx, HandleObject self); /** * Returns the RequestOrResponse's Headers, reifying it if necessary. @@ -74,7 +74,7 @@ class RequestOrResponse final { using ParseBodyCB = bool(JSContext *cx, JS::HandleObject self, JS::UniqueChars buf, size_t len); - enum class BodyReadResult { + enum class BodyReadResult : uint8_t { ArrayBuffer, Blob, FormData, @@ -134,7 +134,7 @@ class Request final : public BuiltinImpl { public: static constexpr const char *class_name = "Request"; - enum class Slots { + enum class Slots : uint8_t { Request = static_cast(RequestOrResponse::Slots::RequestOrResponse), BodyStream = static_cast(RequestOrResponse::Slots::BodyStream), BodyAllPromise = static_cast(RequestOrResponse::Slots::BodyAllPromise), @@ -143,10 +143,10 @@ class Request final : public BuiltinImpl { Headers = static_cast(RequestOrResponse::Slots::Headers), URL = static_cast(RequestOrResponse::Slots::URL), Method = static_cast(RequestOrResponse::Slots::Count), - ResponsePromise, - PendingResponseHandle, - Signal, - Count, + ResponsePromise = 8, + PendingResponseHandle = 9, + Signal = 10, + Count = 11, }; static JSObject *response_promise(JSObject *obj); @@ -191,7 +191,7 @@ class Response final : public BuiltinImpl { public: static constexpr const char *class_name = "Response"; - enum class Slots { + enum class Slots : uint8_t { Response = static_cast(RequestOrResponse::Slots::RequestOrResponse), BodyStream = static_cast(RequestOrResponse::Slots::BodyStream), BodyAllPromise = static_cast(RequestOrResponse::Slots::BodyAllPromise), @@ -199,14 +199,14 @@ class Response final : public BuiltinImpl { BodyUsed = static_cast(RequestOrResponse::Slots::BodyUsed), Headers = static_cast(RequestOrResponse::Slots::Headers), Status = static_cast(RequestOrResponse::Slots::Count), - StatusMessage, - Redirected, - Type, - Aborted, - Count, + StatusMessage = 8, + Redirected = 9, + Type = 10, + Aborted = 11, + Count = 12, }; - enum Type { Basic, Cors, Default, Error, Opaque, OpaqueRedirect }; + enum Type : uint8_t { Basic, Cors, Default, Error, Opaque, OpaqueRedirect }; using Type = enum Type; static const JSFunctionSpec static_methods[]; @@ -242,7 +242,7 @@ class ResponseFutureTask final : public api::AsyncTask { host_api::FutureHttpIncomingResponse *future_; public: - explicit ResponseFutureTask(const HandleObject request, + explicit ResponseFutureTask(HandleObject request, host_api::FutureHttpIncomingResponse *future); [[nodiscard]] bool run(api::Engine *engine) override; @@ -252,8 +252,8 @@ class ResponseFutureTask final : public api::AsyncTask { void trace(JSTracer *trc) override { TraceEdge(trc, &request_, "Request for response future"); } }; -} // namespace fetch -} // namespace web -} // namespace builtins +} // namespace builtins::web::fetch + + #endif diff --git a/builtins/web/file.cpp b/builtins/web/file.cpp index 965d4e71..320da2f9 100644 --- a/builtins/web/file.cpp +++ b/builtins/web/file.cpp @@ -25,9 +25,9 @@ bool read_last_modified(JSContext *cx, HandleValue initv, int64_t *last_modified } // namespace -namespace builtins { -namespace web { -namespace file { + + +namespace builtins::web::file { using blob::Blob; @@ -57,7 +57,7 @@ bool File::name_get(JSContext *cx, unsigned argc, JS::Value *vp) { return api::throw_error(cx, api::Errors::WrongReceiver, "name get", "File"); } - auto name = JS::GetReservedSlot(self, static_cast(Slots::Name)).toString(); + auto *name = JS::GetReservedSlot(self, static_cast(Slots::Name)).toString(); args.rval().setString(name); return true; } @@ -99,7 +99,7 @@ bool File::init(JSContext *cx, HandleObject self, HandleValue fileBits, HandleVa // 3. If the `lastModified` member is provided, let d be set to the lastModified dictionary // member. If it is not provided, set d to the current date and time represented as the number of // milliseconds since the Unix Epoch. - int64_t lastModified; + int64_t lastModified = 0; if (!read_last_modified(cx, opts, &lastModified)) { return false; } @@ -159,6 +159,6 @@ bool File::init_class(JSContext *cx, JS::HandleObject global) { bool install(api::Engine *engine) { return File::init_class(engine->cx(), engine->global()); } -} // namespace file -} // namespace web -} // namespace builtins +} // namespace builtins::web::file + + diff --git a/builtins/web/file.h b/builtins/web/file.h index 310c76c2..aa392f01 100644 --- a/builtins/web/file.h +++ b/builtins/web/file.h @@ -4,16 +4,16 @@ #include "blob.h" #include "builtin.h" -namespace builtins { -namespace web { -namespace file { + + +namespace builtins::web::file { class File : public BuiltinImpl { static bool name_get(JSContext *cx, unsigned argc, JS::Value *vp); static bool lastModified_get(JSContext *cx, unsigned argc, JS::Value *vp); public: static constexpr int ParentSlots = blob::Blob::Slots::Count; - enum Slots { Name = ParentSlots, LastModified, Count }; + enum Slots : uint8_t { Name = ParentSlots, LastModified, Count }; static constexpr const char *class_name = "File"; static constexpr unsigned ctor_length = 2; @@ -33,8 +33,8 @@ class File : public BuiltinImpl { bool install(api::Engine *engine); -} // namespace file -} // namespace web -} // namespace builtins +} // namespace builtins::web::file + + #endif // BUILTINS_WEB_FILE_H diff --git a/builtins/web/form-data/form-data-encoder.cpp b/builtins/web/form-data/form-data-encoder.cpp index 1aa3775c..d13a7da3 100644 --- a/builtins/web/form-data/form-data-encoder.cpp +++ b/builtins/web/form-data/form-data-encoder.cpp @@ -162,9 +162,9 @@ std::string normalize_and_escape(std::string_view src) { }// namespace -namespace builtins { -namespace web { -namespace form_data { + + +namespace builtins::web::form_data { using blob::Blob; using file::File; @@ -175,14 +175,14 @@ using EntryList = JS::GCVector; struct StreamContext { StreamContext(const EntryList *entries, std::span outbuf) - : entries(entries), outbuf(outbuf), read(0), done(false) {} + : entries(entries), outbuf(outbuf) {} const EntryList *entries; std::span outbuf; - size_t read; - bool done; + size_t read{0}; + bool done{false}; - size_t remaining() { + [[nodiscard]] size_t remaining() const { MOZ_ASSERT(outbuf.size() >= read); return outbuf.size() - read; } @@ -229,17 +229,17 @@ struct StreamContext { // - Close: Write the closing boundary indicating the end of the multipart data. // - Done: Processing is complete. class MultipartFormDataImpl { - enum class State : int { Start, EntryHeader, EntryBody, EntryFooter, Close, Done }; + enum class State : uint8_t { Start, EntryHeader, EntryBody, EntryFooter, Close, Done }; - State state_; + State state_{State::Start}; std::string boundary_; std::string remainder_; std::string_view remainder_view_; - size_t chunk_idx_; - size_t file_leftovers_; + size_t chunk_idx_{0}; + size_t file_leftovers_{0}; - bool is_draining() { return (file_leftovers_ || remainder_.size()); }; + bool is_draining() { return ((file_leftovers_ != 0U) || (static_cast(!remainder_.empty()) != 0U)); }; template void write_and_store_remainder(StreamContext &stream, I first, I last); @@ -252,7 +252,7 @@ class MultipartFormDataImpl { public: MultipartFormDataImpl(std::string boundary) - : state_(State::Start), boundary_(std::move(boundary)), chunk_idx_(0), file_leftovers_(0) {} + : boundary_(std::move(boundary)) {} mozilla::Result query_length(JSContext* cx, const EntryList *entries); std::string boundary() { return boundary_; }; @@ -273,8 +273,8 @@ MultipartFormDataImpl::State MultipartFormDataImpl::next_state(StreamContext &st case State::EntryFooter: return finished ? State::Close : State::EntryHeader; case State::Close: - return State::Done; case State::Done: + // fallthrough return State::Done; default: MOZ_ASSERT_UNREACHABLE("Invalid state"); @@ -308,7 +308,7 @@ void MultipartFormDataImpl::maybe_drain_leftovers(JSContext *cx, StreamContext & MOZ_ASSERT(File::is_instance(entry.value)); RootedObject obj(cx, &entry.value.toObject()); - auto blob = Blob::blob(obj); + auto *blob = Blob::blob(obj); auto offset = blob->length() - file_leftovers_; file_leftovers_ -= stream.write(blob->begin() + offset, blob->end()); } @@ -386,7 +386,7 @@ bool MultipartFormDataImpl::handle_entry_header(JSContext *cx, StreamContext &st return false; } - auto tmp = type.size() ? std::string_view(type) : "application/octet-stream"; + auto tmp = (type.size() != 0U) ? std::string_view(type) : "application/octet-stream"; fmt::format_to(std::back_inserter(header), "; filename=\"{}\"\r\n", filename.value()); fmt::format_to(std::back_inserter(header), "Content-Type: {}\r\n\r\n", tmp); } @@ -417,7 +417,7 @@ bool MultipartFormDataImpl::handle_entry_body(JSContext *cx, StreamContext &stre MOZ_ASSERT(File::is_instance(entry.value)); RootedObject obj(cx, &entry.value.toObject()); - auto blob = Blob::blob(obj); + auto *blob = Blob::blob(obj); auto to_write = blob->length(); auto written = stream.write(blob->begin(), blob->end()); MOZ_ASSERT(written <= to_write); @@ -585,8 +585,8 @@ bool MultipartFormData::read(JSContext *cx, HandleObject self, std::spanboundary(); @@ -629,8 +629,8 @@ JSObject *MultipartFormData::form_data(JSObject *self) { mozilla::Result MultipartFormData::query_length(JSContext *cx, HandleObject self) { RootedObject obj(cx, form_data(self)); - auto entries = FormData::entry_list(obj); - auto impl = as_impl(self); + auto *entries = FormData::entry_list(obj); + auto *impl = as_impl(self); return impl->query_length(cx, entries); } @@ -678,13 +678,13 @@ JSObject *MultipartFormData::create(JSContext *cx, HandleObject form_data) { auto base64_str = base64::forgivingBase64Encode(bytes_str, base64::base64EncodeTable); auto boundary = fmt::format("--StarlingMonkeyFormBoundary{}", base64_str); - auto impl = new (std::nothrow) MultipartFormDataImpl(boundary); + auto impl = js::MakeUnique(boundary); if (!impl) { return nullptr; } JS::SetReservedSlot(self, Slots::Form, JS::ObjectValue(*form_data)); - JS::SetReservedSlot(self, Slots::Inner, JS::PrivateValue(reinterpret_cast(impl))); + JS::SetReservedSlot(self, Slots::Inner, JS::PrivateValue(reinterpret_cast(impl.release()))); return self; } @@ -699,12 +699,12 @@ bool MultipartFormData::constructor(JSContext *cx, unsigned argc, JS::Value *vp) void MultipartFormData::finalize(JS::GCContext *gcx, JSObject *self) { MOZ_ASSERT(is_instance(self)); - auto impl = as_impl(self); + auto *impl = as_impl(self); if (impl) { - delete impl; + js_delete(impl); } } -} // namespace form_data -} // namespace web -} // namespace builtins +} // namespace builtins::web::form_data + + diff --git a/builtins/web/form-data/form-data-encoder.h b/builtins/web/form-data/form-data-encoder.h index b0c473a5..782ec22a 100644 --- a/builtins/web/form-data/form-data-encoder.h +++ b/builtins/web/form-data/form-data-encoder.h @@ -3,9 +3,9 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace form_data { + + +namespace builtins::web::form_data { class OutOfMemory {}; class MultipartFormDataImpl; @@ -25,7 +25,7 @@ class MultipartFormData : public BuiltinImpl(src.data); + const auto *chars = reinterpret_cast(src.data); std::string_view sv(chars, src.len); return core::decode(cx, sv); @@ -47,13 +47,12 @@ JSObject *to_owned_buffer(JSContext *cx, jsmultipart::Slice src) { } // namespace -namespace builtins { -namespace web { -namespace form_data { + + +namespace builtins::web::form_data { using file::File; using form_data::FormData; -using form_data::FormDataEntry; using jsmultipart::RetCode; class MultipartParser : public FormDataParser { @@ -62,7 +61,7 @@ class MultipartParser : public FormDataParser { public: MultipartParser(std::string_view boundary) : boundary_(boundary) {} - virtual JSObject *parse(JSContext *cx, std::string_view body) override; + JSObject *parse(JSContext *cx, std::string_view body) override; }; JSObject *MultipartParser::parse(JSContext *cx, std::string_view body) { @@ -76,13 +75,14 @@ JSObject *MultipartParser::parse(JSContext *cx, std::string_view body) { } auto done = false; - auto data = reinterpret_cast(body.data()); + const auto *data = reinterpret_cast(body.data()); - jsmultipart::Slice input{data, body.size()}; - jsmultipart::Entry entry; + jsmultipart::Slice input{.data=data, .len=body.size()}; + jsmultipart::Entry entry{}; - auto encoding = const_cast(jsencoding::encoding_for_label_no_replacement( - reinterpret_cast(const_cast("UTF-8")), 5)); + const char* utf8_label = "UTF-8"; + const auto *encoding = jsencoding::encoding_for_label_no_replacement( + reinterpret_cast(utf8_label), 5); auto deleter1 = [&](auto *state) { jsmultipart::multipart_parser_free(state); }; std::unique_ptr parser( @@ -133,9 +133,9 @@ JSObject *MultipartParser::parse(JSContext *cx, std::string_view body) { return nullptr; } - bool ignore; - auto dst = reinterpret_cast(data.get()); - auto src = entry.value.data; + bool ignore = false; + auto *dst = reinterpret_cast(data.get()); + const auto *src = entry.value.data; jsencoding::decoder_decode_to_utf16(decoder.get(), src, &src_size, dst, &dst_size, false, &ignore); @@ -167,7 +167,7 @@ JSObject *MultipartParser::parse(JSContext *cx, std::string_view body) { } RootedValue content_type_val(cx); - if (entry.content_type.data && entry.content_type.len) { + if (entry.content_type.data && (entry.content_type.len != 0U)) { RootedString content_type(cx, to_owned_string(cx, entry.content_type)); if (!content_type) { return nullptr; @@ -219,7 +219,7 @@ JSObject *MultipartParser::parse(JSContext *cx, std::string_view body) { } class UrlParser : public FormDataParser { - virtual JSObject *parse(JSContext *cx, std::string_view body) override; + JSObject *parse(JSContext *cx, std::string_view body) override; }; JSObject *UrlParser::parse(JSContext *cx, std::string_view body) { @@ -275,8 +275,8 @@ JSObject *UrlParser::parse(JSContext *cx, std::string_view body) { std::unique_ptr FormDataParser::create(std::string_view content_type) { if (content_type.starts_with("multipart/form-data")) { - jsmultipart::Slice content_slice{(uint8_t *)(content_type.data()), content_type.size()}; - jsmultipart::Slice boundary_slice{nullptr, 0}; + jsmultipart::Slice content_slice{.data=(uint8_t *)(content_type.data()), .len=content_type.size()}; + jsmultipart::Slice boundary_slice{.data=nullptr, .len=0}; jsmultipart::boundary_from_content_type(&content_slice, &boundary_slice); if (boundary_slice.data == nullptr) { @@ -285,15 +285,19 @@ std::unique_ptr FormDataParser::create(std::string_view content_ std::string_view boundary((char *)boundary_slice.data, boundary_slice.len); return std::make_unique(boundary); - } else if (content_type.starts_with("application/x-www-form-urlencoded")) { + } + + if (content_type.starts_with("application/x-www-form-urlencoded")) { return std::make_unique(); - } else if (content_type.starts_with("text/plain")) { + } + + if (content_type.starts_with("text/plain")) { // TODO: add plain text content parser } return nullptr; } -} // namespace form_data -} // namespace web -} // namespace builtins +} // namespace builtins::web::form_data + + diff --git a/builtins/web/form-data/form-data-parser.h b/builtins/web/form-data/form-data-parser.h index 63100e85..de80a9aa 100644 --- a/builtins/web/form-data/form-data-parser.h +++ b/builtins/web/form-data/form-data-parser.h @@ -4,20 +4,24 @@ #include "builtin.h" #include "form-data.h" -namespace builtins { -namespace web { -namespace form_data { +namespace builtins::web::form_data { class FormDataParser { public: virtual JSObject *parse(JSContext *cx, std::string_view body) = 0; + + FormDataParser() = default; virtual ~FormDataParser() = default; + FormDataParser(const FormDataParser &) = default; + FormDataParser(FormDataParser &&) = delete; + + FormDataParser &operator=(const FormDataParser &) = default; + FormDataParser &operator=(FormDataParser &&) = delete; + static std::unique_ptr create(std::string_view content_type); }; -} // namespace form_data -} // namespace web -} // namespace builtins +} // namespace builtins::web::form_data #endif // BUILTINS_WEB_FORM_DATA_PARSER_ diff --git a/builtins/web/form-data/form-data.cpp b/builtins/web/form-data/form-data.cpp index 8c193dc6..17cc586c 100644 --- a/builtins/web/form-data/form-data.cpp +++ b/builtins/web/form-data/form-data.cpp @@ -13,14 +13,11 @@ namespace { -using builtins::web::form_data::FormData; using builtins::web::form_data::FormDataEntry; } // namespace -namespace builtins { -namespace web { -namespace form_data { +namespace builtins::web::form_data { using blob::Blob; using file::File; @@ -30,13 +27,14 @@ bool FormDataIterator::next(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER(0) JS::RootedObject form_obj(cx, &JS::GetReservedSlot(self, Slots::Form).toObject()); - const auto entries = FormData::entry_list(form_obj); + auto *const entries = FormData::entry_list(form_obj); size_t index = JS::GetReservedSlot(self, Slots::Index).toInt32(); uint8_t type = JS::GetReservedSlot(self, Slots::Type).toInt32(); JS::RootedObject result(cx, JS_NewPlainObject(cx)); - if (!result) + if (!result) { return false; + } if (index == entries->length()) { JS_DefineProperty(cx, result, "done", JS::TrueHandleValue, JSPROP_ENUMERATE); @@ -65,8 +63,9 @@ bool FormDataIterator::next(JSContext *cx, unsigned argc, JS::Value *vp) { switch (type) { case ITER_TYPE_ENTRIES: { JS::RootedObject pair(cx, JS::NewArrayObject(cx, 2)); - if (!pair) + if (!pair) { return false; + } JS_DefineElement(cx, pair, 0, key_val, JSPROP_ENUMERATE); JS_DefineElement(cx, pair, 1, val_val, JSPROP_ENUMERATE); result_val = JS::ObjectValue(*pair); @@ -110,11 +109,13 @@ const JSPropertySpec FormDataIterator::properties[] = { bool FormDataIterator::init_class(JSContext *cx, JS::HandleObject global) { JS::RootedObject iterator_proto(cx, JS::GetRealmIteratorPrototype(cx)); - if (!iterator_proto) + if (!iterator_proto) { return false; + } - if (!init_class_impl(cx, global, iterator_proto)) + if (!init_class_impl(cx, global, iterator_proto)) { return false; + } // Delete both the `FormDataIterator` global property and the // `constructor` property on `FormDataIterator.prototype`. The latter @@ -127,8 +128,9 @@ JSObject *FormDataIterator::create(JSContext *cx, JS::HandleObject form, uint8_t MOZ_RELEASE_ASSERT(type <= ITER_TYPE_VALUES); JS::RootedObject self(cx, JS_NewObjectWithGivenProto(cx, &class_, proto_obj)); - if (!self) + if (!self) { return nullptr; + } JS::SetReservedSlot(self, Slots::Form, JS::ObjectValue(*form)); JS::SetReservedSlot(self, Slots::Type, JS::Int32Value(type)); @@ -169,7 +171,7 @@ BUILTIN_ITERATOR_METHODS(FormData) FormData::EntryList *FormData::entry_list(JSObject *self) { MOZ_ASSERT(is_instance(self)); - auto entries = static_cast( + auto *entries = static_cast( JS::GetReservedSlot(self, static_cast(Slots::Entries)).toPrivate()); MOZ_ASSERT(entries); @@ -185,7 +187,7 @@ JSObject *create_opts(JSContext *cx, HandleObject blob) { } RootedString type(cx, Blob::type(blob)); - if (JS_GetStringLength(type)) { + if (JS_GetStringLength(type) != 0U) { RootedValue type_val(cx, JS::StringValue(type)); if (!JS_DefineProperty(cx, opts, "type", type_val, JSPROP_ENUMERATE)) { return nullptr; @@ -210,7 +212,7 @@ JSObject *create_opts(JSContext *cx, HandleObject blob) { // Note: all uses of `create-an-entry` immediately append it, too, so that part is folded in here. bool FormData::append(JSContext *cx, HandleObject self, std::string_view name, HandleValue value, HandleValue filename) { - auto entries = entry_list(self); + auto *entries = entry_list(self); // To create an entry given a string name, a string or Blob object value, // and optionally a scalar value string filename: @@ -258,7 +260,7 @@ bool FormData::append(JSContext *cx, HandleObject self, std::string_view name, H filename_val = filename; } - HandleValueArray arr = HandleValueArray(value); + auto arr = HandleValueArray(value); RootedObject file_bits(cx, NewArrayObject(cx, arr)); if (!file_bits) { return false; @@ -319,8 +321,8 @@ bool FormData::get(JSContext *cx, unsigned argc, JS::Value *vp) { return false; } - auto entries = entry_list(self); - auto it = std::find_if(entries->begin(), entries->end(), [&](const FormDataEntry &entry) { + auto *entries = entry_list(self); + auto *it = std::find_if(entries->begin(), entries->end(), [&](const FormDataEntry &entry) { return entry.name == std::string_view(name); }); @@ -341,7 +343,7 @@ bool FormData::getAll(JSContext *cx, unsigned argc, JS::Value *vp) { return false; } - auto entries = entry_list(self); + auto *entries = entry_list(self); JS::RootedObject array(cx, JS::NewArrayObject(cx, 0)); if (!array) { @@ -370,8 +372,8 @@ bool FormData::has(JSContext *cx, unsigned argc, JS::Value *vp) { return false; } - auto entries = entry_list(self); - auto it = std::find_if(entries->begin(), entries->end(), [&](const FormDataEntry &entry) { + auto *entries = entry_list(self); + auto *it = std::find_if(entries->begin(), entries->end(), [&](const FormDataEntry &entry) { return entry.name == std::string_view(name); }); @@ -390,17 +392,17 @@ bool FormData::set(JSContext *cx, unsigned argc, JS::Value *vp) { return false; } - auto entries = entry_list(self); - auto it = std::find_if(entries->begin(), entries->end(), [&](const FormDataEntry &entry) { + auto *entries = entry_list(self); + auto *it = std::find_if(entries->begin(), entries->end(), [&](const FormDataEntry &entry) { return entry.name == std::string_view(name); }); if (it != entries->end()) { it->value = value; return true; - } else { - return append(cx, self, name, value, filename); } + + return append(cx, self, name, value, filename); } JSObject *FormData::create(JSContext *cx) { @@ -409,7 +411,13 @@ JSObject *FormData::create(JSContext *cx) { return nullptr; } - SetReservedSlot(self, static_cast(Slots::Entries), JS::PrivateValue(new EntryList)); + auto entries = js::MakeUnique(); + if (entries == nullptr) { + JS_ReportOutOfMemory(cx); + return nullptr; + } + + SetReservedSlot(self, static_cast(Slots::Entries), JS::PrivateValue(entries.release())); return self; } @@ -439,9 +447,9 @@ bool FormData::constructor(JSContext *cx, unsigned argc, JS::Value *vp) { void FormData::finalize(JS::GCContext *gcx, JSObject *self) { MOZ_ASSERT(is_instance(self)); - auto entries = entry_list(self); - if (entries) { - free(entries); + auto *entries = entry_list(self); + if (!entries) { + js_delete(entries); } } @@ -454,7 +462,7 @@ void FormData::trace(JSTracer *trc, JSObject *self) { return; } - auto entries = entry_list(self); + auto *entries = entry_list(self); entries->trace(trc); } @@ -487,6 +495,4 @@ bool install(api::Engine *engine) { return true; } -} // namespace form_data -} // namespace web -} // namespace builtins +} // namespace builtins::web::form_data diff --git a/builtins/web/form-data/form-data.h b/builtins/web/form-data/form-data.h index 1514e674..af3e8e39 100644 --- a/builtins/web/form-data/form-data.h +++ b/builtins/web/form-data/form-data.h @@ -3,9 +3,9 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace form_data { + + +namespace builtins::web::form_data { struct FormDataEntry { FormDataEntry(std::string_view name, HandleValue value) : name(name), value(value) {} @@ -21,7 +21,7 @@ class FormDataIterator : public BuiltinNoConstructor { public: static constexpr const char *class_name = "FormDataIterator"; - enum Slots { Form, Type, Index, Count }; + enum Slots : uint8_t { Form, Type, Index, Count }; static bool next(JSContext *cx, unsigned argc, JS::Value *vp); @@ -32,7 +32,7 @@ class FormDataIterator : public BuiltinNoConstructor { static const unsigned ctor_length = 0; - static JSObject *create(JSContext *cx, JS::HandleObject params, uint8_t type); + static JSObject *create(JSContext *cx, JS::HandleObject form, uint8_t type); static bool init_class(JSContext *cx, JS::HandleObject global); }; @@ -48,7 +48,7 @@ class FormData : public BuiltinImpl { static bool keys(JSContext *cx, unsigned argc, JS::Value *vp); static bool values(JSContext *cx, unsigned argc, JS::Value *vp); - static bool append(JSContext *cx, HandleObject self, std::string_view key, HandleValue val, + static bool append(JSContext *cx, HandleObject self, std::string_view name, HandleValue val, HandleValue filename); using EntryList = JS::GCVector; @@ -69,7 +69,7 @@ class FormData : public BuiltinImpl { static constexpr unsigned ctor_length = 0; - enum Slots { Entries, Count }; + enum Slots : uint8_t { Entries, Count }; static JSObject *create(JSContext *cx); static bool init_class(JSContext *cx, HandleObject global); @@ -80,8 +80,8 @@ class FormData : public BuiltinImpl { bool install(api::Engine *engine); -} // namespace form_data -} // namespace web -} // namespace builtins +} // namespace builtins::web::form_data + + #endif // BUILTINS_WEB_FORM_FDATA_H diff --git a/builtins/web/performance.cpp b/builtins/web/performance.cpp index af2ff336..b945e2d2 100644 --- a/builtins/web/performance.cpp +++ b/builtins/web/performance.cpp @@ -5,9 +5,9 @@ namespace { using FpMilliseconds = std::chrono::duration; } // namespace -namespace builtins { -namespace web { -namespace performance { + + +namespace builtins::web::performance { std::optional Performance::timeOrigin; @@ -71,6 +71,6 @@ bool install(api::Engine *engine) { return true; } -} // namespace performance -} // namespace web -} // namespace builtins +} // namespace builtins::web::performance + + diff --git a/builtins/web/performance.h b/builtins/web/performance.h index a94a2fa3..4c5e0a05 100644 --- a/builtins/web/performance.h +++ b/builtins/web/performance.h @@ -3,15 +3,15 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace performance { + + +namespace builtins::web::performance { class Performance : public BuiltinNoConstructor { public: static constexpr const char *class_name = "Performance"; static const int ctor_length = 0; - enum Slots { Count }; + enum Slots : uint8_t { Count }; static const JSFunctionSpec methods[]; static const JSFunctionSpec static_methods[]; static const JSPropertySpec properties[]; @@ -27,8 +27,8 @@ class Performance : public BuiltinNoConstructor { bool install(api::Engine *engine); -} // namespace performance -} // namespace web -} // namespace builtins +} // namespace builtins::web::performance + + #endif diff --git a/builtins/web/queue-microtask.cpp b/builtins/web/queue-microtask.cpp index 5d923c0b..d22a6371 100644 --- a/builtins/web/queue-microtask.cpp +++ b/builtins/web/queue-microtask.cpp @@ -1,8 +1,8 @@ #include "queue-microtask.h" -namespace builtins { -namespace web { -namespace queue_microtask { + + +namespace builtins::web::queue_microtask { /** * The `queueMicrotask` global function @@ -41,6 +41,6 @@ bool install(api::Engine *engine) { return JS_DefineFunctions(engine->cx(), engine->global(), methods); } -} // namespace queue_microtask -} // namespace web -} // namespace builtins +} // namespace builtins::web::queue_microtask + + diff --git a/builtins/web/queue-microtask.h b/builtins/web/queue-microtask.h index 4b190479..a9955dd8 100644 --- a/builtins/web/queue-microtask.h +++ b/builtins/web/queue-microtask.h @@ -3,14 +3,14 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace queue_microtask { + + +namespace builtins::web::queue_microtask { bool install(api::Engine *engine); -} // namespace queue_microtask -} // namespace web -} // namespace builtins +} // namespace builtins::web::queue_microtask + + #endif diff --git a/builtins/web/streams/buf-reader.cpp b/builtins/web/streams/buf-reader.cpp index bd9bf6f0..a9ca11d4 100644 --- a/builtins/web/streams/buf-reader.cpp +++ b/builtins/web/streams/buf-reader.cpp @@ -11,9 +11,9 @@ constexpr size_t CHUNK_SIZE = 8192; } // namespace -namespace builtins { -namespace web { -namespace streams { + + +namespace builtins::web::streams { class StreamTask final : public api::AsyncTask { Heap reader_; @@ -96,7 +96,7 @@ bool cancel(JSContext *cx, JS::CallArgs args, HandleObject stream, HandleObject } bool pull(JSContext *cx, JS::CallArgs args, HandleObject source, HandleObject owner, HandleObject controller) { - api::Engine::get(cx)->queue_async_task(new StreamTask(owner)); + api::Engine::get(cx)->queue_async_task(js_new(owner)); args.rval().setUndefined(); return true; } @@ -123,6 +123,7 @@ size_t BufReader::position(JSObject *self) { void BufReader::set_position(JSObject *self, size_t pos) { MOZ_ASSERT(is_instance(self)); + // NOLINTNEXTLINE(performance-no-int-to-ptr): we use a private slot to store the position, not a pointer. JS::SetReservedSlot(self, Slots::Position, JS::PrivateValue(reinterpret_cast(pos))); } @@ -146,6 +147,6 @@ JSObject *BufReader::create(JSContext *cx, JS::HandleObject user, BufReader::Rea return self; } -} // namespace streams -} // namespace web -} // namespace builtins +} // namespace builtins::web::streams + + diff --git a/builtins/web/streams/buf-reader.h b/builtins/web/streams/buf-reader.h index 4374aa6b..199f239b 100644 --- a/builtins/web/streams/buf-reader.h +++ b/builtins/web/streams/buf-reader.h @@ -3,9 +3,9 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace streams { + + +namespace builtins::web::streams { class BufReader : public BuiltinNoConstructor { public: @@ -16,7 +16,7 @@ class BufReader : public BuiltinNoConstructor { static constexpr const char *class_name = "NativeBufReader"; - enum Slots { User, Stream, Read, Position, Count }; + enum Slots : uint8_t { User, Stream, Read, Position, Count }; using Buffer = std::span; @@ -26,7 +26,7 @@ class BufReader : public BuiltinNoConstructor { // already been enqueued or consumed by previous reads. The callee should read // up to `buf.size()` bytes into `buf`. The actual number of bytes read has // to be stored in `read`, and `done` set to true when no further data remains. - typedef bool ReadFn(JSContext *cx, HandleObject user, Buffer buf, size_t start, size_t *read, bool *done); + using ReadFn = bool (JSContext *, HandleObject, Buffer, size_t, size_t *, bool *); static JSObject *user(JSObject *self); static JSObject *stream(JSObject *self); @@ -34,11 +34,11 @@ class BufReader : public BuiltinNoConstructor { static size_t position(JSObject *self); static void set_position(JSObject *self, size_t pos); - static JSObject *create(JSContext *cx, HandleObject owner, ReadFn *read); + static JSObject *create(JSContext *cx, HandleObject user, ReadFn *read); }; -} // namespace streams -} // namespace web -} // namespace builtins +} // namespace builtins::web::streams + + #endif // BUILTINS_WEB_STREAMS_BUF_FREADER_H diff --git a/builtins/web/streams/compression-stream.cpp b/builtins/web/streams/compression-stream.cpp index 4f2a5642..257d13c8 100644 --- a/builtins/web/streams/compression-stream.cpp +++ b/builtins/web/streams/compression-stream.cpp @@ -1,10 +1,4 @@ -// TODO: remove these once the warnings are fixed -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" -#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" #include "js/experimental/TypedData.h" -#pragma clang diagnostic pop - #include "zlib.h" #include "compression-stream.h" @@ -13,13 +7,13 @@ #include "transform-stream-default-controller.h" #include "transform-stream.h" -namespace builtins { -namespace web { -namespace streams { + + +namespace builtins::web::streams { namespace { -enum class Format { +enum class Format : uint8_t { GZIP, Deflate, DeflateRaw, @@ -69,7 +63,7 @@ bool deflate_chunk(JSContext *cx, JS::HandleObject self, JS::HandleValue chunk, return false; } - if (data->size() == 0) { + if (data->empty()) { return true; } @@ -116,19 +110,19 @@ bool deflate_chunk(JSContext *cx, JS::HandleObject self, JS::HandleValue chunk, zstream->avail_out = BUFFER_SIZE; zstream->next_out = buffer; int err = deflate(zstream, finished ? Z_FINISH : Z_NO_FLUSH); - if (!((finished && err == Z_STREAM_END) || err == Z_OK)) { + if ((!finished || err != Z_STREAM_END) && err != Z_OK) { return api::throw_error(cx, StreamErrors::CompressingChunkFailed); } size_t bytes = BUFFER_SIZE - zstream->avail_out; - if (bytes) { + if (bytes != 0U) { JS::RootedObject out_obj(cx, JS_NewUint8Array(cx, bytes)); - if (!out_obj) { + if (out_obj == nullptr) { return false; } { - bool is_shared; + bool is_shared = false; JS::AutoCheckCannotGC nogc(cx); uint8_t *out_buffer = JS_GetUint8ArrayData(out_obj, &is_shared, nogc); memcpy(out_buffer, buffer, bytes); @@ -245,7 +239,7 @@ JSObject *create(JSContext *cx, JS::HandleObject stream, Format format) { // The remainder of the function deals with setting up the deflate state used // for compressing chunks. - z_stream *zstream = (z_stream *)JS_malloc(cx, sizeof(z_stream)); + auto *zstream = (z_stream *)JS_malloc(cx, sizeof(z_stream)); if (!zstream) { JS_ReportOutOfMemory(cx); return nullptr; @@ -254,7 +248,7 @@ JSObject *create(JSContext *cx, JS::HandleObject stream, Format format) { memset(zstream, 0, sizeof(z_stream)); JS::SetReservedSlot(stream, CompressionStream::Slots::State, JS::PrivateValue(zstream)); - uint8_t *buffer = (uint8_t *)JS_malloc(cx, BUFFER_SIZE); + auto *buffer = (uint8_t *)JS_malloc(cx, BUFFER_SIZE); if (!buffer) { JS_ReportOutOfMemory(cx); return nullptr; @@ -297,11 +291,11 @@ bool CompressionStream::constructor(JSContext *cx, unsigned argc, JS::Value *vp) } enum Format format; - if (!strcmp(format_chars.begin(), "deflate-raw")) { + if (strcmp(format_chars.begin(), "deflate-raw") == 0) { format = Format::DeflateRaw; - } else if (!strcmp(format_chars.begin(), "deflate")) { + } else if (strcmp(format_chars.begin(), "deflate") == 0) { format = Format::Deflate; - } else if (!strcmp(format_chars.begin(), "gzip")) { + } else if (strcmp(format_chars.begin(), "gzip") == 0) { format = Format::GZIP; } else { return api::throw_error(cx, StreamErrors::InvalidCompressionFormat, format_chars.begin()); @@ -324,18 +318,20 @@ bool CompressionStream::init_class(JSContext *cx, JS::HandleObject global) { } JSFunction *transformFun = JS_NewFunction(cx, transformAlgorithm, 1, 0, "CS Transform"); - if (!transformFun) + if (!transformFun) { return false; + } transformAlgo.init(cx, JS_GetFunctionObject(transformFun)); JSFunction *flushFun = JS_NewFunction(cx, flushAlgorithm, 1, 0, "CS Flush"); - if (!flushFun) + if (!flushFun) { return false; + } flushAlgo.init(cx, JS_GetFunctionObject(flushFun)); return true; } -} // namespace streams -} // namespace web -} // namespace builtins +} // namespace builtins::web::streams + + diff --git a/builtins/web/streams/compression-stream.h b/builtins/web/streams/compression-stream.h index e2085137..2beb4711 100644 --- a/builtins/web/streams/compression-stream.h +++ b/builtins/web/streams/compression-stream.h @@ -3,9 +3,9 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace streams { + + +namespace builtins::web::streams { /** * Implementation of the WICG CompressionStream builtin. @@ -22,7 +22,7 @@ class CompressionStream : public BuiltinImpl { public: static constexpr const char *class_name = "CompressionStream"; - enum Slots { Transform, Format, State, Buffer, Count }; + enum Slots : uint8_t { Transform, Format, State, Buffer, Count }; static const JSFunctionSpec static_methods[]; static const JSPropertySpec static_properties[]; @@ -35,8 +35,8 @@ class CompressionStream : public BuiltinImpl { static bool constructor(JSContext *cx, unsigned argc, JS::Value *vp); }; -} // namespace streams -} // namespace web -} // namespace builtins +} // namespace builtins::web::streams + + #endif diff --git a/builtins/web/streams/decompression-stream.cpp b/builtins/web/streams/decompression-stream.cpp index 7db7d6c2..ca025570 100644 --- a/builtins/web/streams/decompression-stream.cpp +++ b/builtins/web/streams/decompression-stream.cpp @@ -1,26 +1,17 @@ -// TODO: remove these once the warnings are fixed -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" -#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" #include "js/experimental/TypedData.h" -#pragma clang diagnostic pop - #include "zlib.h" #include "decompression-stream.h" #include "encode.h" #include "transform-stream-default-controller.h" #include "transform-stream.h" - #include "stream-errors.h" -namespace builtins { -namespace web { -namespace streams { +namespace builtins::web::streams { namespace { -enum class Format { +enum class Format : uint8_t { GZIP, Deflate, DeflateRaw, @@ -64,7 +55,7 @@ bool inflate_chunk(JSContext *cx, JS::HandleObject self, JS::HandleValue chunk, return false; } - if (data->size() == 0) { + if (data->empty()) { return true; } @@ -122,14 +113,14 @@ bool inflate_chunk(JSContext *cx, JS::HandleObject self, JS::HandleValue chunk, } size_t bytes = BUFFER_SIZE - zstream->avail_out; - if (bytes) { + if (bytes != 0U) { JS::RootedObject out_obj(cx, JS_NewUint8Array(cx, bytes)); if (!out_obj) { return false; } { - bool is_shared; + bool is_shared = false; JS::AutoCheckCannotGC nogc; uint8_t *out_buffer = JS_GetUint8ArrayData(out_obj, &is_shared, nogc); memcpy(out_buffer, buffer, bytes); @@ -249,7 +240,7 @@ JSObject *create(JSContext *cx, JS::HandleObject stream, Format format) { // The remainder of the function deals with setting up the inflate state used // for decompressing chunks. - z_stream *zstream = (z_stream *)JS_malloc(cx, sizeof(z_stream)); + auto *zstream = (z_stream *)JS_malloc(cx, sizeof(z_stream)); if (!zstream) { JS_ReportOutOfMemory(cx); return nullptr; @@ -258,7 +249,7 @@ JSObject *create(JSContext *cx, JS::HandleObject stream, Format format) { memset(zstream, 0, sizeof(z_stream)); JS::SetReservedSlot(stream, DecompressionStream::Slots::State, JS::PrivateValue(zstream)); - uint8_t *buffer = (uint8_t *)JS_malloc(cx, BUFFER_SIZE); + auto *buffer = (uint8_t *)JS_malloc(cx, BUFFER_SIZE); if (!buffer) { JS_ReportOutOfMemory(cx); return nullptr; @@ -300,11 +291,11 @@ bool DecompressionStream::constructor(JSContext *cx, unsigned argc, JS::Value *v } enum Format format; - if (!strcmp(format_chars.begin(), "deflate-raw")) { + if (strcmp(format_chars.begin(), "deflate-raw") == 0) { format = Format::DeflateRaw; - } else if (!strcmp(format_chars.begin(), "deflate")) { + } else if (strcmp(format_chars.begin(), "deflate") == 0) { format = Format::Deflate; - } else if (!strcmp(format_chars.begin(), "gzip")) { + } else if (strcmp(format_chars.begin(), "gzip") == 0) { format = Format::GZIP; } else { return api::throw_error(cx, api::Errors::TypeError, "DecompressionStream constructor", @@ -328,18 +319,20 @@ bool DecompressionStream::init_class(JSContext *cx, JS::HandleObject global) { } JSFunction *transformFun = JS_NewFunction(cx, transformAlgorithm, 1, 0, "DS Transform"); - if (!transformFun) + if (!transformFun) { return false; + } transformAlgo.init(cx, JS_GetFunctionObject(transformFun)); JSFunction *flushFun = JS_NewFunction(cx, flushAlgorithm, 1, 0, "DS Flush"); - if (!flushFun) + if (!flushFun) { return false; + } flushAlgo.init(cx, JS_GetFunctionObject(flushFun)); return true; } -} // namespace streams -} // namespace web -} // namespace builtins +} // namespace builtins::web::streams + + diff --git a/builtins/web/streams/decompression-stream.h b/builtins/web/streams/decompression-stream.h index ee4a3008..afdd92e6 100644 --- a/builtins/web/streams/decompression-stream.h +++ b/builtins/web/streams/decompression-stream.h @@ -3,9 +3,9 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace streams { + + +namespace builtins::web::streams { /** * Implementation of the WICG DecompressionStream builtin. @@ -22,7 +22,7 @@ class DecompressionStream : public BuiltinImpl { public: static constexpr const char *class_name = "DecompressionStream"; - enum Slots { Transform, Format, State, Buffer, Count }; + enum Slots : uint8_t { Transform, Format, State, Buffer, Count }; static const JSFunctionSpec static_methods[]; static const JSPropertySpec static_properties[]; @@ -35,8 +35,8 @@ class DecompressionStream : public BuiltinImpl { static bool constructor(JSContext *cx, unsigned argc, JS::Value *vp); }; -} // namespace streams -} // namespace web -} // namespace builtins +} // namespace builtins::web::streams + + #endif diff --git a/builtins/web/streams/native-stream-sink.cpp b/builtins/web/streams/native-stream-sink.cpp index f034a9ce..36dec870 100644 --- a/builtins/web/streams/native-stream-sink.cpp +++ b/builtins/web/streams/native-stream-sink.cpp @@ -1,19 +1,12 @@ -// TODO: remove these once the warnings are fixed -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" -#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" #include "js/experimental/TypedData.h" // used within "js/Stream.h" -#pragma clang diagnostic pop - #include "js/Stream.h" #include "native-stream-sink.h" // A JS class to use as the underlying sink for native writable streams, used // for TransformStream. -namespace builtins { -namespace web { -namespace streams { + +namespace builtins::web::streams { JSObject *NativeStreamSink::owner(JSObject *self) { return &JS::GetReservedSlot(self, Slots::Owner).toObject(); @@ -132,8 +125,9 @@ JSObject *NativeStreamSink::create(JSContext *cx, JS::HandleObject owner, CloseAlgorithmImplementation *close, AbortAlgorithmImplementation *abort) { JS::RootedObject sink(cx, JS_NewObjectWithGivenProto(cx, &class_, proto_obj)); - if (!sink) + if (!sink) { return nullptr; + } JS::SetReservedSlot(sink, Slots::Owner, JS::ObjectValue(*owner)); JS::SetReservedSlot(sink, Slots::StartPromise, startPromise); @@ -142,6 +136,6 @@ JSObject *NativeStreamSink::create(JSContext *cx, JS::HandleObject owner, JS::SetReservedSlot(sink, Slots::CloseAlgorithm, JS::PrivateValue((void *)close)); return sink; } -} // namespace streams -} // namespace web -} // namespace builtins +} // namespace builtins::web::streams + + diff --git a/builtins/web/streams/native-stream-sink.h b/builtins/web/streams/native-stream-sink.h index 94c9c2c0..5370140b 100644 --- a/builtins/web/streams/native-stream-sink.h +++ b/builtins/web/streams/native-stream-sink.h @@ -3,16 +3,16 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace streams { + + +namespace builtins::web::streams { class NativeStreamSink : public BuiltinNoConstructor { private: public: static constexpr const char *class_name = "NativeStreamSink"; - enum Slots { + enum Slots : uint8_t { Owner, // TransformStream. Controller, // The WritableStreamDefaultController. InternalWriter, // Only used to lock the stream if it's consumed internally. @@ -25,14 +25,9 @@ class NativeStreamSink : public BuiltinNoConstructor { Count }; - typedef bool WriteAlgorithmImplementation(JSContext *cx, JS::CallArgs args, - JS::HandleObject stream, JS::HandleObject owner, - JS::HandleValue chunk); - typedef bool AbortAlgorithmImplementation(JSContext *cx, JS::CallArgs args, - JS::HandleObject stream, JS::HandleObject owner, - JS::HandleValue reason); - typedef bool CloseAlgorithmImplementation(JSContext *cx, JS::CallArgs args, - JS::HandleObject stream, JS::HandleObject owner); + using WriteAlgorithmImplementation = bool (JSContext *, JS::CallArgs, JS::HandleObject, JS::HandleObject, JS::HandleValue); + using AbortAlgorithmImplementation = bool (JSContext *, JS::CallArgs, JS::HandleObject, JS::HandleObject, JS::HandleValue); + using CloseAlgorithmImplementation = bool (JSContext *, JS::CallArgs, JS::HandleObject, JS::HandleObject); static const JSFunctionSpec static_methods[]; static const JSPropertySpec static_properties[]; @@ -62,7 +57,7 @@ class NativeStreamSink : public BuiltinNoConstructor { AbortAlgorithmImplementation *abort); }; -} // namespace streams -} // namespace web -} // namespace builtins +} // namespace builtins::web::streams + + #endif diff --git a/builtins/web/streams/native-stream-source.cpp b/builtins/web/streams/native-stream-source.cpp index 8d8d4475..aa012529 100644 --- a/builtins/web/streams/native-stream-source.cpp +++ b/builtins/web/streams/native-stream-source.cpp @@ -1,10 +1,4 @@ -// TODO: remove these once the warnings are fixed -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" -#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" #include "js/experimental/TypedData.h" // used within "js/Stream.h" -#pragma clang diagnostic pop - #include "js/Stream.h" #include "native-stream-sink.h" @@ -14,9 +8,9 @@ // A JS class to use as the underlying source for native readable streams, used // for Request/Response bodies and TransformStream. -namespace builtins { -namespace web { -namespace streams { + + +namespace builtins::web::streams { JSObject *NativeStreamSource::owner(JSObject *self) { MOZ_ASSERT(is_instance(self)); @@ -51,9 +45,8 @@ JSObject *NativeStreamSource::stream(JSObject *self) { */ JSObject *NativeStreamSource::get_controller_source(JSContext *cx, JS::HandleObject controller) { JS::RootedValue source(cx); - bool success __attribute__((unused)); - success = JS::ReadableStreamControllerGetUnderlyingSource(cx, controller, &source); - MOZ_ASSERT(success); + auto success = JS::ReadableStreamControllerGetUnderlyingSource(cx, controller, &source); + MOZ_RELEASE_ASSERT(success); return source.isObject() ? &source.toObject() : nullptr; } @@ -86,7 +79,7 @@ JSObject *NativeStreamSource::piped_to_transform_stream(JSObject *self) { bool NativeStreamSource::lock_stream(JSContext *cx, JS::HandleObject stream) { MOZ_ASSERT(JS::IsReadableStream(stream)); - bool locked; + bool locked = false; JS::ReadableStreamIsLocked(cx, stream, &locked); if (locked) { return api::throw_error(cx, StreamErrors::StreamAlreadyLocked); @@ -97,8 +90,9 @@ bool NativeStreamSource::lock_stream(JSContext *cx, JS::HandleObject stream) { auto mode = JS::ReadableStreamReaderMode::Default; JS::RootedObject reader(cx, JS::ReadableStreamGetReader(cx, stream, mode)); - if (!reader) + if (!reader) { return false; + } JS::SetReservedSlot(self, Slots::InternalReader, JS::ObjectValue(*reader)); return true; @@ -183,6 +177,6 @@ JSObject *NativeStreamSource::create(JSContext *cx, JS::HandleObject owner, JS:: JS::SetReservedSlot(source, Slots::Stream, JS::ObjectValue(*stream)); return source; } -} // namespace streams -} // namespace web -} // namespace builtins +} // namespace builtins::web::streams + + diff --git a/builtins/web/streams/native-stream-source.h b/builtins/web/streams/native-stream-source.h index 4da0738a..f521060a 100644 --- a/builtins/web/streams/native-stream-source.h +++ b/builtins/web/streams/native-stream-source.h @@ -3,14 +3,14 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace streams { + + +namespace builtins::web::streams { class NativeStreamSource : public BuiltinNoConstructor { private: public: static constexpr const char *class_name = "NativeStreamSource"; - enum Slots { + enum Slots : uint8_t { Owner, // Request or Response object, or TransformStream. Stream, // The ReadableStreamDefaultObject. InternalReader, // Only used to lock the stream if it's consumed internally. @@ -27,12 +27,8 @@ class NativeStreamSource : public BuiltinNoConstructor { static const JSPropertySpec static_properties[]; static const JSFunctionSpec methods[]; static const JSPropertySpec properties[]; - typedef bool PullAlgorithmImplementation(JSContext *cx, JS::CallArgs args, - JS::HandleObject stream, JS::HandleObject owner, - JS::HandleObject controller); - typedef bool CancelAlgorithmImplementation(JSContext *cx, JS::CallArgs args, - JS::HandleObject stream, JS::HandleObject owner, - JS::HandleValue reason); + using PullAlgorithmImplementation = bool (JSContext *, JS::CallArgs, JS::HandleObject, JS::HandleObject, JS::HandleObject); + using CancelAlgorithmImplementation = bool (JSContext *, JS::CallArgs, JS::HandleObject, JS::HandleObject, JS::HandleValue); static JSObject *owner(JSObject *self); static JSObject *stream(JSObject *self); static JS::Value startPromise(JSObject *self); @@ -61,7 +57,7 @@ class NativeStreamSource : public BuiltinNoConstructor { PullAlgorithmImplementation *pull, CancelAlgorithmImplementation *cancel, JS::HandleFunction size = nullptr, double highWaterMark = 0.0); }; -} // namespace streams -} // namespace web -} // namespace builtins +} // namespace builtins::web::streams + + #endif diff --git a/builtins/web/streams/streams.cpp b/builtins/web/streams/streams.cpp index d274a085..9f0a3e33 100644 --- a/builtins/web/streams/streams.cpp +++ b/builtins/web/streams/streams.cpp @@ -2,34 +2,36 @@ #include "buf-reader.h" #include "compression-stream.h" #include "decompression-stream.h" -#include "event_loop.h" #include "native-stream-sink.h" #include "native-stream-source.h" #include "transform-stream-default-controller.h" #include "transform-stream.h" -namespace builtins { -namespace web { -namespace streams { +namespace builtins::web::streams { bool install(api::Engine *engine) { - if (!NativeStreamSource::init_class(engine->cx(), engine->global())) + if (!NativeStreamSource::init_class(engine->cx(), engine->global())) { return false; - if (!NativeStreamSink::init_class(engine->cx(), engine->global())) + } + if (!NativeStreamSink::init_class(engine->cx(), engine->global())) { return false; - if (!TransformStreamDefaultController::init_class(engine->cx(), engine->global())) + } + if (!TransformStreamDefaultController::init_class(engine->cx(), engine->global())) { return false; - if (!TransformStream::init_class(engine->cx(), engine->global())) + } + if (!TransformStream::init_class(engine->cx(), engine->global())) { return false; - if (!CompressionStream::init_class(engine->cx(), engine->global())) + } + if (!CompressionStream::init_class(engine->cx(), engine->global())) { return false; - if (!DecompressionStream::init_class(engine->cx(), engine->global())) + } + if (!DecompressionStream::init_class(engine->cx(), engine->global())) { return false; - if (!BufReader::init_class(engine->cx(), engine->global())) + } + if (!BufReader::init_class(engine->cx(), engine->global())) { return false; + } return true; } -} // namespace streams -} // namespace web -} // namespace builtins +} // namespace builtins::web::streams diff --git a/builtins/web/streams/streams.h b/builtins/web/streams/streams.h index 8002be68..cab049f4 100644 --- a/builtins/web/streams/streams.h +++ b/builtins/web/streams/streams.h @@ -3,12 +3,12 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace streams { + + +namespace builtins::web::streams { bool install(api::Engine *engine); -} // namespace streams -} // namespace web -} // namespace builtins +} // namespace builtins::web::streams + + #endif diff --git a/builtins/web/streams/transform-stream-default-controller.cpp b/builtins/web/streams/transform-stream-default-controller.cpp index 48c9d8a3..b3f58dd5 100644 --- a/builtins/web/streams/transform-stream-default-controller.cpp +++ b/builtins/web/streams/transform-stream-default-controller.cpp @@ -1,17 +1,12 @@ -// TODO: remove these once the warnings are fixed -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" -#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" #include "js/experimental/TypedData.h" // used in "js/Conversions.h" -#pragma clang diagnostic pop - #include "js/Stream.h" #include "transform-stream-default-controller.h" #include "transform-stream.h" - #include "stream-errors.h" +#include + /** * Implementation of the WHATWG TransformStream builtin. * @@ -20,9 +15,9 @@ */ // A JS class to use as the underlying sink for native writable streams, used // for TransformStream. -namespace builtins { -namespace web { -namespace streams { + + +namespace builtins::web::streams { JSObject *TransformStreamDefaultController::stream(JSObject *controller) { MOZ_ASSERT(is_instance(controller)); return &JS::GetReservedSlot(controller, Slots::Stream).toObject(); @@ -53,8 +48,8 @@ bool TransformStreamDefaultController::desiredSize_get(JSContext *cx, unsigned a // 1. Let readableController be [this].[stream].[readable].[controller]. JSObject *stream = TransformStreamDefaultController::stream(self); JSObject *readable = TransformStream::readable(stream); - double value; - bool has_value; + double value = NAN; + bool has_value = false; if (!JS::ReadableStreamGetDesiredSize(cx, readable, &has_value, &value)) { return false; } @@ -137,8 +132,9 @@ JSObject *TransformStreamDefaultController::create( TransformStreamDefaultController::TransformAlgorithmImplementation *transformAlgo, TransformStreamDefaultController::FlushAlgorithmImplementation *flushAlgo) { JS::RootedObject controller(cx, JS_NewObjectWithGivenProto(cx, &class_, proto_obj)); - if (!controller) + if (!controller) { return nullptr; + } // 1. Assert: stream [implements] `[TransformStream]`. MOZ_ASSERT(TransformStream::is_instance(stream)); @@ -395,8 +391,9 @@ JSObject *TransformStreamDefaultController::SetUpFromTransformer(JSContext *cx, // controller, transformAlgorithm, flushAlgorithm). JS::RootedObject controller(cx); controller = SetUp(cx, stream, transform_algorithm_transformer, flush_algorithm_transformer); - if (!controller) + if (!controller) { return nullptr; + } // Set the additional bits required to execute the transformer-based transform // and flush algorithms. @@ -466,6 +463,4 @@ void TransformStreamDefaultController::ClearAlgorithms(JSObject *controller) { JS::SetReservedSlot(controller, Slots::FlushAlgorithm, JS::PrivateValue(nullptr)); JS::SetReservedSlot(controller, Slots::FlushInput, JS::UndefinedValue()); } -} // namespace streams -} // namespace web -} // namespace builtins +} // namespace builtins::web::streams diff --git a/builtins/web/streams/transform-stream-default-controller.h b/builtins/web/streams/transform-stream-default-controller.h index ad544852..955468c5 100644 --- a/builtins/web/streams/transform-stream-default-controller.h +++ b/builtins/web/streams/transform-stream-default-controller.h @@ -3,9 +3,9 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace streams { + + +namespace builtins::web::streams { class TransformStreamDefaultController : public BuiltinNoConstructor { @@ -13,7 +13,7 @@ class TransformStreamDefaultController public: static constexpr const char *class_name = "TransformStreamDefaultController"; - enum Slots { + enum Slots : uint8_t { Stream, Transformer, TransformAlgorithm, @@ -25,9 +25,8 @@ class TransformStreamDefaultController Count }; - typedef JSObject *TransformAlgorithmImplementation(JSContext *cx, JS::HandleObject controller, - JS::HandleValue chunk); - typedef JSObject *FlushAlgorithmImplementation(JSContext *cx, JS::HandleObject controller); + using TransformAlgorithmImplementation = JSObject *(JSContext *, JS::HandleObject, JS::HandleValue); + using FlushAlgorithmImplementation = JSObject *(JSContext *, JS::HandleObject); static const JSFunctionSpec static_methods[]; static const JSPropertySpec static_properties[]; @@ -69,8 +68,8 @@ class TransformStreamDefaultController static void ClearAlgorithms(JSObject *controller); }; -} // namespace streams -} // namespace web -} // namespace builtins +} // namespace builtins::web::streams + + #endif diff --git a/builtins/web/streams/transform-stream.cpp b/builtins/web/streams/transform-stream.cpp index d9b48ad0..a42ea503 100644 --- a/builtins/web/streams/transform-stream.cpp +++ b/builtins/web/streams/transform-stream.cpp @@ -1,10 +1,3 @@ -// TODO: remove these once the warnings are fixed -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" -#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" -#include "js/experimental/TypedData.h" // used in "js/Conversions.h" -#pragma clang diagnostic pop - #include "builtin.h" #include "js/Conversions.h" #include "js/Stream.h" @@ -45,7 +38,7 @@ bool pipeTo(JSContext *cx, unsigned argc, JS::Value *vp) { JS::RootedObject target(cx, args[0].isObject() ? &args[0].toObject() : nullptr); if (target && NativeStreamSource::stream_has_native_source(cx, self) && JS::IsWritableStream(target) && TransformStream::is_ts_writable(cx, target)) { - if (auto ts = TransformStream::ts_from_writable(cx, target)) { + if (auto *ts = TransformStream::ts_from_writable(cx, target)) { bool streamHasTransformer = false; auto streamHasTransformerVal = JS::GetReservedSlot(ts, TransformStream::Slots::HasTransformer); @@ -65,7 +58,7 @@ bool pipeTo(JSContext *cx, unsigned argc, JS::Value *vp) { bool pipeThrough(JSContext *cx, JS::HandleObject source_readable, JS::HandleObject target_writable, JS::HandleValue options) { // 1. If ! IsReadableStreamLocked(this) is true, throw a TypeError exception. - bool locked; + bool locked = false; if (!JS::ReadableStreamIsLocked(cx, source_readable, &locked)) { return false; } @@ -107,11 +100,7 @@ bool pipeThrough(JSContext *cx, JS::HandleObject source_readable, JS::HandleObje // 5. Set promise.[[PromiseIsHandled]] to true. // JSAPI doesn't provide a straightforward way to do this, but we can just // register null-reactions in a way that achieves it. - if (!JS::AddPromiseReactionsIgnoringUnhandledRejection(cx, promise, nullptr, nullptr)) { - return false; - } - - return true; + return JS::AddPromiseReactionsIgnoringUnhandledRejection(cx, promise, nullptr, nullptr); } bool pipeThrough(JSContext *cx, unsigned argc, JS::Value *vp) { @@ -127,8 +116,10 @@ bool pipeThrough(JSContext *cx, unsigned argc, JS::Value *vp) { JS::RootedObject writable(cx); JS::RootedValue val(cx); - if (!JS_GetProperty(cx, transform, "readable", &val)) + if (!JS_GetProperty(cx, transform, "readable", &val)) { return false; + } + if (!val.isObject() || !JS::IsReadableStream(&val.toObject())) { return api::throw_error( cx, api::Errors::TypeError, "ReadableStream.pipeThrough", "transformStream parameter", @@ -137,8 +128,10 @@ bool pipeThrough(JSContext *cx, unsigned argc, JS::Value *vp) { readable = &val.toObject(); - if (!JS_GetProperty(cx, transform, "writable", &val)) + if (!JS_GetProperty(cx, transform, "writable", &val)) { return false; + } + if (!val.isObject() || !JS::IsWritableStream(&val.toObject())) { return api::throw_error( cx, api::Errors::TypeError, "ReadableStream.pipeThrough", "transformStream parameter", @@ -181,12 +174,7 @@ bool initialize_additions(JSContext *cx, JS::HandleObject global) { } overridden_pipeTo.setObject(*JS_GetFunctionObject(pipeTo_fun)); - - if (!JS_DefineFunction(cx, proto_obj, "pipeThrough", pipeThrough, 1, JSPROP_ENUMERATE)) { - return false; - } - - return true; + return JS_DefineFunction(cx, proto_obj, "pipeThrough", pipeThrough, 1, JSPROP_ENUMERATE) != nullptr; } } // namespace ReadableStream_additions @@ -262,9 +250,9 @@ bool ExtractStrategy(JSContext *cx, JS::HandleValue strategy, double default_hwm * All algorithm names and steps refer to spec algorithms defined at * https://streams.spec.whatwg.org/#ts-class */ -namespace builtins { -namespace web { -namespace streams { + + +namespace builtins::web::streams { /** * The native object owning the sink underlying the TransformStream's readable * end. @@ -382,7 +370,7 @@ void TransformStream::set_used_as_mixin(JSObject *self) { bool TransformStream::readable_get(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER_WITH_NAME(0, "get readable") - auto readable_val = readable(self); + auto *readable_val = readable(self); // TODO: determine why this isn't being set in some cases if (readable_val) { args.rval().setObject(*readable_val); @@ -392,7 +380,7 @@ bool TransformStream::readable_get(JSContext *cx, unsigned argc, JS::Value *vp) bool TransformStream::writable_get(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER_WITH_NAME(0, "get writable") - auto writable_val = writable(self); + auto *writable_val = writable(self); // TODO: determine why this isn't being set in some cases if (writable_val) { args.rval().setObject(*writable_val); @@ -452,7 +440,7 @@ bool TransformStream::constructor(JSContext *cx, unsigned argc, JS::Value *vp) { // 3. If transformerDict["readableType"] [exists], throw a `[RangeError]` // exception. - bool found; + bool found = false; if (!JS_HasProperty(cx, transformerDict, "readableType", &found)) { return false; } @@ -478,7 +466,7 @@ bool TransformStream::constructor(JSContext *cx, unsigned argc, JS::Value *vp) { // 0). // 6. Let readableSizeAlgorithm be ! // [ExtractSizeAlgorithm](readableStrategy). - double readableHighWaterMark; + double readableHighWaterMark = 0.0; JS::RootedFunction readableSizeAlgorithm(cx); if (!ExtractStrategy(cx, args.get(2), 0, &readableHighWaterMark, &readableSizeAlgorithm)) { return false; @@ -488,7 +476,7 @@ bool TransformStream::constructor(JSContext *cx, unsigned argc, JS::Value *vp) { // 1). // 8. Let writableSizeAlgorithm be ! // [ExtractSizeAlgorithm](writableStrategy). - double writableHighWaterMark; + double writableHighWaterMark = 1.0; JS::RootedFunction writableSizeAlgorithm(cx); if (!ExtractStrategy(cx, args.get(1), 1, &writableHighWaterMark, &writableSizeAlgorithm)) { return false; @@ -500,8 +488,9 @@ bool TransformStream::constructor(JSContext *cx, unsigned argc, JS::Value *vp) { create(cx, transformStreamInstance, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm, transformer, startFunction, transformFunction, flushFunction)); - if (!self) + if (!self) { return false; + } JS::SetReservedSlot(self, TransformStream::Slots::HasTransformer, JS::BooleanValue(JS::ToBoolean(transformer))); @@ -512,8 +501,9 @@ bool TransformStream::constructor(JSContext *cx, unsigned argc, JS::Value *vp) { bool TransformStream::init_class(JSContext *cx, JS::HandleObject global) { bool ok = init_class_impl(cx, global); - if (!ok) + if (!ok) { return false; + } return ReadableStream_additions::initialize_additions(cx, global); } @@ -638,8 +628,9 @@ bool TransformStream::DefaultSinkWriteAlgorithm(JSContext *cx, JS::CallArgs args // fulfillment steps: JS::RootedObject then_handler(cx); then_handler = create_internal_method(cx, stream, chunk); - if (!then_handler) + if (!then_handler) { return false; + } JS::RootedObject result(cx); result = JS::CallOriginalPromiseThen(cx, changePromise, then_handler, nullptr); @@ -694,7 +685,7 @@ bool TransformStream::default_sink_close_algo_then_handler(JSContext *cx, JS::Ha JS::CallArgs args) { // 5.1.1. If readable.[state] is "`errored`", throw readable.[storedError]. JS::RootedObject readable(cx, &extra.toObject()); - bool is_errored; + bool is_errored = false; if (!JS::ReadableStreamIsErrored(cx, readable, &is_errored)) { return false; } @@ -718,9 +709,9 @@ bool TransformStream::default_sink_close_algo_then_handler(JSContext *cx, JS::Ha // throwing an exception, and the `else` branch will never be taken. if (JS::CheckReadableStreamControllerCanCloseOrEnqueue(cx, readableController, "close")) { return JS::ReadableStreamClose(cx, readable); - } else { - JS_ClearPendingException(cx); } + + JS_ClearPendingException(cx); return true; } @@ -772,15 +763,17 @@ bool TransformStream::DefaultSinkCloseAlgorithm(JSContext *cx, JS::CallArgs args JS::RootedObject then_handler(cx); JS::RootedValue extra(cx, JS::ObjectValue(*readable)); then_handler = create_internal_method(cx, stream, extra); - if (!then_handler) + if (!then_handler) { return false; + } // 5.2. If flushPromise was rejected with reason r, then: // Sub-steps in handler above. JS::RootedObject catch_handler(cx); catch_handler = create_internal_method(cx, stream, extra); - if (!catch_handler) + if (!catch_handler) { return false; + } JS::RootedObject result(cx); result = JS::CallOriginalPromiseThen(cx, flushPromise, then_handler, catch_handler); @@ -843,14 +836,16 @@ bool TransformStream::Initialize(JSContext *cx, JS::HandleObject stream, JS::RootedObject sink( cx, NativeStreamSink::create(cx, stream, startPromiseVal, DefaultSinkWriteAlgorithm, DefaultSinkCloseAlgorithm, DefaultSinkAbortAlgorithm)); - if (!sink) + if (!sink) { return false; + } JS::RootedObject writable(cx); writable = JS::NewWritableDefaultStreamObject(cx, sink, writableSizeAlgorithm, writableHighWaterMark); - if (!writable) + if (!writable) { return false; + } JS::SetReservedSlot(stream, TransformStream::Slots::Writable, JS::ObjectValue(*writable)); @@ -867,13 +862,15 @@ bool TransformStream::Initialize(JSContext *cx, JS::HandleObject stream, JS::RootedObject source( cx, NativeStreamSource::create(cx, stream, startPromiseVal, pullAlgorithm, cancelAlgorithm, readableSizeAlgorithm, readableHighWaterMark)); - if (!source) + if (!source) { return false; + } JS::RootedObject readable(cx); readable = NativeStreamSource::stream(source); - if (!readable) + if (!readable) { return false; + } JS::SetReservedSlot(stream, TransformStream::Slots::Readable, JS::ObjectValue(*readable)); @@ -944,8 +941,9 @@ TransformStream::create(JSContext *cx, JS::HandleObject self, double writableHig // Step 9. JS::RootedObject startPromise(cx, JS::NewPromiseObject(cx, nullptr)); - if (!startPromise) + if (!startPromise) { return nullptr; + } // Step 10. if (!Initialize(cx, self, startPromise, writableHighWaterMark, writableSizeAlgorithm, @@ -992,8 +990,9 @@ JSObject *TransformStream::create(JSContext *cx, double writableHighWaterMark, JS::HandleObject transformFunction, JS::HandleObject flushFunction) { JS::RootedObject self(cx, JS_NewObjectWithGivenProto(cx, &class_, proto_obj)); - if (!self) + if (!self) { return nullptr; + } return TransformStream::create(cx, self, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm, transformer, @@ -1021,6 +1020,4 @@ JSObject *TransformStream::create_rs_proxy(JSContext *cx, JS::HandleObject input return readable(transform_stream); } -} // namespace streams -} // namespace web -} // namespace builtins +} // namespace builtins::web::streams diff --git a/builtins/web/streams/transform-stream.h b/builtins/web/streams/transform-stream.h index 982cbcb9..a5239dce 100644 --- a/builtins/web/streams/transform-stream.h +++ b/builtins/web/streams/transform-stream.h @@ -4,9 +4,9 @@ #include "builtin.h" // #include "js-compute-builtins.h" -namespace builtins { -namespace web { -namespace streams { + + +namespace builtins::web::streams { class TransformStream : public BuiltinImpl { private: @@ -14,7 +14,7 @@ class TransformStream : public BuiltinImpl { static constexpr const char *class_name = "TransformStream"; static const int ctor_length = 0; - enum Slots { + enum Slots : uint8_t { Controller, Readable, Writable, @@ -93,8 +93,8 @@ class TransformStream : public BuiltinImpl { static JSObject *create_rs_proxy(JSContext *cx, JS::HandleObject input_readable); }; -} // namespace streams -} // namespace web -} // namespace builtins +} // namespace builtins::web::streams + + #endif diff --git a/builtins/web/structured-clone.cpp b/builtins/web/structured-clone.cpp index e19a54a0..e2439648 100644 --- a/builtins/web/structured-clone.cpp +++ b/builtins/web/structured-clone.cpp @@ -4,9 +4,9 @@ #include "dom-exception.h" #include "mozilla/Assertions.h" -namespace builtins { -namespace web { -namespace structured_clone { + + +namespace builtins::web::structured_clone { // Magic number used in structured cloning as a tag to identify a // URLSearchParam. @@ -81,7 +81,7 @@ bool WriteStructuredClone(JSContext *cx, JSStructuredCloneWriter *w, JS::HandleO return false; } } else if (blob::Blob::is_instance(obj)) { - auto data = blob::Blob::blob(obj); + auto *data = blob::Blob::blob(obj); if (!JS_WriteUint32Pair(w, SCTAG_DOM_BLOB, data->length()) || !JS_WriteBytes(w, (void *)data->begin(), data->length())) { return false; @@ -93,7 +93,7 @@ bool WriteStructuredClone(JSContext *cx, JSStructuredCloneWriter *w, JS::HandleO return true; } -JSStructuredCloneCallbacks sc_callbacks = {ReadStructuredClone, WriteStructuredClone}; +JSStructuredCloneCallbacks sc_callbacks = {.read=ReadStructuredClone, .write=WriteStructuredClone}; /** * The `structuredClone` global function @@ -130,6 +130,6 @@ bool install(api::Engine *engine) { return JS_DefineFunctions(engine->cx(), engine->global(), methods); } -} // namespace structured_clone -} // namespace web -} // namespace builtins +} // namespace builtins::web::structured_clone + + diff --git a/builtins/web/structured-clone.h b/builtins/web/structured-clone.h index 779b30b7..ceae1ab2 100644 --- a/builtins/web/structured-clone.h +++ b/builtins/web/structured-clone.h @@ -5,14 +5,14 @@ #include "js/StructuredClone.h" #include "url.h" -namespace builtins { -namespace web { -namespace structured_clone { + + +namespace builtins::web::structured_clone { bool install(api::Engine *engine); -} // namespace structured_clone -} // namespace web -} // namespace builtins +} // namespace builtins::web::structured_clone + + #endif diff --git a/builtins/web/text-codec/text-codec.cpp b/builtins/web/text-codec/text-codec.cpp index 8922c21a..2798bb0b 100644 --- a/builtins/web/text-codec/text-codec.cpp +++ b/builtins/web/text-codec/text-codec.cpp @@ -2,18 +2,18 @@ #include "text-decoder.h" #include "text-encoder.h" -namespace builtins { -namespace web { -namespace text_codec { +namespace builtins::web::text_codec { bool install(api::Engine *engine) { - if (!TextEncoder::init_class(engine->cx(), engine->global())) + if (!TextEncoder::init_class(engine->cx(), engine->global())) { return false; - if (!TextDecoder::init_class(engine->cx(), engine->global())) + } + if (!TextDecoder::init_class(engine->cx(), engine->global())) { return false; + } return true; } -} // namespace text_codec -} // namespace web -} // namespace builtins +} // namespace builtins::web::text_codec + + diff --git a/builtins/web/text-codec/text-codec.h b/builtins/web/text-codec/text-codec.h index 94b6ebc5..53788e37 100644 --- a/builtins/web/text-codec/text-codec.h +++ b/builtins/web/text-codec/text-codec.h @@ -3,12 +3,12 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace text_codec { + + +namespace builtins::web::text_codec { bool install(api::Engine *engine); } -} // namespace web -} // namespace builtins + + #endif diff --git a/builtins/web/text-codec/text-decoder.cpp b/builtins/web/text-codec/text-decoder.cpp index 4bea9f22..a5bd84e6 100644 --- a/builtins/web/text-codec/text-decoder.cpp +++ b/builtins/web/text-codec/text-decoder.cpp @@ -4,9 +4,9 @@ #include "text-codec-errors.h" -namespace builtins { -namespace web { -namespace text_codec { + + +namespace builtins::web::text_codec { bool TextDecoder::decode(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER(0); @@ -57,11 +57,11 @@ bool TextDecoder::decode(JSContext *cx, unsigned argc, JS::Value *vp) { JS::GetReservedSlot(self, static_cast(TextDecoder::Slots::Fatal)).toBoolean(); auto ignoreBOM = JS::GetReservedSlot(self, static_cast(TextDecoder::Slots::IgnoreBOM)).toBoolean(); - auto decoder = reinterpret_cast( + auto *decoder = reinterpret_cast( JS::GetReservedSlot(self, static_cast(TextDecoder::Slots::Decoder)).toPrivate()); MOZ_ASSERT(decoder); - uint32_t result; + uint32_t result = 0; size_t srcLen = src->size(); size_t destLen = jsencoding::decoder_max_utf16_buffer_length(decoder, srcLen); std::unique_ptr dest(new uint16_t[destLen + 1]); @@ -76,13 +76,13 @@ bool TextDecoder::decode(JSContext *cx, unsigned argc, JS::Value *vp) { return api::throw_error(cx, TextCodecErrors::DecodingFailed); } } else { - bool hadReplacements; + bool hadReplacements = false; result = jsencoding::decoder_decode_to_utf16(decoder, src_ptr, &srcLen, dest.get(), &destLen, !stream, &hadReplacements); } MOZ_ASSERT(result == 0); - auto encoding = reinterpret_cast( + auto *encoding = reinterpret_cast( JS::GetReservedSlot(self, static_cast(TextDecoder::Slots::Encoding)).toPrivate()); MOZ_ASSERT(encoding); // If the internal streaming flag of the decoder object is not set, @@ -112,7 +112,7 @@ bool TextDecoder::encoding_get(JSContext *cx, unsigned argc, JS::Value *vp) { return api::throw_error(cx, api::Errors::WrongReceiver, "encoding get", "TextDecoder"); } - auto encoding = reinterpret_cast( + auto *encoding = reinterpret_cast( JS::GetReservedSlot(self, static_cast(TextDecoder::Slots::Encoding)).toPrivate()); MOZ_ASSERT(encoding); @@ -197,17 +197,18 @@ bool TextDecoder::constructor(JSContext *cx, unsigned argc, JS::Value *vp) { // 1. Remove any leading and trailing ASCII whitespace from label. // 2. If label is an ASCII case-insensitive match for any of the labels listed in the table // below, then return the corresponding encoding; otherwise return failure. JS-Compute-Runtime: - jsencoding::Encoding *encoding; + const jsencoding::Encoding *encoding = nullptr; if (label_value.isUndefined()) { - encoding = const_cast(jsencoding::encoding_for_label_no_replacement( - reinterpret_cast(const_cast("UTF-8")), 5)); + const char *utf8_label = "UTF-8"; + encoding = jsencoding::encoding_for_label_no_replacement( + reinterpret_cast(utf8_label), 5); } else { auto label_chars = core::encode(cx, label_value); if (!label_chars) { return false; } - encoding = const_cast(jsencoding::encoding_for_label_no_replacement( - reinterpret_cast(label_chars.begin()), label_chars.len)); + encoding = jsencoding::encoding_for_label_no_replacement( + reinterpret_cast(label_chars.begin()), label_chars.len); } if (!encoding) { return api::throw_error(cx, TextCodecErrors::InvalidEncoding); @@ -234,16 +235,20 @@ bool TextDecoder::constructor(JSContext *cx, unsigned argc, JS::Value *vp) { } } JS::RootedObject self(cx, JS_NewObjectForConstructor(cx, &class_, args)); - jsencoding::Decoder *decoder; + jsencoding::Decoder *decoder = nullptr; if (ignoreBOM) { decoder = jsencoding::encoding_new_decoder_without_bom_handling(encoding); } else { decoder = jsencoding::encoding_new_decoder_with_bom_removal(encoding); } + + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast): drop const to store encoding in the slot + auto *encoding_ptr = const_cast(encoding); + JS::SetReservedSlot(self, static_cast(TextDecoder::Slots::Decoder), JS::PrivateValue(decoder)); JS::SetReservedSlot(self, static_cast(TextDecoder::Slots::Encoding), - JS::PrivateValue(encoding)); + JS::PrivateValue(encoding_ptr)); JS::SetReservedSlot(self, static_cast(TextDecoder::Slots::Fatal), JS::BooleanValue(fatal)); JS::SetReservedSlot(self, static_cast(TextDecoder::Slots::IgnoreBOM), @@ -258,7 +263,7 @@ bool TextDecoder::init_class(JSContext *cx, JS::HandleObject global) { } void TextDecoder::finalize(JS::GCContext *gcx, JSObject *self) { - auto decoder = reinterpret_cast( + auto *decoder = reinterpret_cast( JS::GetReservedSlot(self, static_cast(TextDecoder::Slots::Decoder)).toPrivate()); if (decoder) { @@ -266,6 +271,6 @@ void TextDecoder::finalize(JS::GCContext *gcx, JSObject *self) { } } -} // namespace text_codec -} // namespace web -} // namespace builtins +} // namespace builtins::web::text_codec + + diff --git a/builtins/web/text-codec/text-decoder.h b/builtins/web/text-codec/text-decoder.h index d3be6788..4de8feba 100644 --- a/builtins/web/text-codec/text-decoder.h +++ b/builtins/web/text-codec/text-decoder.h @@ -3,9 +3,9 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace text_codec { + + +namespace builtins::web::text_codec { class TextDecoder final : public BuiltinImpl { static bool decode(JSContext *cx, unsigned argc, JS::Value *vp); @@ -16,7 +16,7 @@ class TextDecoder final : public BuiltinImpl #include #include "js/ArrayBuffer.h" -#include "mozilla/Span.h" -// TODO: remove these once the warnings are fixed -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" #include "js/experimental/TypedData.h" -#pragma clang diagnostic pop +#include "mozilla/Span.h" -namespace builtins { -namespace web { -namespace text_codec { +namespace builtins::web::text_codec { bool TextEncoder::encode(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER(0); @@ -62,7 +55,7 @@ bool TextEncoder::encodeInto(JSContext *cx, unsigned argc, JS::Value *vp) { return api::throw_error(cx, api::Errors::WrongReceiver, "encodeInto", "TextEncoder"); } - auto source = JS::ToString(cx, args.get(0)); + auto *source = JS::ToString(cx, args.get(0)); if (!source) { return false; } @@ -74,8 +67,8 @@ bool TextEncoder::encodeInto(JSContext *cx, unsigned argc, JS::Value *vp) { } JS::RootedObject destination(cx, &destination_value.toObject()); - uint8_t *data; - bool is_shared; + uint8_t *data = nullptr; + bool is_shared = false; size_t len = 0; // JS_GetObjectAsUint8Array returns nullptr without throwing if the object is not // a Uint8Array, so we don't need to do explicit checks before calling it. @@ -88,8 +81,8 @@ bool TextEncoder::encodeInto(JSContext *cx, unsigned argc, JS::Value *vp) { if (!maybe) { return false; } - size_t read; - size_t written; + size_t read = 0; + size_t written = 0; std::tie(read, written) = *maybe; MOZ_ASSERT(written <= len); @@ -164,6 +157,6 @@ bool TextEncoder::init_class(JSContext *cx, JS::HandleObject global) { return init_class_impl(cx, global); } -} // namespace text_codec -} // namespace web -} // namespace builtins +} // namespace builtins::web::text_codec + + diff --git a/builtins/web/text-codec/text-encoder.h b/builtins/web/text-codec/text-encoder.h index 85134f90..a206b6f3 100644 --- a/builtins/web/text-codec/text-encoder.h +++ b/builtins/web/text-codec/text-encoder.h @@ -3,9 +3,9 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace text_codec { + + +namespace builtins::web::text_codec { class TextEncoder final : public BuiltinImpl { static bool encode(JSContext *cx, unsigned argc, JS::Value *vp); @@ -15,7 +15,7 @@ class TextEncoder final : public BuiltinImpl { public: static constexpr const char *class_name = "TextEncoder"; - enum class Slots { Count }; + enum class Slots : uint8_t { Count }; static const JSFunctionSpec static_methods[]; static const JSPropertySpec static_properties[]; static const JSFunctionSpec methods[]; @@ -27,8 +27,8 @@ class TextEncoder final : public BuiltinImpl { static bool constructor(JSContext *cx, unsigned argc, JS::Value *vp); }; -} // namespace text_codec -} // namespace web -} // namespace builtins +} // namespace builtins::web::text_codec + + #endif diff --git a/builtins/web/timers.cpp b/builtins/web/timers.cpp index 94f740ca..d4e9a8cb 100644 --- a/builtins/web/timers.cpp +++ b/builtins/web/timers.cpp @@ -2,6 +2,7 @@ #include "event_loop.h" +#include #include #include #include @@ -16,7 +17,7 @@ namespace { class TimersMap { public: - std::map timers_ = {}; + std::map timers_; int32_t next_timer_id = 1; void trace(JSTracer *trc) { for (auto &[id, timer] : timers_) { @@ -44,16 +45,16 @@ class TimerTask final : public api::AsyncTask { public: explicit TimerTask(const int64_t delay_ns, const bool repeat, HandleObject callback, JS::HandleValueVector args) - : delay_(delay_ns), repeat_(repeat), callback_(callback) { - deadline_ = host_api::MonotonicClock::now() + delay_ns; + : timer_id_(TIMERS_MAP->next_timer_id++), delay_(delay_ns), deadline_(host_api::MonotonicClock::now() + delay_ns), repeat_(repeat), callback_(callback) { + arguments_.reserve(args.length()); - for (auto &arg : args) { + for (const auto &arg : args) { arguments_.emplace_back(arg); } handle_ = host_api::MonotonicClock::subscribe(deadline_, true); - timer_id_ = TIMERS_MAP->next_timer_id++; + TIMERS_MAP->timers_.emplace(timer_id_, this); } @@ -131,13 +132,11 @@ namespace builtins::web::timers { template bool set_timeout_or_interval(JSContext *cx, HandleObject handler, JS::HandleValueVector handle_args, int32_t delay_ms, int32_t *timer_id) { - if (delay_ms < 0) { - delay_ms = 0; - } + delay_ms = std::max(delay_ms, 0); // Convert delay from milliseconds to nanoseconds, as that's what Timers operate on. const int64_t delay = static_cast(delay_ms) * 1000000; - const auto timer = new TimerTask(delay, repeat, handler, handle_args); + auto *const timer = js_new(delay, repeat, handler, handle_args); ENGINE->queue_async_task(timer); *timer_id = timer->timer_id(); diff --git a/builtins/web/url.cpp b/builtins/web/url.cpp index b7276e18..83dd01b2 100644 --- a/builtins/web/url.cpp +++ b/builtins/web/url.cpp @@ -13,9 +13,9 @@ #include "js/GCHashTable.h" #include "js/TypeDecls.h" -namespace builtins { -namespace web { -namespace url { + + +namespace builtins::web::url { using blob::Blob; using file::File; @@ -24,13 +24,14 @@ using worker_location::WorkerLocation; bool URLSearchParamsIterator::next(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER(0) JS::RootedObject params_obj(cx, &JS::GetReservedSlot(self, Slots::Params).toObject()); - const auto params = URLSearchParams::get_params(params_obj); + auto *const params = URLSearchParams::get_params(params_obj); size_t index = JS::GetReservedSlot(self, Slots::Index).toInt32(); uint8_t type = JS::GetReservedSlot(self, Slots::Type).toInt32(); JS::RootedObject result(cx, JS_NewPlainObject(cx)); - if (!result) + if (!result) { return false; + } jsurl::JSSearchParam param{}; jsurl::params_at(params, index, ¶m); @@ -51,16 +52,18 @@ bool URLSearchParamsIterator::next(JSContext *cx, unsigned argc, JS::Value *vp) if (type != ITER_TYPE_VALUES) { auto chars = JS::UTF8Chars((char *)param.name.data, param.name.len); JS::RootedString str(cx, JS_NewStringCopyUTF8N(cx, chars)); - if (!str) + if (!str) { return false; + } key_val = JS::StringValue(str); } if (type != ITER_TYPE_KEYS) { auto chars = JS::UTF8Chars((char *)param.value.data, param.value.len); JS::RootedString str(cx, JS_NewStringCopyUTF8N(cx, chars)); - if (!str) + if (!str) { return false; + } val_val = JS::StringValue(str); } @@ -69,8 +72,9 @@ bool URLSearchParamsIterator::next(JSContext *cx, unsigned argc, JS::Value *vp) switch (type) { case ITER_TYPE_ENTRIES: { JS::RootedObject pair(cx, JS::NewArrayObject(cx, 2)); - if (!pair) + if (!pair) { return false; + } JS_DefineElement(cx, pair, 0, key_val, JSPROP_ENUMERATE); JS_DefineElement(cx, pair, 1, val_val, JSPROP_ENUMERATE); result_val = JS::ObjectValue(*pair); @@ -114,11 +118,13 @@ const JSPropertySpec URLSearchParamsIterator::properties[] = { bool URLSearchParamsIterator::init_class(JSContext *cx, JS::HandleObject global) { JS::RootedObject iterator_proto(cx, JS::GetRealmIteratorPrototype(cx)); - if (!iterator_proto) + if (!iterator_proto) { return false; + } - if (!init_class_impl(cx, global, iterator_proto)) + if (!init_class_impl(cx, global, iterator_proto)) { return false; + } // Delete both the `URLSearchParamsIterator` global property and the // `constructor` property on `URLSearchParamsIterator.prototype`. The latter @@ -131,8 +137,9 @@ JSObject *URLSearchParamsIterator::create(JSContext *cx, JS::HandleObject params MOZ_RELEASE_ASSERT(type <= ITER_TYPE_VALUES); JS::RootedObject self(cx, JS_NewObjectWithGivenProto(cx, &class_, proto_obj)); - if (!self) + if (!self) { return nullptr; + } JS::SetReservedSlot(self, Slots::Params, JS::ObjectValue(*params)); JS::SetReservedSlot(self, Slots::Type, JS::Int32Value(type)); @@ -181,11 +188,12 @@ jsurl::SpecString append_impl_validate(JSContext *cx, JS::HandleValue key, const } bool append_impl(JSContext *cx, JS::HandleObject self, jsurl::SpecString key, JS::HandleValue val, const char *_) { - const auto params = URLSearchParams::get_params(self); + auto *const params = URLSearchParams::get_params(self); auto value = core::encode_spec_string(cx, val); - if (!value.data) + if (!value.data) { return false; + } jsurl::params_append(params, key, value); return true; @@ -199,8 +207,9 @@ jsurl::SpecSlice URLSearchParams::serialize(JSContext *cx, JS::HandleObject self bool URLSearchParams::append(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER(2) auto value = append_impl_validate(cx, args[0], "append"); - if (!append_impl(cx, self, value, args[1], "append")) + if (!append_impl(cx, self, value, args[1], "append")) { return false; + } args.rval().setUndefined(); return true; @@ -213,12 +222,15 @@ bool URLSearchParams::delete_(JSContext *cx, unsigned argc, JS::Value *vp) { static_cast(JS::GetReservedSlot(self, Slots::Params).toPrivate()); auto name = core::encode_spec_string(cx, args.get(0)); - if (!name.data) + if (!name.data) { return false; + } if (args.hasDefined(1)) { auto value = core::encode_spec_string(cx, args.get(1)); - if (!value.data) return false; + if (!value.data) { + return false; + } jsurl::params_delete_kv(params, &name, &value); } else { jsurl::params_delete(params, &name); @@ -234,12 +246,15 @@ bool URLSearchParams::has(JSContext *cx, unsigned argc, JS::Value *vp) { static_cast(JS::GetReservedSlot(self, Slots::Params).toPrivate()); auto name = core::encode_spec_string(cx, args.get(0)); - if (!name.data) + if (!name.data) { return false; + } if (args.hasDefined(1)) { auto value = core::encode_spec_string(cx, args.get(1)); - if (!value.data) return false; + if (!value.data) { + return false; + } args.rval().setBoolean(jsurl::params_has_kv(params, &name, &value)); } else { args.rval().setBoolean(jsurl::params_has(params, &name)); @@ -250,12 +265,13 @@ bool URLSearchParams::has(JSContext *cx, unsigned argc, JS::Value *vp) { bool URLSearchParams::get(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER(1); - auto *params = static_cast( + const auto *params = static_cast( JS::GetReservedSlot(self, Slots::Params).toPrivate()); auto name = core::encode_spec_string(cx, args.get(0)); - if (!name.data) + if (!name.data) { return false; + } const jsurl::SpecSlice slice = jsurl::params_get(params, &name); if (!slice.data) { @@ -264,8 +280,9 @@ bool URLSearchParams::get(JSContext *cx, unsigned argc, JS::Value *vp) { } JS::RootedString str(cx, JS_NewStringCopyUTF8N(cx, JS::UTF8Chars((char *)slice.data, slice.len))); - if (!str) + if (!str) { return false; + } args.rval().setString(str); return true; } @@ -273,30 +290,34 @@ bool URLSearchParams::get(JSContext *cx, unsigned argc, JS::Value *vp) { bool URLSearchParams::getAll(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER(1); - auto *params = static_cast( + const auto *params = static_cast( JS::GetReservedSlot(self, Slots::Params).toPrivate()); auto name = core::encode_spec_string(cx, args.get(0)); - if (!name.data) + if (!name.data) { return false; + } const jsurl::CVec values = jsurl::params_get_all(params, &name); JS::RootedObject result(cx, JS::NewArrayObject(cx, values.len)); - if (!result) + if (!result) { return false; + } JS::RootedString str(cx); JS::RootedValue str_val(cx); for (size_t i = 0; i < values.len; i++) { const jsurl::SpecSlice value = values.ptr[i]; str = JS_NewStringCopyUTF8N(cx, JS::UTF8Chars((char *)value.data, value.len)); - if (!str) + if (!str) { return false; + } str_val.setString(str); - if (!JS_SetElement(cx, result, i, str_val)) + if (!JS_SetElement(cx, result, i, str_val)) { return false; + } } args.rval().setObject(*result); @@ -310,12 +331,14 @@ bool URLSearchParams::set(JSContext *cx, unsigned argc, JS::Value *vp) { static_cast(JS::GetReservedSlot(self, Slots::Params).toPrivate()); auto name = core::encode_spec_string(cx, args[0]); - if (!name.data) + if (!name.data) { return false; + } auto value = core::encode_spec_string(cx, args[1]); - if (!value.data) + if (!value.data) { return false; + } jsurl::params_set(params, name, value); return true; @@ -339,8 +362,9 @@ bool URLSearchParams::toString(JSContext *cx, unsigned argc, JS::Value *vp) { JS::RootedString str( cx, JS_NewStringCopyUTF8N( cx, JS::UTF8Chars(reinterpret_cast(slice.data), slice.len))); - if (!str) + if (!str) { return false; + } args.rval().setString(str); return true; @@ -353,20 +377,23 @@ bool URLSearchParams::constructor(JSContext *cx, unsigned argc, JS::Value *vp) { JS::RootedObject urlSearchParamsInstance(cx, JS_NewObjectForConstructor(cx, &class_, args)); JS::RootedObject self(cx, create(cx, urlSearchParamsInstance, args.get(0))); - if (!self) + if (!self) { return false; + } args.rval().setObject(*self); return true; } bool URLSearchParams::init_class(JSContext *cx, JS::HandleObject global) { - if (!init_class_impl(cx, global)) + if (!init_class_impl(cx, global)) { return false; + } JS::RootedValue entries(cx); - if (!JS_GetProperty(cx, proto_obj, "entries", &entries)) + if (!JS_GetProperty(cx, proto_obj, "entries", &entries)) { return false; + } JS::SymbolCode code = JS::SymbolCode::iterator; JS::RootedId iteratorId(cx, JS::GetWellKnownSymbolKey(cx, code)); @@ -375,7 +402,7 @@ bool URLSearchParams::init_class(JSContext *cx, JS::HandleObject global) { JSObject *URLSearchParams::create(JSContext *cx, JS::HandleObject self, JS::HandleValue params_val) { - auto params = jsurl::new_params(); + auto *params = jsurl::new_params(); JS::SetReservedSlot(self, Slots::Params, JS::PrivateValue(params)); bool consumed = false; @@ -387,8 +414,9 @@ JSObject *URLSearchParams::create(JSContext *cx, JS::HandleObject self, if (!consumed) { auto init = core::encode_spec_string(cx, params_val); - if (!init.data) + if (!init.data) { return nullptr; + } jsurl::params_init(params, &init); } @@ -399,8 +427,9 @@ JSObject *URLSearchParams::create(JSContext *cx, JS::HandleObject self, JSObject *URLSearchParams::create(JSContext *cx, JS::HandleObject self, jsurl::JSUrl *url) { jsurl::JSUrlSearchParams *params = jsurl::url_search_params(url); - if (!params) + if (!params) { return nullptr; + } JS::SetReservedSlot(self, Slots::Params, JS::PrivateValue(params)); JS::SetReservedSlot(self, Slots::Url, JS::PrivateValue(url)); @@ -499,7 +528,7 @@ const JSPropertySpec URL::properties[] = { struct UrlKey { std::string key_; - UrlKey() {} + UrlKey() = default; UrlKey(std::string key) : key_(std::move(key)) {} void trace(JSTracer *trc) {} @@ -573,7 +602,7 @@ bool URL::createObjectURL(JSContext *cx, unsigned argc, JS::Value *vp) { return false; } - auto uuid = maybe_uuid.value(); + const auto& uuid = maybe_uuid.value(); result.append(uuid); RootedString url(cx, JS_NewStringCopyN(cx, result.data(), result.size())); @@ -590,6 +619,9 @@ bool URL::createObjectURL(JSContext *cx, unsigned argc, JS::Value *vp) { } bool URL::revokeObjectURL(JSContext *cx, unsigned argc, JS::Value *vp) { + // Suppress false positive in Mozilla's HashTable implementation + // about null dereference, the remove method will check if the entry exists. + // NOLINTBEGIN CallArgs args = JS::CallArgsFromVp(argc, vp); if (!args.requireAtLeast(cx, "createObjectURL", 1)) { return false; @@ -602,8 +634,8 @@ bool URL::revokeObjectURL(JSContext *cx, unsigned argc, JS::Value *vp) { return false; } - // 2. If urlRecord’s scheme is not "blob", return. - // 3. Let entry be urlRecord’s blob URL entry. + // 2. If urlRecord’s scheme is not "blob", return. + // 3. Let entry be urlRecord’s blob URL entry. std::string url_record(chars.ptr.get()); if (!url_record.starts_with("blob:")) { return true; @@ -613,7 +645,9 @@ bool URL::revokeObjectURL(JSContext *cx, unsigned argc, JS::Value *vp) { // 5. Let isAuthorized be the result of checking for same-partition blob URL usage with entry and the current settings object. // 6. If isAuthorized is false, then return. // 7. Remove an entry from the Blob URL Store for url. - URL_STORE.get().remove(chars.ptr.get()); + + URL_STORE.get().remove(url_record); + // NOLINTEND return true; } @@ -632,6 +666,11 @@ const jsurl::JSUrl *URL::url(JSObject *self) { return static_cast(JS::GetReservedSlot(self, Url).toPrivate()); } +jsurl::JSUrl *URL::url_mut(JSObject *self) { + MOZ_ASSERT(is_instance(self)); + return static_cast(JS::GetReservedSlot(self, Url).toPrivate()); +} + jsurl::SpecString URL::origin(JSContext *cx, JS::HandleObject self) { return jsurl::origin(url(self)); } @@ -639,8 +678,9 @@ jsurl::SpecString URL::origin(JSContext *cx, JS::HandleObject self) { bool URL::origin(JSContext *cx, JS::HandleObject self, JS::MutableHandleValue rval) { jsurl::SpecString slice = origin(cx, self); JS::RootedString str(cx, JS_NewStringCopyUTF8N(cx, JS::UTF8Chars((char *)slice.data, slice.len))); - if (!str) + if (!str) { return false; + } rval.setString(str); return true; } @@ -657,15 +697,14 @@ bool URL::searchParams_get(JSContext *cx, unsigned argc, JS::Value *vp) { if (params_val.isNullOrUndefined()) { JS::RootedObject url_search_params_instance( cx, JS_NewObjectWithGivenProto(cx, &URLSearchParams::class_, URLSearchParams::proto_obj)); - if (!url_search_params_instance) + if (!url_search_params_instance) { return false; + } - // The const-cast here is okay because we while normally callers of URL::url mustn't mutate - // the returned object, URLSearchParams is intended to. - params = URLSearchParams::create(cx, url_search_params_instance, - const_cast(url(self))); - if (!params) + params = URLSearchParams::create(cx, url_search_params_instance, url_mut(self)); + if (!params) { return false; + } JS::SetReservedSlot(self, Slots::Params, JS::ObjectValue(*params)); } else { params = ¶ms_val.toObject(); @@ -689,11 +728,13 @@ bool URL::constructor(JSContext *cx, unsigned argc, JS::Value *vp) { CTOR_HEADER("URL", 1); JS::RootedObject urlInstance(cx, JS_NewObjectForConstructor(cx, &class_, args)); - if (!urlInstance) + if (!urlInstance) { return false; + } JS::RootedObject self(cx, create(cx, urlInstance, args.get(0), args.get(1))); - if (!self) + if (!self) { return false; + } args.rval().setObject(*self); return true; @@ -703,7 +744,7 @@ DEF_ERR(InvalidURLError, JSEXN_TYPEERR, "URL constructor: {0} is not a valid URL JSObject *URL::create(JSContext *cx, JS::HandleObject self, jsurl::SpecString url_str, const jsurl::JSUrl *base) { - jsurl::JSUrl *url; + jsurl::JSUrl *url = nullptr; if (base) { url = jsurl::new_jsurl_with_base(&url_str, base); } else { @@ -723,8 +764,9 @@ JSObject *URL::create(JSContext *cx, JS::HandleObject self, jsurl::SpecString ur JSObject *URL::create(JSContext *cx, JS::HandleObject self, JS::HandleValue url_val, const jsurl::JSUrl *base) { auto str = core::encode_spec_string(cx, url_val); - if (!str.data) + if (!str.data) { return nullptr; + } return create(cx, self, str, base); } @@ -740,7 +782,7 @@ JSObject *URL::create(JSContext *cx, JS::HandleObject self, JS::HandleValue url_ } void URL::finalize(JS::GCContext *gcx, JSObject *self) { - jsurl::JSUrl *url = + auto *url = static_cast(JS::GetReservedSlot(self, Slots::Url).toPrivate()); jsurl::free_jsurl(url); } @@ -756,8 +798,9 @@ JSObject *URL::create(JSContext *cx, JS::HandleObject self, JS::HandleValue url_ if (!base_val.isUndefined()) { auto str = core::encode_spec_string(cx, base_val); - if (!str.data) + if (!str.data) { return nullptr; + } base = jsurl::new_jsurl(&str); if (!base) { @@ -775,15 +818,18 @@ bool URL::init_class(JSContext *cx, JS::HandleObject global) { } bool install(api::Engine *engine) { - if (!URL::init_class(engine->cx(), engine->global())) + if (!URL::init_class(engine->cx(), engine->global())) { return false; - if (!URLSearchParams::init_class(engine->cx(), engine->global())) + } + if (!URLSearchParams::init_class(engine->cx(), engine->global())) { return false; - if (!URLSearchParamsIterator::init_class(engine->cx(), engine->global())) + } + if (!URLSearchParamsIterator::init_class(engine->cx(), engine->global())) { return false; + } return true; } -} // namespace url -} // namespace web -} // namespace builtins +} // namespace builtins::web::url + + diff --git a/builtins/web/url.h b/builtins/web/url.h index 778f752a..5ee7e9ba 100644 --- a/builtins/web/url.h +++ b/builtins/web/url.h @@ -4,15 +4,15 @@ #include "builtin.h" #include "rust-url.h" -namespace builtins { -namespace web { -namespace url { + + +namespace builtins::web::url { class URLSearchParamsIterator : public BuiltinNoConstructor { public: static constexpr const char *class_name = "URLSearchParamsIterator"; - enum Slots { Params, Type, Index, Count }; + enum Slots : uint8_t { Params, Type, Index, Count }; static bool next(JSContext *cx, unsigned argc, JS::Value *vp); @@ -44,7 +44,7 @@ class URLSearchParams : public BuiltinNoConstructor { public: static constexpr const char *class_name = "URLSearchParams"; - enum Slots { Url, Params, Count }; + enum Slots : uint8_t { Url, Params, Count }; static const JSFunctionSpec static_methods[]; static const JSPropertySpec static_properties[]; @@ -97,7 +97,7 @@ class URL : public BuiltinImpl { public: static constexpr const char *class_name = "URL"; - enum Slots { Url, Params, Count }; + enum Slots : uint8_t { Url, Params, Count }; static const JSFunctionSpec static_methods[]; static const JSPropertySpec static_properties[]; static const JSFunctionSpec methods[]; @@ -106,6 +106,7 @@ class URL : public BuiltinImpl { static const unsigned ctor_length = 1; static const jsurl::JSUrl *url(JSObject *self); + static jsurl::JSUrl *url_mut(JSObject *self); static jsurl::SpecString origin(JSContext *cx, JS::HandleObject self); static bool origin(JSContext *cx, JS::HandleObject self, JS::MutableHandleValue rval); @@ -136,13 +137,13 @@ class URL : public BuiltinImpl { static bool init_class(JSContext *cx, JS::HandleObject global); static bool constructor(JSContext *cx, unsigned argc, JS::Value *vp); - static void finalize(JS::GCContext *gcx, JSObject *obj); + static void finalize(JS::GCContext *gcx, JSObject *self); }; bool install(api::Engine *engine); -} // namespace url -} // namespace web -} // namespace builtins +} // namespace builtins::web::url + + #endif diff --git a/builtins/web/worker-location.cpp b/builtins/web/worker-location.cpp index b713a4d9..812d9d49 100644 --- a/builtins/web/worker-location.cpp +++ b/builtins/web/worker-location.cpp @@ -6,9 +6,9 @@ * `location`. * https://html.spec.whatwg.org/multipage/workers.html#worker-locations */ -namespace builtins { -namespace web { -namespace worker_location { + + +namespace builtins::web::worker_location { JS::PersistentRooted WorkerLocation::url; @@ -83,6 +83,6 @@ bool install(api::Engine *engine) { return WorkerLocation::init_class(engine->cx(), engine->global()); } -} // namespace worker_location -} // namespace web -} // namespace builtins +} // namespace builtins::web::worker_location + + diff --git a/builtins/web/worker-location.h b/builtins/web/worker-location.h index df054a32..f542daf6 100644 --- a/builtins/web/worker-location.h +++ b/builtins/web/worker-location.h @@ -3,16 +3,16 @@ #include "builtin.h" -namespace builtins { -namespace web { -namespace worker_location { + + +namespace builtins::web::worker_location { class WorkerLocation : public BuiltinNoConstructor { private: public: static constexpr const char *class_name = "WorkerLocation"; static const int ctor_length = 1; - enum Slots { Count }; + enum Slots : uint8_t { Count }; static const JSFunctionSpec static_methods[]; static const JSPropertySpec static_properties[]; static const JSFunctionSpec methods[]; @@ -26,8 +26,8 @@ class WorkerLocation : public BuiltinNoConstructor { bool install(api::Engine *engine); -} // namespace worker_location -} // namespace web -} // namespace builtins +} // namespace builtins::web::worker_location + + #endif diff --git a/cmake/compile-flags.cmake b/cmake/compile-flags.cmake index 219b2f05..75a8593f 100644 --- a/cmake/compile-flags.cmake +++ b/cmake/compile-flags.cmake @@ -12,7 +12,8 @@ list(APPEND CMAKE_EXE_LINKER_FLAGS list(JOIN CMAKE_EXE_LINKER_FLAGS " " CMAKE_EXE_LINKER_FLAGS) list(APPEND CMAKE_CXX_FLAGS - -std=gnu++20 -Wall -Werror -Qunused-arguments -Wimplicit-fallthrough -Wno-unknown-warning-option + -std=gnu++20 -Wall -Werror -Qunused-arguments + -Wimplicit-fallthrough -Wno-unknown-warning-option -Wno-invalid-offsetof -fno-sized-deallocation -fno-aligned-new -mthread-model single -fPIC -fno-rtti -fno-exceptions -fno-math-errno -pipe -fno-omit-frame-pointer -funwind-tables -m32 diff --git a/cmake/lint.cmake b/cmake/lint.cmake new file mode 100644 index 00000000..ab32cfd0 --- /dev/null +++ b/cmake/lint.cmake @@ -0,0 +1,33 @@ +set(CLANG_TIDY ${WASI_SDK_PREFIX}/bin/clang-tidy) +set(RUN_CLANG_TIDY ${WASI_SDK_PREFIX}/bin/run-clang-tidy) +set(CLANG_APPLY_REPLACEMENTS ${WASI_SDK_PREFIX}/bin/clang-apply-replacements) +set(WASI_SYSROOT ${WASI_SDK_PREFIX}/share/wasi-sysroot) + +add_custom_target(clang-tidy + COMMAND ${RUN_CLANG_TIDY} + -p=${CMAKE_BINARY_DIR} + -clang-tidy-binary=${CLANG_TIDY} + -extra-arg=--sysroot=${WASI_SYSROOT} + -config-file=${CMAKE_SOURCE_DIR}/.clang-tidy + ${CMAKE_SOURCE_DIR}/builtins + ${CMAKE_SOURCE_DIR}/runtime + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMENT "Running clang‑tidy over the codebase" + VERBATIM) + +add_custom_target(clang-tidy-fix + COMMAND ${RUN_CLANG_TIDY} + -p=${CMAKE_BINARY_DIR} + -clang-tidy-binary=${CLANG_TIDY} + -clang-apply-replacements-binary=${CLANG_APPLY_REPLACEMENTS} + -extra-arg=--sysroot=${WASI_SYSROOT} + -config-file=${CMAKE_SOURCE_DIR}/.clang-tidy + -fix + ${CMAKE_SOURCE_DIR}/builtins + ${CMAKE_SOURCE_DIR}/runtime + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMENT "Running clang‑tidy over the codebase and applying fixes" + VERBATIM) + +add_dependencies(clang-tidy starling-raw.wasm) +add_dependencies(clang-tidy-fix starling-raw.wasm) diff --git a/crates/rust-multipart/rust-multipart-ffi.h b/crates/rust-multipart/rust-multipart-ffi.h index 86d06531..4cb9d832 100644 --- a/crates/rust-multipart/rust-multipart-ffi.h +++ b/crates/rust-multipart/rust-multipart-ffi.h @@ -15,7 +15,7 @@ namespace jsmultipart { -enum class RetCode { +enum class RetCode : uint8_t { Ok = 0, Eos = 1, Error = 2, diff --git a/docs/src/developer/builtins-cpp.md b/docs/src/developer/builtins-cpp.md index 8e64319f..aee4bff6 100644 --- a/docs/src/developer/builtins-cpp.md +++ b/docs/src/developer/builtins-cpp.md @@ -109,7 +109,7 @@ class MyClass : public BuiltinImpl { static bool static_prop_get(JSContext *cx, unsigned argc, JS::Value *vp); public: - enum Slots { SlotA, SlotB, Count }; + enum Slots : uint8_t { SlotA, SlotB, Count }; static constexpr const char *class_name = "MyClass"; static constexpr unsigned ctor_length = 2; diff --git a/host-apis/wasi-0.2.0/host_api.cpp b/host-apis/wasi-0.2.0/host_api.cpp index 40d9507e..493a4597 100644 --- a/host-apis/wasi-0.2.0/host_api.cpp +++ b/host-apis/wasi-0.2.0/host_api.cpp @@ -453,7 +453,7 @@ Result HttpOutgoingBody::write_all(api::Engine *engine, HostBytes bytes, } class BodyAppendTask final : public api::AsyncTask { - enum class State { + enum class State : uint8_t { BlockedOnBoth, BlockedOnIncoming, BlockedOnOutgoing, diff --git a/include/builtin.h b/include/builtin.h index c3cf215a..42d8a99e 100644 --- a/include/builtin.h +++ b/include/builtin.h @@ -8,20 +8,14 @@ #include #include -// TODO: remove these once the warnings are fixed -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" -#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" #include "js/ArrayBuffer.h" #include "js/Conversions.h" #include "jsapi.h" #include "jsfriendapi.h" -// ReSharper disable once CppUnusedIncludeDirective #include "js/experimental/TypedData.h" #include "js/ForOfIterator.h" #include "js/Object.h" #include "js/Promise.h" -#pragma clang diagnostic pop using JS::CallArgs; using JS::CallArgsFromVp; diff --git a/include/extension-api.h b/include/extension-api.h index e35be18a..3c9d2541 100644 --- a/include/extension-api.h +++ b/include/extension-api.h @@ -3,15 +3,8 @@ #include #include "builtin.h" -#include "mozilla/WeakPtr.h" - -// TODO: remove these once the warnings are fixed -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" -#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" - #include "jsapi.h" -#pragma clang diagnostic pop +#include "mozilla/WeakPtr.h" using JS::RootedObject; using JS::RootedString; @@ -27,7 +20,7 @@ using JS::PersistentRootedVector; using std::optional; -typedef int32_t PollableHandle; +using PollableHandle = int32_t; constexpr PollableHandle INVALID_POLLABLE_HANDLE = -1; constexpr PollableHandle IMMEDIATE_TASK_HANDLE = -2; @@ -76,7 +69,7 @@ struct EngineConfig { EngineConfig() = default; }; -enum class EngineState { Uninitialized, EngineInitializing, ScriptPreInitializing, Initialized, Aborted }; +enum class EngineState : uint8_t { Uninitialized, EngineInitializing, ScriptPreInitializing, Initialized, Aborted }; class Engine { std::unique_ptr config_; @@ -86,8 +79,8 @@ class Engine { explicit Engine(std::unique_ptr config); static Engine *get(JSContext *cx); - JSContext *cx(); - HandleObject global(); + static JSContext *cx(); + static HandleObject global(); EngineState state(); bool debugging_enabled(); bool wpt_mode(); @@ -116,8 +109,8 @@ class Engine { * changing this default, and will impact all subsequent top-level * evaluations. */ - bool eval_toplevel(const char *path, MutableHandleValue result); - bool eval_toplevel(JS::SourceText &source, const char *path, + bool eval_toplevel(std::string_view, MutableHandleValue result); + bool eval_toplevel(JS::SourceText &source, std::string_view path, MutableHandleValue result); /** @@ -132,7 +125,7 @@ class Engine { /** * Returns the global the initialization script runs in. */ - HandleObject init_script_global(); + static HandleObject init_script_global(); /** * Run the async event loop as long as there's interest registered in keeping it running. @@ -155,49 +148,56 @@ class Engine { /** * Add an event loop interest to track */ - void incr_event_loop_interest(); + static void incr_event_loop_interest(); /** * Remove an event loop interest to track * The last decrementer marks the event loop as complete to finish */ - void decr_event_loop_interest(); + static void decr_event_loop_interest(); /** * Get the JS value associated with the top-level script execution - * the last expression for a script, or the module namespace for a module. */ - HandleValue script_value(); + static HandleValue script_value(); - bool has_pending_async_tasks(); - void queue_async_task(RefPtr task); - bool cancel_async_task(RefPtr task); + static bool has_pending_async_tasks(); + static void queue_async_task(const RefPtr& task); + bool cancel_async_task(const RefPtr& task); - bool has_unhandled_promise_rejections(); + static bool has_unhandled_promise_rejections(); void report_unhandled_promise_rejections(); - void clear_unhandled_promise_rejections(); + static void clear_unhandled_promise_rejections(); void abort(const char *reason); - bool debug_logging_enabled(); + static bool debug_logging_enabled(); - bool dump_value(JS::Value val, FILE *fp = stdout); - bool print_stack(FILE *fp); - void dump_error(HandleValue error, FILE *fp = stderr); - void dump_pending_exception(const char *description = "", FILE *fp = stderr); - void dump_promise_rejection(HandleValue reason, HandleObject promise, FILE *fp = stderr); + static bool dump_value(JS::Value val, FILE *fp = stdout); + static bool print_stack(FILE *fp); + static void dump_error(HandleValue error, FILE *fp = stderr); + static void dump_pending_exception(const char *description = "", FILE *fp = stderr); + static void dump_promise_rejection(HandleValue reason, HandleObject promise, FILE *fp = stderr); }; -typedef bool (*TaskCompletionCallback)(JSContext* cx, HandleObject receiver); +using TaskCompletionCallback = bool (*)(JSContext* cx, HandleObject receiver); class AsyncTask : public js::RefCounted, public mozilla::SupportsWeakPtr { protected: PollableHandle handle_ = -1; public: + AsyncTask() = default; virtual ~AsyncTask() = default; + AsyncTask(const AsyncTask &) = delete; + AsyncTask(AsyncTask &&) = delete; + + AsyncTask &operator=(const AsyncTask &) = delete; + AsyncTask &operator=(AsyncTask &&) = delete; + virtual bool run(Engine *engine) = 0; virtual bool cancel(Engine *engine) = 0; diff --git a/include/host_api.h b/include/host_api.h index 6c9fe053..330354f7 100644 --- a/include/host_api.h +++ b/include/host_api.h @@ -2,7 +2,6 @@ #define JS_RUNTIME_HOST_API_H #include -#include #include #include #include @@ -10,15 +9,11 @@ #include #include -#include "../crates/rust-url/rust-url.h" #include "extension-api.h" #include "js/TypeDecls.h" - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" #include "js/Utility.h" -#include "jsapi.h" -#pragma clang diagnostic pop + +#include "../crates/rust-url/rust-url.h" using std::optional; using std::string_view; diff --git a/justfile b/justfile index 901a068c..456e63c2 100644 --- a/justfile +++ b/justfile @@ -45,6 +45,12 @@ do_clean: clean-all: && do_clean @echo "This will remove {{builddir}}" +# Run clang-tidy +lint: (build "clang-tidy") + +# Run clang-tidy and apply offered fixes +lint-fix: (build "clang-tidy-fix") + # Componentize js script componentize script="" outfile="starling.wasm": build {{ builddir }}/componentize.sh {{ script }} -o {{ outfile }} diff --git a/runtime/allocator.cpp b/runtime/allocator.cpp index c3d594d4..66472db0 100644 --- a/runtime/allocator.cpp +++ b/runtime/allocator.cpp @@ -1,5 +1,5 @@ - #include "allocator.h" +#include "js/MemoryFunctions.h" JSContext *CONTEXT = nullptr; diff --git a/runtime/allocator.h b/runtime/allocator.h index 5c2e74f5..05f506cc 100644 --- a/runtime/allocator.h +++ b/runtime/allocator.h @@ -2,21 +2,6 @@ #define JS_COMPUTE_RUNTIME_ALLOCATOR_H #include -#include -#include -#include -#include -#include -#include -#include - -#include "js/TypeDecls.h" - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" -#include "js/Utility.h" -#include "jsapi.h" -#pragma clang diagnostic pop struct JSContext; @@ -33,7 +18,7 @@ extern "C" { void *cabi_realloc(void *ptr, size_t orig_size, size_t align, size_t new_size); /// A more ergonomic version of cabi_realloc for fresh allocations. -inline void *cabi_malloc(size_t bytes, size_t align) { return cabi_realloc(NULL, 0, align, bytes); } +inline void *cabi_malloc(size_t bytes, size_t align) { return cabi_realloc(nullptr, 0, align, bytes); } /// Not required by wit-bindgen generated code, but a usefully named version of /// JS_free that can help with identifying where memory allocated by the c-abi. diff --git a/runtime/builtin.cpp b/runtime/builtin.cpp index f8435d18..05541fbc 100644 --- a/runtime/builtin.cpp +++ b/runtime/builtin.cpp @@ -1,7 +1,7 @@ #include "builtin.h" static const JSErrorFormatString *GetErrorMessageFromRef(void *userRef, unsigned errorNumber) { - auto error = static_cast(userRef); + auto *error = static_cast(userRef); JS::ConstUTF8CharsZ(error->format, strlen(error->format)); return error; @@ -16,7 +16,7 @@ bool api::throw_error(JSContext* cx, const JSErrorFormatString &error, } JS_ReportErrorNumberUTF8Array(cx, GetErrorMessageFromRef, - const_cast(&error), 0, args); + const_cast(&error), 0, args); // NOLINT(cppcoreguidelines-pro-type-const-cast) return false; } @@ -29,8 +29,8 @@ std::optional> value_to_buffer(JSContext *cx, JS::HandleValue } JS::RootedObject input(cx, &val.toObject()); - uint8_t *data; - bool is_shared; + uint8_t *data = nullptr; + bool is_shared = false; size_t len = 0; if (JS_IsArrayBufferViewObject(input)) { diff --git a/runtime/debugger.cpp b/runtime/debugger.cpp index 0fa98718..447573a3 100644 --- a/runtime/debugger.cpp +++ b/runtime/debugger.cpp @@ -35,7 +35,7 @@ bool dbg_set_content_path(JSContext *cx, unsigned argc, Value *vp) { bool print_location(JSContext *cx, FILE *fp = stdout) { JS::AutoFilename filename; - uint32_t lineno; + uint32_t lineno = 0; JS::ColumnNumberOneOrigin column; if (!DescribeScriptedCaller(&filename, cx, &lineno, &column)) { return false; @@ -73,7 +73,7 @@ class TCPSocket : public builtins::BuiltinNoConstructor { public: static constexpr const char *class_name = "TCPSocket"; - enum Slots { TCPSocketHandle, Count }; + enum Slots : uint8_t { TCPSocketHandle, Count }; static const JSFunctionSpec static_methods[]; static const JSPropertySpec static_properties[]; @@ -99,12 +99,12 @@ bool TCPSocket::send(JSContext *cx, unsigned argc, JS::Value *vp) { bool TCPSocket::receive(JSContext *cx, unsigned argc, JS::Value *vp) { METHOD_HEADER(1); - int32_t chunk_size; + int32_t chunk_size = 0; if (!ToInt32(cx, args[0], &chunk_size)) { return false; } auto chunk = socket(self)->receive(chunk_size); - auto str = core::decode(cx, chunk); + auto *str = core::decode(cx, chunk); if (!str) { return false; } @@ -134,7 +134,7 @@ host_api::HostString read_message(JSContext *cx, host_api::TCPSocket *socket) { return nullptr; } - char *end; + char *end = nullptr; uint16_t message_length = std::strtoul(chunk.begin(), &end, 10); if (end == chunk.begin() || *end != '\n') { return nullptr; @@ -154,7 +154,7 @@ host_api::HostString read_message(JSContext *cx, host_api::TCPSocket *socket) { } // namespace debugging_socket bool initialize_debugger(JSContext *cx, uint16_t port, bool content_already_initialized) { - auto socket = host_api::TCPSocket::make(host_api::TCPSocket::IPAddressFamily::IPV4); + auto *socket = host_api::TCPSocket::make(host_api::TCPSocket::IPAddressFamily::IPV4); MOZ_RELEASE_ASSERT(socket, "Failed to create debugging socket"); if (!socket->connect({127, 0, 0, 1}, port) || !socket->send("get-session-port")) { @@ -175,7 +175,7 @@ bool initialize_debugger(JSContext *cx, uint16_t port, bool content_already_init return true; } - char *end; + char *end = nullptr; uint16_t session_port = std::strtoul(response.begin(), &end, 10); if (session_port < 1024 || session_port > 65535) { printf("Invalid debugging session port '%*s' received, continuing without debugging ...\n", @@ -206,7 +206,7 @@ bool initialize_debugger(JSContext *cx, uint16_t port, bool content_already_init .setNewCompartmentInSystemZone() .setInvisibleToDebugger(true); - static JSClass global_class = {"global", JSCLASS_GLOBAL_FLAGS, &JS::DefaultGlobalClassOps}; + static JSClass global_class = {.name="global", .flags=JSCLASS_GLOBAL_FLAGS, .cOps=&JS::DefaultGlobalClassOps}; RootedObject global(cx); global = JS_NewGlobalObject(cx, &global_class, nullptr, JS::DontFireOnNewGlobalHook, options); if (!global) { @@ -256,11 +256,7 @@ bool initialize_debugger(JSContext *cx, uint16_t port, bool content_already_init } RootedValue result(cx); - if (!JS_ExecuteScript(cx, script, &result)) { - return false; - } - - return true; + return JS_ExecuteScript(cx, script, &result); } } // anonymous namespace @@ -297,7 +293,7 @@ void maybe_init_debugger(api::Engine *engine, bool content_already_initialized) // Resuming a wizer snapshot, so we have to ensure that the environment is reset. __wasilibc_initialize_environ(); - auto port_str = std::getenv("DEBUGGER_PORT"); + auto *port_str = std::getenv("DEBUGGER_PORT"); if (port_str) { uint32_t port = std::stoi(port_str); if (!initialize_debugger(engine->cx(), port, content_already_initialized)) { diff --git a/runtime/decode.cpp b/runtime/decode.cpp index 076d38cd..3c187b85 100644 --- a/runtime/decode.cpp +++ b/runtime/decode.cpp @@ -9,7 +9,7 @@ JSString *decode(JSContext *cx, string_view str) { JSString *decode_byte_string(JSContext *cx, string_view str) { JS::UniqueLatin1Chars chars( - static_cast(std::memcpy(malloc(str.size()), str.data(), str.size()))); + static_cast(std::memcpy(js_malloc(str.size()), str.data(), str.size()))); return JS_NewLatin1String(cx, std::move(chars), str.length()); } diff --git a/runtime/encode.cpp b/runtime/encode.cpp index 2d97cea5..866fea1e 100644 --- a/runtime/encode.cpp +++ b/runtime/encode.cpp @@ -1,14 +1,8 @@ #include "encode.h" - -// TODO: remove these once the warnings are fixed -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" #include "js/Conversions.h" -#pragma clang diagnostic pop namespace core { -using host_api::HostBytes; using host_api::HostString; HostString encode(JSContext *cx, JS::HandleString str) { @@ -37,7 +31,7 @@ HostString encode_byte_string(JSContext *cx, JS::HandleValue val) { if (!str) { return HostString{}; } - size_t length; + size_t length = 0; if (!JS::StringHasLatin1Chars(str)) { bool foundBadChar = false; { @@ -62,10 +56,12 @@ HostString encode_byte_string(JSContext *cx, JS::HandleValue val) { } else { length = JS::GetStringLength(str); } - char *buf = static_cast(malloc(length)); - if (!JS_EncodeStringToBuffer(cx, str, buf, length)) + + char *buf = static_cast(js_malloc(length)); + if (!JS_EncodeStringToBuffer(cx, str, buf, length)) { MOZ_ASSERT_UNREACHABLE(); - return HostString(JS::UniqueChars(buf), length); +} + return {JS::UniqueChars(buf), length}; } jsurl::SpecString encode_spec_string(JSContext *cx, JS::HandleValue val) { diff --git a/runtime/engine.cpp b/runtime/engine.cpp index 341dc3b7..d097106f 100644 --- a/runtime/engine.cpp +++ b/runtime/engine.cpp @@ -5,22 +5,17 @@ #include "event_loop.h" #include "script_loader.h" -// TODO: remove these once the warnings are fixed -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" -#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" #include "js/CompilationAndEvaluation.h" #include "js/Modules.h" #include "js/ForOfIterator.h" #include "js/Initialization.h" #include "js/Promise.h" #include "jsfriendapi.h" -#pragma clang diagnostic pop #include #include #include -#include +#include #ifdef MEM_STATS #include @@ -53,13 +48,12 @@ static bool dump_mem_stats(JSContext *cx) { #define TRACE(...) \ if (config_->verbose) { \ - std::cout << "trace(" << __func__ << ":" << __LINE__ << "): " << __VA_ARGS__ << std::endl; \ + fmt::print("trace({}:{}): {}\n", __func__, __LINE__, fmt::format(__VA_ARGS__)); \ fflush(stdout); \ - } +} + -using std::chrono::duration_cast; using std::chrono::microseconds; -using std::chrono::system_clock; using JS::Value; @@ -79,8 +73,9 @@ bool debug_logging_enabled() { return DEBUG_LOGGING; } JS::UniqueChars stringify_value(JSContext *cx, JS::HandleValue value) { JS::RootedString str(cx, JS_ValueToSource(cx, value)); - if (!str) + if (!str) { return nullptr; + } return JS_EncodeStringToUTF8(cx, str); } @@ -113,8 +108,9 @@ bool print_stack(JSContext *cx, HandleObject stack, FILE *fp) { bool print_stack(JSContext *cx, FILE *fp) { RootedObject stackp(cx); - if (!JS::CaptureCurrentStack(cx, &stackp)) + if (!JS::CaptureCurrentStack(cx, &stackp)) { return false; + } return print_stack(cx, stackp, fp); } @@ -135,7 +131,7 @@ void print_cause(JSContext *cx, HandleValue error, FILE *fp) { fprintf(stderr, "Caused by: "); - bool has_stack; + bool has_stack = false; dump_error(cx, cause_val, &has_stack, fp); } } @@ -174,7 +170,7 @@ void dump_error(JSContext *cx, HandleValue error, bool *has_stack, FILE *fp) { } void dump_promise_rejection(JSContext *cx, HandleValue reason, HandleObject promise, FILE *fp) { - bool has_stack; + bool has_stack = false; dump_error(cx, reason, &has_stack, fp); // If the rejection reason isn't an `Error` object, we can't get an exception @@ -191,7 +187,7 @@ void dump_promise_rejection(JSContext *cx, HandleValue reason, HandleObject prom } /* The class of the global object. */ -static JSClass global_class = {"global", JSCLASS_GLOBAL_FLAGS, &JS::DefaultGlobalClassOps}; +static JSClass global_class = {.name="global", .flags=JSCLASS_GLOBAL_FLAGS, .cOps=&JS::DefaultGlobalClassOps}; JS::PersistentRootedObject GLOBAL; JS::PersistentRootedObject INIT_SCRIPT_GLOBAL; @@ -278,14 +274,14 @@ bool create_content_global(JSContext * cx) { static bool define_builtin_module(JSContext *cx, unsigned argc, Value *vp); bool create_initializer_global(Engine *engine) { - auto cx = engine->cx(); + auto *cx = engine->cx(); JS::RealmOptions options; options.creationOptions() .setStreamsEnabled(true) .setExistingCompartment(engine->global()); - static JSClass global_class = {"global", JSCLASS_GLOBAL_FLAGS, &JS::DefaultGlobalClassOps}; + static JSClass global_class = {.name="global", .flags=JSCLASS_GLOBAL_FLAGS, .cOps=&JS::DefaultGlobalClassOps}; RootedObject global(cx); global = JS_NewGlobalObject(cx, &global_class, nullptr, JS::DontFireOnNewGlobalHook, options); if (!global) { @@ -338,7 +334,7 @@ bool init_js(const EngineConfig& config) { return false; } - auto opts = new JS::CompileOptions(cx); + auto *opts = new JS::CompileOptions(cx); // This ensures that we're eagerly loading the sript, and not lazily // generating bytecode for functions. @@ -355,22 +351,26 @@ bool init_js(const EngineConfig& config) { static bool report_unhandled_promise_rejections(JSContext *cx) { RootedValue iterable(cx); - if (!JS::SetValues(cx, unhandledRejectedPromises, &iterable)) + if (!JS::SetValues(cx, unhandledRejectedPromises, &iterable)) { return false; + } JS::ForOfIterator it(cx); - if (!it.init(iterable)) + if (!it.init(iterable)) { return false; + } RootedValue promise_val(cx); RootedObject promise(cx); while (true) { - bool done; - if (!it.next(&promise_val, &done)) + bool done = false; + if (!it.next(&promise_val, &done)) { return false; + } - if (done) + if (done) { break; + } promise = &promise_val.toObject(); // Note: we unconditionally print these, since they almost always indicate @@ -442,7 +442,7 @@ Engine::Engine(std::unique_ptr config) { TRACE("StarlingMonkey engine initializing"); - if (!init_js(*config_.get())) { + if (!init_js(*config_)) { abort("Initializing JS Engine"); } @@ -468,10 +468,10 @@ Engine::Engine(std::unique_ptr config) { } } - TRACE("Module mode: " << config_->module_mode); + TRACE("Module mode: ", config_->module_mode); scriptLoader->enable_module_mode(config_->module_mode); - mozilla::Maybe content_script_path = config_->content_script_path; + auto content_script_path = config_->content_script_path; if (config_->pre_initialize) { state_ = EngineState::ScriptPreInitializing; @@ -482,15 +482,15 @@ Engine::Engine(std::unique_ptr config) { // resumed wizer snapshot. content_debugger::maybe_init_debugger(this, false); if (auto replacement_script_path = content_debugger::replacement_script_path()) { - TRACE("Using replacement script path received from debugger: " << *replacement_script_path); + TRACE("Using replacement script path received from debugger: ", *replacement_script_path); content_script_path = replacement_script_path; } } if (content_script_path) { - TRACE("Evaluating initial script from file " << content_script_path.value()); + TRACE("Evaluating initial script from file ", content_script_path.value()); RootedValue result(cx()); - if (!eval_toplevel(content_script_path.value().data(), &result)) { + if (!eval_toplevel(content_script_path.value(), &result)) { abort("evaluating top-level script"); } } @@ -502,7 +502,7 @@ Engine::Engine(std::unique_ptr config) { const std::string& script = config_->content_script.value(); RootedValue result(cx()); if (!source.init(cx(), script.c_str(), script.size(), JS::SourceOwnership::Borrowed) - || !eval_toplevel(source, path.data(), &result)) { + || !eval_toplevel(source, path, &result)) { abort("evaluating top-level inline script"); } } @@ -537,7 +537,7 @@ void Engine::abort(const char *reason) { } bool Engine::define_builtin_module(const char* id, HandleValue builtin) { - TRACE("Defining builtin module '" << id << "'"); + TRACE("Defining builtin module '", id, "'"); return scriptLoader->define_builtin_module(id, builtin); } @@ -560,17 +560,17 @@ static bool define_builtin_module(JSContext *cx, unsigned argc, Value *vp) { } bool Engine::run_initialization_script() { - auto cx = this->cx(); + auto *cx = this->cx(); JSAutoRealm ar(cx, INIT_SCRIPT_GLOBAL); auto path = config_->initializer_script_path.value(); - TRACE("Running initialization script from file " << path); + TRACE("Running initialization script from file ", path); JS::SourceText source; - if (!scriptLoader->load_resolved_script(CONTEXT, path.c_str(), path.c_str(), source)) { + if (!scriptLoader->load_resolved_script(CONTEXT, path, path, source)) { return false; } - auto opts = new JS::CompileOptions(cx); + auto *opts = new JS::CompileOptions(cx); opts->setDiscardSource(); opts->setFile(path.c_str()); JS::RootedScript script(cx, Compile(cx, *opts, source)); @@ -583,7 +583,7 @@ bool Engine::run_initialization_script() { HandleObject Engine::init_script_global() { return INIT_SCRIPT_GLOBAL; } -bool Engine::eval_toplevel(JS::SourceText &source, const char *path, +bool Engine::eval_toplevel(JS::SourceText &source, std::string_view path, MutableHandleValue result) { MOZ_ASSERT(state() > EngineState::EngineInitializing, "Engine must be done initializing"); MOZ_ASSERT(state() != EngineState::Aborted, "Engine state is aborted"); @@ -648,7 +648,7 @@ bool Engine::eval_toplevel(JS::SourceText &source, const char return true; } -bool Engine::eval_toplevel(const char *path, MutableHandleValue result) { +bool Engine::eval_toplevel(std::string_view path, MutableHandleValue result) { JS::SourceText source; if (!scriptLoader->load_script(CONTEXT, path, source)) { return false; @@ -662,11 +662,11 @@ bool Engine::run_event_loop() { } void Engine::incr_event_loop_interest() { - return core::EventLoop::incr_event_loop_interest(); + core::EventLoop::incr_event_loop_interest(); } void Engine::decr_event_loop_interest() { - return core::EventLoop::decr_event_loop_interest(); + core::EventLoop::decr_event_loop_interest(); } bool Engine::dump_value(JS::Value val, FILE *fp) { return ::dump_value(CONTEXT, val, fp); } @@ -677,7 +677,7 @@ void Engine::dump_pending_exception(const char *description, FILE *fp) { } void Engine::dump_error(JS::HandleValue err, FILE *fp) { - bool has_stack; + bool has_stack = false; ::dump_error(CONTEXT, err, &has_stack, fp); fflush(fp); } @@ -690,11 +690,11 @@ bool Engine::debug_logging_enabled() { return ::debug_logging_enabled(); } bool Engine::has_pending_async_tasks() { return core::EventLoop::has_pending_async_tasks(); } -void Engine::queue_async_task(RefPtr task) { +void Engine::queue_async_task(const RefPtr& task) { core::EventLoop::queue_async_task(task); } -bool Engine::cancel_async_task(RefPtr task) { +bool Engine::cancel_async_task(const RefPtr& task) { return core::EventLoop::cancel_async_task(this, task); } diff --git a/runtime/event_loop.cpp b/runtime/event_loop.cpp index d315e799..2bc40c18 100644 --- a/runtime/event_loop.cpp +++ b/runtime/event_loop.cpp @@ -8,7 +8,7 @@ #include struct TaskQueue { - std::vector> tasks = {}; + std::vector> tasks; int interest_cnt = 0; bool event_loop_running = false; @@ -23,13 +23,13 @@ static PersistentRooted queue; namespace core { -void EventLoop::queue_async_task(RefPtr task) { +void EventLoop::queue_async_task(const RefPtr& task) { MOZ_ASSERT(task); queue.get().tasks.emplace_back(task); } -bool EventLoop::cancel_async_task(api::Engine *engine, RefPtr task) { - const auto tasks = &queue.get().tasks; +bool EventLoop::cancel_async_task(api::Engine *engine, const RefPtr& task) { + auto *const tasks = &queue.get().tasks; for (auto it = tasks->begin(); it != tasks->end(); ++it) { if (*it == task) { tasks->erase(it); @@ -75,7 +75,7 @@ bool EventLoop::run_event_loop(api::Engine *engine, double total_compute) { return true; } - const auto tasks = &queue.get().tasks; + auto *const tasks = &queue.get().tasks; size_t tasks_size = tasks->size(); if (tasks_size == 0) { exit_event_loop(); diff --git a/runtime/event_loop.h b/runtime/event_loop.h index a5ada005..acca516c 100644 --- a/runtime/event_loop.h +++ b/runtime/event_loop.h @@ -2,13 +2,7 @@ #define JS_COMPUTE_RUNTIME_EVENT_LOOP_H #include "extension-api.h" - -// TODO: remove these once the warnings are fixed -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" -#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" #include "jsapi.h" -#pragma clang diagnostic pop namespace core { @@ -41,12 +35,12 @@ class EventLoop { /** * Queue a new async task. */ - static void queue_async_task(RefPtr task); + static void queue_async_task(const RefPtr& task); /** * Remove a queued async task. */ - static bool cancel_async_task(api::Engine *engine, RefPtr task); + static bool cancel_async_task(api::Engine *engine, const RefPtr& task); }; } // namespace core diff --git a/runtime/js.cpp b/runtime/js.cpp index a5cf05c7..1dfc28f3 100644 --- a/runtime/js.cpp +++ b/runtime/js.cpp @@ -1,6 +1,8 @@ +#include #include #include #include +#include #include "builtin.h" #include "extension-api.h" @@ -16,7 +18,7 @@ api::Engine *engine; api::Engine* initialize(std::vector args) { auto config_parser = starling::ConfigParser(); - config_parser.apply_env()->apply_args(args); + config_parser.apply_env()->apply_args(std::move(args)); return new api::Engine(config_parser.take()); } @@ -33,7 +35,7 @@ static uint64_t mono_clock_offset = 0; // This overrides wasi-libc's weakly linked implementation of clock_gettime to ensure that // monotonic clocks really are monotonic, even across resumptions of wizer snapshots. int clock_gettime(clockid_t clock, timespec * ts) { - __wasi_clockid_t clock_id; + __wasi_clockid_t clock_id = 0; if (clock == CLOCK_REALTIME) { clock_id = __WASI_CLOCKID_REALTIME; } else if (clock == CLOCK_MONOTONIC) { @@ -41,7 +43,7 @@ int clock_gettime(clockid_t clock, timespec * ts) { } else { return EINVAL; } - __wasi_timestamp_t t; + __wasi_timestamp_t t = 0; auto errno = __wasi_clock_time_get(clock_id, 1, &t); if (errno != 0) { return EINVAL; @@ -65,11 +67,9 @@ void wizen() { ENGINE->finish_pre_initialization(); // Ensure that the monotonic clock is always increasing, even across multiple resumptions. - __wasi_timestamp_t t; + __wasi_timestamp_t t = 0; MOZ_RELEASE_ASSERT(!__wasi_clock_time_get(__WASI_CLOCKID_MONOTONIC, 1, &t)); - if (mono_clock_offset < t) { - mono_clock_offset = t; - } + mono_clock_offset = std::max(mono_clock_offset, t); __wasilibc_deinitialize_environ(); } @@ -87,7 +87,9 @@ WIZER_INIT(wizen); extern "C" bool exports_wasi_cli_run_run() { auto arg_strings = host_api::environment_get_arguments(); std::vector args; - for (auto& arg : arg_strings) args.push_back(arg); + args.reserve(arg_strings.size()); + for (auto& arg : arg_strings) { args.push_back(arg); +} auto config_parser = starling::ConfigParser(); config_parser.apply_env()->apply_args(args); diff --git a/runtime/script_loader.cpp b/runtime/script_loader.cpp index 36130f1b..0a328d50 100644 --- a/runtime/script_loader.cpp +++ b/runtime/script_loader.cpp @@ -2,22 +2,27 @@ #include "encode.h" #include -#include #include #include #include #include #include -static api::Engine* ENGINE; -static ScriptLoader* SCRIPT_LOADER; +namespace { + +api::Engine* ENGINE; +ScriptLoader* SCRIPT_LOADER; +bool MODULE_MODE = true; +std::string BASE_PATH; + JS::PersistentRootedObject moduleRegistry; JS::PersistentRootedObject builtinModules; -static bool MODULE_MODE = true; -static char* BASE_PATH = nullptr; -mozilla::Maybe PATH_PREFIX = mozilla::Nothing(); JS::CompileOptions *COMPILE_OPTS; +mozilla::Maybe PATH_PREFIX = mozilla::Nothing(); + +} // namespace + using host_api::HostString; namespace ScriptLoaderErrors { @@ -30,74 +35,81 @@ class AutoCloseFile { FILE* file; public: - explicit AutoCloseFile(FILE* f) : file(f) {} + explicit AutoCloseFile(FILE *f) : file(f) {} ~AutoCloseFile() { release(); } + + AutoCloseFile(const AutoCloseFile &) = default; + AutoCloseFile(AutoCloseFile &&) = delete; + + AutoCloseFile &operator=(const AutoCloseFile &) = default; + AutoCloseFile &operator=(AutoCloseFile &&) = delete; + bool release() { bool success = true; if (file && file != stdin && file != stdout && file != stderr) { - success = !fclose(file); + success = (fclose(file) == 0); } file = nullptr; + // Clang analyzer complains about the stream leaking when stream is stdin, stdout, or stderr. + // NOLINTNEXTLINE(clang-analyzer-unix.Stream) return success; } }; // strip off the given prefix when possible for nicer debugging stacks -static const char* strip_prefix(const char* resolved_path, +static std::string strip_prefix(std::string_view resolved_path, mozilla::Maybe path_prefix) { if (!path_prefix) { - return strdup(resolved_path); + return std::string(resolved_path); } - auto& base = *path_prefix; - if (strncmp(resolved_path, base.data(), base.length()) != 0) { - return strdup(resolved_path); + + const auto& base = *path_prefix; + if (!resolved_path.starts_with(base)) { + return std::string(resolved_path); } - size_t path_len = strlen(resolved_path); - char* buf(js_pod_malloc(path_len - base.length() + 1)); - strncpy(buf, &resolved_path[base.length()], path_len - base.length() + 1); - return buf; + + return std::string(resolved_path.substr(base.size())); } struct stat s; -static const char* resolve_extension(const char* resolved_path) { - if (stat(resolved_path, &s) == 0) { + +static std::string resolve_extension(std::string resolved_path) { + if (stat(resolved_path.c_str(), &s) == 0) { return resolved_path; } - size_t len = strlen(resolved_path); - if (strncmp(resolved_path + len - 3, ".js", 3) == 0) { + + if (resolved_path.size() >= 3 && + resolved_path.compare(resolved_path.size() - 3, 3, ".js") == 0) { return resolved_path; } - char* resolved_path_ext = new char[len + 4]; - strncpy(resolved_path_ext, resolved_path, len); - strncpy(resolved_path_ext + len, ".js", 4); - MOZ_ASSERT(strlen(resolved_path_ext) == len + 3); - if (stat(resolved_path_ext, &s) == 0) { - delete[] resolved_path; - return resolved_path_ext; + + std::string with_ext = resolved_path + ".js"; + if (stat(with_ext.c_str(), &s) == 0) { + return with_ext; } - delete[] resolved_path_ext; return resolved_path; } -static const char* resolve_path(const char* path, const char* base, size_t base_len) { - MOZ_ASSERT(base); +static std::string resolve_path(std::string_view path, std::string_view base) { + size_t base_len = base.size(); while (base_len > 0 && base[base_len - 1] != '/') { base_len--; } - size_t path_len = strlen(path); + size_t path_len = path.size(); // create the maximum buffer size as a working buffer - char* resolved_path = new char[base_len + path_len + 1]; + std::string resolved_path; + resolved_path.reserve(base_len + path_len + 1); // copy the base in if used size_t resolved_len = base_len; - if (path[0] == '/') { + if (!path.empty() && path[0] == '/') { resolved_len = 0; } else { - strncpy(resolved_path, base, base_len); + resolved_path.assign(base.substr(0, base_len)); } // Iterate through each segment of the path, copying each segment into the resolved path, @@ -107,10 +119,12 @@ static const char* resolve_path(const char* path, const char* base, size_t base_ while (path_cur_idx < path_len) { // read until the end or the next / to get the segment position // as the substring between path_from_idx and path_cur_idx - while (path_cur_idx < path_len && path[path_cur_idx] != '/') + while (path_cur_idx < path_len && path[path_cur_idx] != '/') { path_cur_idx++; - if (path_cur_idx == path_from_idx) + } + if (path_cur_idx == path_from_idx) { break; + } // . segment to skip if (path_cur_idx - path_from_idx == 1 && path[path_from_idx] == '.') { path_cur_idx++; @@ -122,29 +136,31 @@ static const char* resolve_path(const char* path, const char* base, size_t base_ path_cur_idx++; path_from_idx = path_cur_idx; if (resolved_len > 0 && resolved_path[resolved_len - 1] == '/') { - resolved_len --; + resolved_len--; } while (resolved_len > 0 && resolved_path[resolved_len - 1] != '/') { resolved_len--; } + // Resize string to match resolved_len + resolved_path.resize(resolved_len); continue; } // normal segment to copy (with the trailing / if not the last segment) - if (path[path_cur_idx] == '/') + if (path_cur_idx < path_len && path[path_cur_idx] == '/') { path_cur_idx++; - strncpy(resolved_path + resolved_len, path + path_from_idx, path_cur_idx - path_from_idx); + } + + // Copy segment equivalent to: strncpy(resolved_path + resolved_len, path + path_from_idx, path_cur_idx - path_from_idx); + resolved_path.append(path.substr(path_from_idx, path_cur_idx - path_from_idx)); resolved_len += path_cur_idx - path_from_idx; path_from_idx = path_cur_idx; } - // finalize the buffer - resolved_path[resolved_len] = '\0'; - MOZ_ASSERT(strlen(resolved_path) == resolved_len); - return resolve_extension(resolved_path); + return resolve_extension(std::move(resolved_path)); } static JSObject* get_module(JSContext* cx, JS::SourceText &source, - const char* resolved_path, const JS::CompileOptions &opts) { + std::string_view resolved_path, const JS::CompileOptions &opts) { RootedObject module(cx, JS::CompileModule(cx, opts, source)); if (!module) { return nullptr; @@ -156,12 +172,12 @@ static JSObject* get_module(JSContext* cx, JS::SourceText &so return nullptr; } - RootedString resolved_path_str(cx, JS_NewStringCopyZ(cx, resolved_path)); + RootedString resolved_path_str(cx, JS_NewStringCopyN(cx, resolved_path.data(), resolved_path.size())); if (!resolved_path_str) { return nullptr; } - RootedValue resolved_path_val(cx, StringValue(resolved_path_str)); + RootedValue resolved_path_val(cx, StringValue(resolved_path_str)); if (!JS_DefineProperty(cx, info, "id", resolved_path_val, JSPROP_ENUMERATE)) { return nullptr; } @@ -175,14 +191,14 @@ static JSObject* get_module(JSContext* cx, JS::SourceText &so return module; } -static JSObject* get_module(JSContext* cx, const char* specifier, const char* resolved_path, - const JS::CompileOptions &opts) { - RootedString resolved_path_str(cx, JS_NewStringCopyZ(cx, resolved_path)); +static JSObject *get_module(JSContext *cx, std::string_view specifier, + std::string_view resolved_path, const JS::CompileOptions &opts) { + RootedString resolved_path_str(cx, JS_NewStringCopyN(cx, resolved_path.data(), resolved_path.size())); if (!resolved_path_str) { return nullptr; } - RootedValue resolved_path_val(cx, StringValue(resolved_path_str)); + RootedValue resolved_path_val(cx, StringValue(resolved_path_str)); RootedValue module_val(cx); if (!JS::MapGet(cx, moduleRegistry, resolved_path_val, &module_val)) { return nullptr; @@ -327,10 +343,11 @@ JSObject* module_resolve_hook(JSContext* cx, HandleValue referencingPrivate, } HostString str = core::encode(cx, parent_path_val); - const char* resolved_path = resolve_path(path.get(), str.ptr.get(), str.len); + auto resolved_path = resolve_path(path.get(), str.ptr.get()); JS::CompileOptions opts(cx, *COMPILE_OPTS); - opts.setFileAndLine(strip_prefix(resolved_path, PATH_PREFIX), 1); + auto stripped = strip_prefix(resolved_path, PATH_PREFIX); + opts.setFileAndLine(stripped.c_str(), 1); return get_module(cx, path.get(), resolved_path, opts); } @@ -379,7 +396,7 @@ bool ScriptLoader::define_builtin_module(const char* id, HandleValue builtin) { } RootedValue module_val(cx); RootedValue id_val(cx, StringValue(id_str)); - bool already_exists; + bool already_exists = false; if (!MapHas(cx, builtinModules, id_val, &already_exists)) { return false; } @@ -396,9 +413,15 @@ void ScriptLoader::enable_module_mode(bool enable) { MODULE_MODE = enable; } -bool ScriptLoader::load_resolved_script(JSContext *cx, const char *specifier, - const char* resolved_path, +bool ScriptLoader::load_resolved_script(JSContext *cx, std::string_view specifier_sv, + std::string_view resolved_path_sv, JS::SourceText &script) { + std::string specifier_str(specifier_sv); + std::string resolved_path_str(resolved_path_sv); + + const auto *specifier = specifier_str.c_str(); + const auto *resolved_path = resolved_path_str.c_str(); + FILE *file = fopen(resolved_path, "r"); if (!file) { return api::throw_error(cx, ScriptLoaderErrors::ModuleLoadingError, @@ -430,36 +453,32 @@ bool ScriptLoader::load_resolved_script(JSContext *cx, const char *specifier, return script.init(cx, std::move(buf), len); } -bool ScriptLoader::load_script(JSContext *cx, const char *script_path, +bool ScriptLoader::load_script(JSContext *cx, std::string_view path, JS::SourceText &script) { - const char *resolved_path; - if (!BASE_PATH) { - auto last_slash = strrchr(script_path, '/'); - size_t base_len; - if (last_slash) { - last_slash++; - base_len = last_slash - script_path; - BASE_PATH = new char[base_len + 1]; - MOZ_ASSERT(BASE_PATH); - strncpy(BASE_PATH, script_path, base_len); - BASE_PATH[base_len] = '\0'; + + std::string resolved; + if (BASE_PATH.empty()) { + auto pos = path.find_last_of('/'); + if (pos != std::string::npos) { + BASE_PATH = path.substr(0, pos + 1); } else { - BASE_PATH = strdup("./"); + BASE_PATH = "./"; } - resolved_path = script_path; + resolved = path; } else { - resolved_path = resolve_path(script_path, BASE_PATH, strlen(BASE_PATH)); + resolved = resolve_path(path, BASE_PATH); } - - return load_resolved_script(cx, script_path, resolved_path, script); + return load_resolved_script(cx, path, resolved, script); } -bool ScriptLoader::eval_top_level_script(const char *path, JS::SourceText &source, +bool ScriptLoader::eval_top_level_script(std::string_view path, JS::SourceText &source, MutableHandleValue result, MutableHandleValue tla_promise) { JSContext *cx = ENGINE->cx(); JS::CompileOptions opts(cx, *COMPILE_OPTS); - opts.setFileAndLine(strip_prefix(path, PATH_PREFIX), 1); + auto stripped = strip_prefix(path, PATH_PREFIX); + opts.setFileAndLine(stripped.c_str(), 1); + JS::RootedScript script(cx); RootedObject module(cx); if (MODULE_MODE) { diff --git a/runtime/script_loader.h b/runtime/script_loader.h index 4b872acc..a1588716 100644 --- a/runtime/script_loader.h +++ b/runtime/script_loader.h @@ -3,26 +3,31 @@ #include -// TODO: remove these once the warnings are fixed -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" -#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" #include #include #include -#pragma clang diagnostic pop class ScriptLoader { public: ScriptLoader(api::Engine *engine, JS::CompileOptions *opts, mozilla::Maybe path_prefix); + + ScriptLoader(const ScriptLoader &) = default; + ScriptLoader(ScriptLoader &&) = delete; + + ScriptLoader &operator=(const ScriptLoader &) = default; + ScriptLoader &operator=(ScriptLoader &&) = delete; + ~ScriptLoader(); - bool define_builtin_module(const char* id, HandleValue builtin); - void enable_module_mode(bool enable); - bool eval_top_level_script(const char *path, JS::SourceText &source, - MutableHandleValue result, MutableHandleValue tla_promise); - bool load_script(JSContext* cx, const char *script_path, JS::SourceText &script); + static bool define_builtin_module(const char* id, HandleValue builtin); + static void enable_module_mode(bool enable); + + static bool eval_top_level_script(std::string_view path, JS::SourceText &source, + MutableHandleValue result, MutableHandleValue tla_promise); + + static bool load_script(JSContext *cx, std::string_view script_path, + JS::SourceText &script); /** * Load a script without attempting to resolve its path relative to a base path. @@ -30,8 +35,9 @@ class ScriptLoader { * This is useful for loading ancillary scripts without interfering with, or depending on, * the script loader's state as determined by loading and running content scripts. */ - bool load_resolved_script(JSContext *cx, const char *specifier, const char *resolved_path, - JS::SourceText &script); + static bool load_resolved_script(JSContext *cx, std::string_view specifier, + std::string_view resolved_path, + JS::SourceText &script); }; #endif //SCRIPTLOADER_H diff --git a/runtime/sequence.hpp b/runtime/sequence.hpp index 358d2151..913e5509 100644 --- a/runtime/sequence.hpp +++ b/runtime/sequence.hpp @@ -1,15 +1,11 @@ #ifndef JS_COMPUTE_RUNTIME_SEQUENCE_HPP #define JS_COMPUTE_RUNTIME_SEQUENCE_HPP -// TODO: remove these once the warnings are fixed -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winvalid-offsetof" #include "js/ForOfIterator.h" #include "jsapi.h" #include "jsfriendapi.h" #include -#pragma clang diagnostic pop namespace core { @@ -31,8 +27,9 @@ bool maybe_consume_sequence_or_record(JSContext *cx, JS::HandleValue initv, JS:: // First, try consuming args[0] as a sequence>. JS::ForOfIterator it(cx); - if (!it.init(initv, JS::ForOfIterator::AllowNonIterable)) + if (!it.init(initv, JS::ForOfIterator::AllowNonIterable)) { return false; + } // Note: this currently doesn't treat strings as iterable even though they // are. We don't have any constructors that want to iterate over strings, and @@ -41,50 +38,63 @@ bool maybe_consume_sequence_or_record(JSContext *cx, JS::HandleValue initv, JS:: JS::RootedValue entry(cx); while (true) { - bool done; - if (!it.next(&entry, &done)) + bool done = false; + if (!it.next(&entry, &done)) { return false; + } - if (done) + if (done) { break; + } - if (!entry.isObject()) + if (!entry.isObject()) { return api::throw_error(cx, api::Errors::InvalidSequence, ctor_name, alt_text); + } JS::ForOfIterator entr_iter(cx); - if (!entr_iter.init(entry, JS::ForOfIterator::AllowNonIterable)) + if (!entr_iter.init(entry, JS::ForOfIterator::AllowNonIterable)) { return false; + } - if (!entr_iter.valueIsIterable()) + if (!entr_iter.valueIsIterable()) { return api::throw_error(cx, api::Errors::InvalidSequence, ctor_name, alt_text); + } { - bool done; + bool done = false; // Extract key. - if (!entr_iter.next(&key, &done)) + if (!entr_iter.next(&key, &done)) { return false; - if (done) + } + if (done) { return api::throw_error(cx, api::Errors::InvalidSequence, ctor_name, alt_text); + } T validated_key = validate(cx, key, ctor_name); - if (!validated_key) + if (!validated_key) { return false; + } // Extract value. - if (!entr_iter.next(&value, &done)) + if (!entr_iter.next(&value, &done)) { return false; - if (done) + } + if (done) { return api::throw_error(cx, api::Errors::InvalidSequence, ctor_name, alt_text); + } // Ensure that there aren't any further entries. - if (!entr_iter.next(&entry, &done)) + if (!entr_iter.next(&entry, &done)) { return false; - if (!done) + } + if (!done) { return api::throw_error(cx, api::Errors::InvalidSequence, ctor_name, alt_text); + } - if (!apply(cx, target, std::move(validated_key), value, ctor_name)) + if (!apply(cx, target, std::move(validated_key), value, ctor_name)) { return false; + } } } *consumed = true; @@ -93,8 +103,9 @@ bool maybe_consume_sequence_or_record(JSContext *cx, JS::HandleValue initv, JS:: // valid input, following https://webidl.spec.whatwg.org/#js-record exactly. JS::RootedObject init(cx, &initv.toObject()); JS::RootedIdVector ids(cx); - if (!js::GetPropertyKeys(cx, init, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &ids)) + if (!js::GetPropertyKeys(cx, init, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &ids)) { return false; + } JS::RootedId curId(cx); @@ -103,18 +114,23 @@ bool maybe_consume_sequence_or_record(JSContext *cx, JS::HandleValue initv, JS:: for (size_t i = 0; i < ids.length(); ++i) { curId = ids[i]; key = js::IdToValue(curId); - if (!JS_GetOwnPropertyDescriptorById(cx, init, curId, &desc)) + if (!JS_GetOwnPropertyDescriptorById(cx, init, curId, &desc)) { return false; - if (desc.isNothing() || !desc->enumerable()) + } + if (desc.isNothing() || !desc->enumerable()) { continue; + } // Get call is observable and must come after any value validation T validated_key = validate(cx, key, ctor_name); - if (!validated_key) + if (!validated_key) { return false; - if (!JS_GetPropertyById(cx, init, curId, &value)) + } + if (!JS_GetPropertyById(cx, init, curId, &value)) { return false; - if (!apply(cx, target, std::move(validated_key), value, ctor_name)) + } + if (!apply(cx, target, std::move(validated_key), value, ctor_name)) { return false; + } } *consumed = true; } else {