diff --git a/Makefile b/Makefile index 36ab87f0bdf420..4640338f936b7e 100644 --- a/Makefile +++ b/Makefile @@ -174,7 +174,7 @@ with-code-cache test-code-cache: out/Makefile: config.gypi common.gypi node.gyp \ deps/uv/uv.gyp deps/llhttp/llhttp.gyp deps/zlib/zlib.gyp \ - deps/simdutf/simdutf.gyp deps/ada/ada.gyp \ + deps/simdutf/simdutf.gyp deps/ada/ada.gyp deps/nbytes/nbytes.gyp \ tools/v8_gypfiles/toolchain.gypi tools/v8_gypfiles/features.gypi \ tools/v8_gypfiles/inspector.gypi tools/v8_gypfiles/v8.gyp $(PYTHON) tools/gyp_node.py -f make diff --git a/deps/nbytes/README.md b/deps/nbytes/README.md new file mode 100644 index 00000000000000..9ff412adb30560 --- /dev/null +++ b/deps/nbytes/README.md @@ -0,0 +1,5 @@ +# Node.js bytes (nbytes) library + +The `nbytes` library extracts certain Node.js specific byte manipulation +functions from the core of Node.js itself and makes them available for +use in other projects that need to emulate Node.js' behavior. diff --git a/deps/nbytes/nbytes.cpp b/deps/nbytes/nbytes.cpp new file mode 100644 index 00000000000000..4eb4b6e6aa72a8 --- /dev/null +++ b/deps/nbytes/nbytes.cpp @@ -0,0 +1,251 @@ +#include "nbytes.h" +#include +#include +#include + +namespace nbytes { + +// ============================================================================ +// Byte Swapping + +namespace { +// These are defined by or on some systems. +// To avoid warnings, undefine them before redefining them. +#ifdef BSWAP_2 +# undef BSWAP_2 +#endif +#ifdef BSWAP_4 +# undef BSWAP_4 +#endif +#ifdef BSWAP_8 +# undef BSWAP_8 +#endif + +#if defined(_MSC_VER) +#include +#define BSWAP_2(x) _byteswap_ushort(x) +#define BSWAP_4(x) _byteswap_ulong(x) +#define BSWAP_8(x) _byteswap_uint64(x) +#else +#define BSWAP_2(x) ((x) << 8) | ((x) >> 8) +#define BSWAP_4(x) \ + (((x) & 0xFF) << 24) | \ + (((x) & 0xFF00) << 8) | \ + (((x) >> 8) & 0xFF00) | \ + (((x) >> 24) & 0xFF) +#define BSWAP_8(x) \ + (((x) & 0xFF00000000000000ull) >> 56) | \ + (((x) & 0x00FF000000000000ull) >> 40) | \ + (((x) & 0x0000FF0000000000ull) >> 24) | \ + (((x) & 0x000000FF00000000ull) >> 8) | \ + (((x) & 0x00000000FF000000ull) << 8) | \ + (((x) & 0x0000000000FF0000ull) << 24) | \ + (((x) & 0x000000000000FF00ull) << 40) | \ + (((x) & 0x00000000000000FFull) << 56) +#endif +} // namespace + +bool SwapBytes16(void* data, size_t nbytes) { + if (nbytes % sizeof(uint16_t) != 0) return false; + +#if defined(_MSC_VER) + if (AlignUp(data, sizeof(uint16_t)) == data) { + // MSVC has no strict aliasing, and is able to highly optimize this case. + uint16_t* data16 = reinterpret_cast(data); + size_t len16 = nbytes / sizeof(uint16_t); + for (size_t i = 0; i < len16; i++) { + data16[i] = BSWAP_2(data16[i]); + } + return true; + } +#endif + + uint16_t temp; + uint8_t* ptr = reinterpret_cast(data); + for (size_t i = 0; i < nbytes; i += sizeof(uint16_t)) { + memcpy(&temp, &ptr[i], sizeof(uint16_t)); + temp = BSWAP_2(temp); + memcpy(&ptr[i], &temp, sizeof(uint16_t)); + } + + return true; +} + +bool SwapBytes32(void* data, size_t nbytes) { + if (nbytes % sizeof(uint32_t) != 0) return false; + +#if defined(_MSC_VER) + // MSVC has no strict aliasing, and is able to highly optimize this case. + if (AlignUp(data, sizeof(uint32_t)) == data) { + uint32_t* data32 = reinterpret_cast(data); + size_t len32 = nbytes / sizeof(uint32_t); + for (size_t i = 0; i < len32; i++) { + data32[i] = BSWAP_4(data32[i]); + } + return true; + } +#endif + + uint32_t temp = 0; + uint8_t* ptr = reinterpret_cast(data); + for (size_t i = 0; i < nbytes; i += sizeof(uint32_t)) { + memcpy(&temp, &ptr[i], sizeof(uint32_t)); + temp = BSWAP_4(temp); + memcpy(&ptr[i], &temp, sizeof(uint32_t)); + } + + return true; +} + +bool SwapBytes64(void* data, size_t nbytes) { + if (nbytes % sizeof(uint64_t) != 0) return false; + +#if defined(_MSC_VER) + if (AlignUp(data, sizeof(uint64_t)) == data) { + // MSVC has no strict aliasing, and is able to highly optimize this case. + uint64_t* data64 = reinterpret_cast(data); + size_t len64 = nbytes / sizeof(uint64_t); + for (size_t i = 0; i < len64; i++) { + data64[i] = BSWAP_8(data64[i]); + } + return true; + } +#endif + + uint64_t temp = 0; + uint8_t* ptr = reinterpret_cast(data); + for (size_t i = 0; i < nbytes; i += sizeof(uint64_t)) { + memcpy(&temp, &ptr[i], sizeof(uint64_t)); + temp = BSWAP_8(temp); + memcpy(&ptr[i], &temp, sizeof(uint64_t)); + } + + return true; +} + +// ============================================================================ +// Base64 (legacy) + +// supports regular and URL-safe base64 +const int8_t unbase64_table[256] = + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, -2, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + +// ============================================================================ +// Hex + +const int8_t unhex_table[256] = + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + +size_t HexEncode( + const char* src, + size_t slen, + char* dst, + size_t dlen) { + // We know how much we'll write, just make sure that there's space. + NBYTES_ASSERT_TRUE( + dlen >= MultiplyWithOverflowCheck(slen, 2u) && + "not enough space provided for hex encode"); + + dlen = slen * 2; + for (size_t i = 0, k = 0; k < dlen; i += 1, k += 2) { + static const char hex[] = "0123456789abcdef"; + uint8_t val = static_cast(src[i]); + dst[k + 0] = hex[val >> 4]; + dst[k + 1] = hex[val & 15]; + } + + return dlen; +} + +std::string HexEncode(const char* src, size_t slen) { + size_t dlen = slen * 2; + std::string dst(dlen, '\0'); + HexEncode(src, slen, dst.data(), dlen); + return dst; +} + +// ============================================================================ + +void ForceAsciiSlow(const char* src, char* dst, size_t len) { + for (size_t i = 0; i < len; ++i) { + dst[i] = src[i] & 0x7f; + } +} + +void ForceAscii(const char* src, char* dst, size_t len) { + if (len < 16) { + ForceAsciiSlow(src, dst, len); + return; + } + + const unsigned bytes_per_word = sizeof(uintptr_t); + const unsigned align_mask = bytes_per_word - 1; + const unsigned src_unalign = reinterpret_cast(src) & align_mask; + const unsigned dst_unalign = reinterpret_cast(dst) & align_mask; + + if (src_unalign > 0) { + if (src_unalign == dst_unalign) { + const unsigned unalign = bytes_per_word - src_unalign; + ForceAsciiSlow(src, dst, unalign); + src += unalign; + dst += unalign; + len -= src_unalign; + } else { + ForceAsciiSlow(src, dst, len); + return; + } + } + +#if defined(_WIN64) || defined(_LP64) + const uintptr_t mask = ~0x8080808080808080ll; +#else + const uintptr_t mask = ~0x80808080l; +#endif + + const uintptr_t* srcw = reinterpret_cast(src); + uintptr_t* dstw = reinterpret_cast(dst); + + for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) { + dstw[i] = srcw[i] & mask; + } + + const unsigned remainder = len & align_mask; + if (remainder > 0) { + const size_t offset = len - remainder; + ForceAsciiSlow(src + offset, dst + offset, remainder); + } +} + +} // namespace nbytes diff --git a/deps/nbytes/nbytes.gyp b/deps/nbytes/nbytes.gyp new file mode 100644 index 00000000000000..0c1b76752e98b5 --- /dev/null +++ b/deps/nbytes/nbytes.gyp @@ -0,0 +1,16 @@ +{ + 'variables': { + 'nbytes_sources': [ 'nbytes.cpp' ], + }, + 'targets': [ + { + 'target_name': 'nbytes', + 'type': 'static_library', + 'include_dirs': ['.'], + 'direct_dependent_settings': { + 'include_dirs': ['.'], + }, + 'sources': [ '<@(nbytes_sources)' ] + }, + ] +} diff --git a/src/string_search.h b/deps/nbytes/nbytes.h similarity index 68% rename from src/string_search.h rename to deps/nbytes/nbytes.h index cd9ef320a81112..7af92ddc3d538e 100644 --- a/src/string_search.h +++ b/deps/nbytes/nbytes.h @@ -1,18 +1,260 @@ -// Copyright 2011 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. +#pragma once -#ifndef SRC_STRING_SEARCH_H_ -#define SRC_STRING_SEARCH_H_ +#include +#include +#include +#include +#include +#include + +namespace nbytes { + +#if NBYTES_DEVELOPMENT_CHECKS +#define NBYTES_STR(x) #x +#define NBYTES_REQUIRE(EXPR) \ + { \ + if (!(EXPR) { abort(); }) } + +#define NBYTES_FAIL(MESSAGE) \ + do { \ + std::cerr << "FAIL: " << (MESSAGE) << std::endl; \ + abort(); \ + } while (0); +#define NBYTES_ASSERT_EQUAL(LHS, RHS, MESSAGE) \ + do { \ + if (LHS != RHS) { \ + std::cerr << "Mismatch: '" << LHS << "' - '" << RHS << "'" << std::endl; \ + NBYTES_FAIL(MESSAGE); \ + } \ + } while (0); +#define NBYTES_ASSERT_TRUE(COND) \ + do { \ + if (!(COND)) { \ + std::cerr << "Assert at line " << __LINE__ << " of file " << __FILE__ \ + << std::endl; \ + NBYTES_FAIL(NBYTES_STR(COND)); \ + } \ + } while (0); +#else +#define NBYTES_FAIL(MESSAGE) +#define NBYTES_ASSERT_EQUAL(LHS, RHS, MESSAGE) +#define NBYTES_ASSERT_TRUE(COND) +#endif -#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS +[[noreturn]] inline void unreachable() { +#ifdef __GNUC__ + __builtin_unreachable(); +#elif defined(_MSC_VER) + __assume(false); +#else +#endif +} -#include "util.h" +// The nbytes (short for "node bytes") is a set of utility helpers for +// working with bytes that are extracted from Node.js' internals. The +// motivation for extracting these into a separate library is to make it +// easier for other projects to implement functionality that is compatible +// with Node.js' implementation of various byte manipulation functions. -#include -#include +// Round up a to the next highest multiple of b. +template +constexpr T RoundUp(T a, T b) { + return a % b != 0 ? a + b - (a % b) : a; +} + +// Align ptr to an `alignment`-bytes boundary. +template +constexpr T* AlignUp(T* ptr, U alignment) { + return reinterpret_cast( + RoundUp(reinterpret_cast(ptr), alignment)); +} + +template +inline T AlignDown(T value, U alignment) { + return reinterpret_cast( + (reinterpret_cast(value) & ~(alignment - 1))); +} + +template +inline T MultiplyWithOverflowCheck(T a, T b) { + auto ret = a * b; + if (a != 0) { + NBYTES_ASSERT_TRUE(b == ret / a); + } + + return ret; +} + +void ForceAsciiSlow(const char* src, char* dst, size_t len); +void ForceAscii(const char* src, char* dst, size_t len); + +// ============================================================================ +// Byte Swapping + +// Swaps bytes in place. nbytes is the number of bytes to swap and must be a +// multiple of the word size (checked by function). +bool SwapBytes16(void* data, size_t nbytes); +bool SwapBytes32(void* data, size_t nbytes); +bool SwapBytes64(void* data, size_t nbytes); + +// ============================================================================ +// Base64 (legacy) + +#ifdef _MSC_VER +#pragma warning(push) +// MSVC C4003: not enough actual parameters for macro 'identifier' +#pragma warning(disable : 4003) +#endif + +extern const int8_t unbase64_table[256]; + +template +bool Base64DecodeGroupSlow(char* const dst, const size_t dstlen, + const TypeName* const src, const size_t srclen, + size_t* const i, size_t* const k) { + uint8_t hi; + uint8_t lo; +#define V(expr) \ + for (;;) { \ + const uint8_t c = static_cast(src[*i]); \ + lo = unbase64_table[c]; \ + *i += 1; \ + if (lo < 64) break; /* Legal character. */ \ + if (c == '=' || *i >= srclen) return false; /* Stop decoding. */ \ + } \ + expr; \ + if (*i >= srclen) return false; \ + if (*k >= dstlen) return false; \ + hi = lo; + V(/* Nothing. */); + V(dst[(*k)++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4)); + V(dst[(*k)++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2)); + V(dst[(*k)++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0)); +#undef V + return true; // Continue decoding. +} + +enum class Base64Mode { + NORMAL, + URL +}; + +inline constexpr size_t Base64EncodedSize( + size_t size, + Base64Mode mode = Base64Mode::NORMAL) { + return mode == Base64Mode::NORMAL ? ((size + 2) / 3 * 4) + : static_cast(std::ceil( + static_cast(size * 4) / 3)); +} + +// Doesn't check for padding at the end. Can be 1-2 bytes over. +inline constexpr size_t Base64DecodedSizeFast(size_t size) { + // 1-byte input cannot be decoded + return size > 1 ? (size / 4) * 3 + (size % 4 + 1) / 2 : 0; +} + +inline uint32_t ReadUint32BE(const unsigned char* p) { + return static_cast(p[0] << 24U) | + static_cast(p[1] << 16U) | + static_cast(p[2] << 8U) | + static_cast(p[3]); +} + +template +size_t Base64DecodedSize(const TypeName* src, size_t size) { + // 1-byte input cannot be decoded + if (size < 2) + return 0; + + if (src[size - 1] == '=') { + size--; + if (src[size - 1] == '=') + size--; + } + return Base64DecodedSizeFast(size); +} + +template +size_t Base64DecodeFast(char* const dst, const size_t dstlen, + const TypeName* const src, const size_t srclen, + const size_t decoded_size) { + const size_t available = dstlen < decoded_size ? dstlen : decoded_size; + const size_t max_k = available / 3 * 3; + size_t max_i = srclen / 4 * 4; + size_t i = 0; + size_t k = 0; + while (i < max_i && k < max_k) { + const unsigned char txt[] = { + static_cast(unbase64_table[static_cast(src[i + 0])]), + static_cast(unbase64_table[static_cast(src[i + 1])]), + static_cast(unbase64_table[static_cast(src[i + 2])]), + static_cast(unbase64_table[static_cast(src[i + 3])]), + }; + + const uint32_t v = ReadUint32BE(txt); + // If MSB is set, input contains whitespace or is not valid base64. + if (v & 0x80808080) { + if (!Base64DecodeGroupSlow(dst, dstlen, src, srclen, &i, &k)) + return k; + max_i = i + (srclen - i) / 4 * 4; // Align max_i again. + } else { + dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03); + dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F); + dst[k + 2] = ((v >> 2) & 0xC0) | ((v >> 0) & 0x3F); + i += 4; + k += 3; + } + } + if (i < srclen && k < dstlen) { + Base64DecodeGroupSlow(dst, dstlen, src, srclen, &i, &k); + } + return k; +} + +template +size_t Base64Decode(char* const dst, const size_t dstlen, + const TypeName* const src, const size_t srclen) { + const size_t decoded_size = Base64DecodedSize(src, srclen); + return Base64DecodeFast(dst, dstlen, src, srclen, decoded_size); +} + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// ============================================================================ +// Hex (legacy) + +extern const int8_t unhex_table[256]; + +template +static size_t HexDecode(char* buf, + size_t len, + const TypeName* src, + const size_t srcLen) { + size_t i; + for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) { + unsigned a = unhex_table[static_cast(src[i * 2 + 0])]; + unsigned b = unhex_table[static_cast(src[i * 2 + 1])]; + if (!~a || !~b) + return i; + buf[i] = (a << 4) | b; + } + + return i; +} + +size_t HexEncode( + const char* src, + size_t slen, + char* dst, + size_t dlen); + +std::string HexEncode(const char* src, size_t slen); + +// ============================================================================ +// StringSearch -namespace node { namespace stringsearch { template @@ -36,7 +278,7 @@ class Vector { // Access individual vector elements - checks bounds in debug mode. T& operator[](size_t index) const { - DCHECK_LT(index, length_); + NBYTES_ASSERT_TRUE(index < length_); return start_[is_forward_ ? index : (length_ - index - 1)]; } @@ -46,7 +288,6 @@ class Vector { bool is_forward_; }; - //--------------------------------------------------------------------- // String Search object. //--------------------------------------------------------------------- @@ -97,7 +338,7 @@ class StringSearch : private StringSearchBase { } size_t pattern_length = pattern_.length(); - CHECK_GT(pattern_length, 0); + NBYTES_ASSERT_TRUE(pattern_length > 0); if (pattern_length < kBMMinPatternLength) { if (pattern_length == 1) { strategy_ = SearchStrategy::kSingleChar; @@ -122,7 +363,7 @@ class StringSearch : private StringSearchBase { case kSingleChar: return SingleCharSearch(subject, index); } - UNREACHABLE(); + unreachable(); } static inline int AlphabetSize() { @@ -176,23 +417,13 @@ class StringSearch : private StringSearchBase { size_t start_; }; - -template -inline T AlignDown(T value, U alignment) { - return reinterpret_cast( - (reinterpret_cast(value) & ~(alignment - 1))); -} - - inline uint8_t GetHighestValueByte(uint16_t character) { return std::max(static_cast(character & 0xFF), static_cast(character >> 8)); } - inline uint8_t GetHighestValueByte(uint8_t character) { return character; } - // Searches for a byte value in a memory buffer, back to front. // Uses memrchr(3) on systems which support it, for speed. // Falls back to a vanilla for loop on non-GNU systems such as Windows. @@ -211,7 +442,6 @@ inline const void* MemrchrFill(const void* haystack, uint8_t needle, #endif } - // Finds the first occurrence of *two-byte* character pattern[0] in the string // `subject`. Does not check that the whole pattern matches. template @@ -229,12 +459,12 @@ inline size_t FindFirstCharacter(Vector pattern, const void* void_pos; if (subject.forward()) { // Assert that bytes_to_search won't overflow - CHECK_LE(pos, max_n); - CHECK_LE(max_n - pos, SIZE_MAX / sizeof(Char)); + NBYTES_ASSERT_TRUE(pos <= max_n); + NBYTES_ASSERT_TRUE(max_n - pos <= SIZE_MAX / sizeof(Char)); void_pos = memchr(subject.start() + pos, search_byte, bytes_to_search); } else { - CHECK_LE(pos, subject.length()); - CHECK_LE(subject.length() - pos, SIZE_MAX / sizeof(Char)); + NBYTES_ASSERT_TRUE(pos <= subject.length()); + NBYTES_ASSERT_TRUE(subject.length() - pos <= SIZE_MAX / sizeof(Char)); void_pos = MemrchrFill(subject.start() + pattern.length() - 1, search_byte, bytes_to_search); @@ -257,7 +487,6 @@ inline size_t FindFirstCharacter(Vector pattern, return subject.length(); } - // Finds the first occurrence of the byte pattern[0] in string `subject`. // Does not verify that the whole pattern matches. template <> @@ -293,7 +522,7 @@ template size_t StringSearch::SingleCharSearch( Vector subject, size_t index) { - CHECK_EQ(1, pattern_.length()); + NBYTES_ASSERT_TRUE(1 == pattern_.length()); return FindFirstCharacter(pattern_, subject, index); } @@ -306,13 +535,13 @@ template size_t StringSearch::LinearSearch( Vector subject, size_t index) { - CHECK_GT(pattern_.length(), 1); + NBYTES_ASSERT_TRUE(pattern_.length() > 1); const size_t n = subject.length() - pattern_.length(); for (size_t i = index; i <= n; i++) { i = FindFirstCharacter(pattern_, subject, i); if (i == subject.length()) return subject.length(); - CHECK_LE(i, n); + NBYTES_ASSERT_TRUE(i <= n); bool matches = true; for (size_t j = 1; j < pattern_.length(); j++) { @@ -553,7 +782,7 @@ size_t StringSearch::InitialSearch( i = FindFirstCharacter(pattern_, subject, i); if (i == subject.length()) return subject.length(); - CHECK_LE(i, n); + NBYTES_ASSERT_TRUE(i <= n); size_t j = 1; do { if (pattern_[j] != subject[i + j]) { @@ -586,9 +815,6 @@ size_t SearchString(Vector subject, return search.Search(subject, start_index); } } // namespace stringsearch -} // namespace node - -namespace node { template size_t SearchString(const Char* haystack, @@ -614,7 +840,7 @@ size_t SearchString(const Char* haystack, } else { relative_start_index = diff - start_index; } - size_t pos = node::stringsearch::SearchString( + size_t pos = stringsearch::SearchString( v_haystack, v_needle, relative_start_index); if (pos == haystack_length) { // not found @@ -631,8 +857,14 @@ size_t SearchString(const char* haystack, size_t haystack_length, reinterpret_cast(needle), N - 1, 0, true); } -} // namespace node +// ============================================================================ +// Version metadata +#define NBYTES_VERSION "0.0.1" -#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS +enum { + NBYTES_VERSION_MAJOR = 0, + NBYTES_VERSION_MINOR = 0, + NBYTES_VERSION_REVISION = 1, +}; -#endif // SRC_STRING_SEARCH_H_ +} // namespace nbytes diff --git a/node.gyp b/node.gyp index 8ca56d52d73d60..0685742e8165fa 100644 --- a/node.gyp +++ b/node.gyp @@ -187,8 +187,6 @@ 'src/base_object.h', 'src/base_object-inl.h', 'src/base_object_types.h', - 'src/base64.h', - 'src/base64-inl.h', 'src/blob_serializer_deserializer.h', 'src/blob_serializer_deserializer-inl.h', 'src/callback_queue.h', @@ -293,7 +291,6 @@ 'src/string_bytes.h', 'src/string_decoder.h', 'src/string_decoder-inl.h', - 'src/string_search.h', 'src/tcp_wrap.h', 'src/timers.h', 'src/tracing/agent.h', @@ -845,6 +842,7 @@ 'deps/simdjson/simdjson.gyp:simdjson', 'deps/simdutf/simdutf.gyp:simdutf', 'deps/ada/ada.gyp:ada', + 'deps/nbytes/nbytes.gyp:nbytes', 'node_js2c#host', ], @@ -1120,6 +1118,7 @@ 'deps/sqlite/sqlite.gyp:sqlite', 'deps/uvwasi/uvwasi.gyp:uvwasi', 'deps/ada/ada.gyp:ada', + 'deps/nbytes/nbytes.gyp:nbytes', ], 'includes': [ 'node.gypi' @@ -1170,6 +1169,7 @@ 'deps/simdjson/simdjson.gyp:simdjson', 'deps/simdutf/simdutf.gyp:simdutf', 'deps/ada/ada.gyp:ada', + 'deps/nbytes/nbytes.gyp:nbytes', ], 'includes': [ @@ -1246,6 +1246,7 @@ 'deps/histogram/histogram.gyp:histogram', 'deps/sqlite/sqlite.gyp:sqlite', 'deps/ada/ada.gyp:ada', + 'deps/nbytes/nbytes.gyp:nbytes', ], 'includes': [ @@ -1361,6 +1362,7 @@ 'deps/histogram/histogram.gyp:histogram', 'deps/sqlite/sqlite.gyp:sqlite', 'deps/ada/ada.gyp:ada', + 'deps/nbytes/nbytes.gyp:nbytes', 'deps/simdjson/simdjson.gyp:simdjson', 'deps/simdutf/simdutf.gyp:simdutf', ], diff --git a/src/base64-inl.h b/src/base64-inl.h deleted file mode 100644 index 20a2f233ae9f35..00000000000000 --- a/src/base64-inl.h +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef SRC_BASE64_INL_H_ -#define SRC_BASE64_INL_H_ - -#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS - -#include "base64.h" -#include "util.h" - -namespace node { - -extern const int8_t unbase64_table[256]; - - -inline static int8_t unbase64(uint8_t x) { - return unbase64_table[x]; -} - - -inline uint32_t ReadUint32BE(const unsigned char* p) { - return static_cast(p[0] << 24U) | - static_cast(p[1] << 16U) | - static_cast(p[2] << 8U) | - static_cast(p[3]); -} - -#ifdef _MSC_VER -#pragma warning(push) -// MSVC C4003: not enough actual parameters for macro 'identifier' -#pragma warning(disable : 4003) -#endif - -template -bool base64_decode_group_slow(char* const dst, const size_t dstlen, - const TypeName* const src, const size_t srclen, - size_t* const i, size_t* const k) { - uint8_t hi; - uint8_t lo; -#define V(expr) \ - for (;;) { \ - const uint8_t c = static_cast(src[*i]); \ - lo = unbase64(c); \ - *i += 1; \ - if (lo < 64) break; /* Legal character. */ \ - if (c == '=' || *i >= srclen) return false; /* Stop decoding. */ \ - } \ - expr; \ - if (*i >= srclen) return false; \ - if (*k >= dstlen) return false; \ - hi = lo; - V(/* Nothing. */); - V(dst[(*k)++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4)); - V(dst[(*k)++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2)); - V(dst[(*k)++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0)); -#undef V - return true; // Continue decoding. -} - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -template -size_t base64_decode_fast(char* const dst, const size_t dstlen, - const TypeName* const src, const size_t srclen, - const size_t decoded_size) { - const size_t available = dstlen < decoded_size ? dstlen : decoded_size; - const size_t max_k = available / 3 * 3; - size_t max_i = srclen / 4 * 4; - size_t i = 0; - size_t k = 0; - while (i < max_i && k < max_k) { - const unsigned char txt[] = { - static_cast(unbase64(static_cast(src[i + 0]))), - static_cast(unbase64(static_cast(src[i + 1]))), - static_cast(unbase64(static_cast(src[i + 2]))), - static_cast(unbase64(static_cast(src[i + 3]))), - }; - - const uint32_t v = ReadUint32BE(txt); - // If MSB is set, input contains whitespace or is not valid base64. - if (v & 0x80808080) { - if (!base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k)) - return k; - max_i = i + (srclen - i) / 4 * 4; // Align max_i again. - } else { - dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03); - dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F); - dst[k + 2] = ((v >> 2) & 0xC0) | ((v >> 0) & 0x3F); - i += 4; - k += 3; - } - } - if (i < srclen && k < dstlen) { - base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k); - } - return k; -} - - -template -size_t base64_decoded_size(const TypeName* src, size_t size) { - // 1-byte input cannot be decoded - if (size < 2) - return 0; - - if (src[size - 1] == '=') { - size--; - if (src[size - 1] == '=') - size--; - } - return base64_decoded_size_fast(size); -} - - -template -size_t base64_decode(char* const dst, const size_t dstlen, - const TypeName* const src, const size_t srclen) { - const size_t decoded_size = base64_decoded_size(src, srclen); - return base64_decode_fast(dst, dstlen, src, srclen, decoded_size); -} - -} // namespace node - -#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS - -#endif // SRC_BASE64_INL_H_ diff --git a/src/base64.h b/src/base64.h deleted file mode 100644 index c59a8bb50637c8..00000000000000 --- a/src/base64.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef SRC_BASE64_H_ -#define SRC_BASE64_H_ - -#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS - -#include "util.h" - -#include -#include -#include - -namespace node { -//// Base 64 //// - -enum class Base64Mode { - NORMAL, - URL -}; - -static inline constexpr size_t base64_encoded_size( - size_t size, - Base64Mode mode = Base64Mode::NORMAL) { - return mode == Base64Mode::NORMAL ? ((size + 2) / 3 * 4) - : static_cast(std::ceil( - static_cast(size * 4) / 3)); -} - -// Doesn't check for padding at the end. Can be 1-2 bytes over. -static inline constexpr size_t base64_decoded_size_fast(size_t size) { - // 1-byte input cannot be decoded - return size > 1 ? (size / 4) * 3 + (size % 4 + 1) / 2 : 0; -} - -inline uint32_t ReadUint32BE(const unsigned char* p); - -template -size_t base64_decoded_size(const TypeName* src, size_t size); - -template -size_t base64_decode(char* const dst, - const size_t dstlen, - const TypeName* const src, - const size_t srclen); -} // namespace node - - -#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS - -#endif // SRC_BASE64_H_ diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index 299802238732df..26877f3ddd8f69 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -22,10 +22,10 @@ #include "cares_wrap.h" #include "ada.h" #include "async_wrap-inl.h" -#include "base64-inl.h" #include "base_object-inl.h" #include "env-inl.h" #include "memory_tracker-inl.h" +#include "nbytes.h" #include "node.h" #include "node_errors.h" #include "node_external_reference.h" @@ -591,11 +591,11 @@ int ParseSoaReply( return ARES_EBADRESP; } - const unsigned int serial = ReadUint32BE(ptr + 0 * 4); - const unsigned int refresh = ReadUint32BE(ptr + 1 * 4); - const unsigned int retry = ReadUint32BE(ptr + 2 * 4); - const unsigned int expire = ReadUint32BE(ptr + 3 * 4); - const unsigned int minttl = ReadUint32BE(ptr + 4 * 4); + const unsigned int serial = nbytes::ReadUint32BE(ptr + 0 * 4); + const unsigned int refresh = nbytes::ReadUint32BE(ptr + 1 * 4); + const unsigned int retry = nbytes::ReadUint32BE(ptr + 2 * 4); + const unsigned int expire = nbytes::ReadUint32BE(ptr + 3 * 4); + const unsigned int minttl = nbytes::ReadUint32BE(ptr + 4 * 4); Local soa_record = Object::New(env->isolate()); soa_record->Set(env->context(), @@ -1801,7 +1801,7 @@ void SetLocalAddress(const FunctionCallbackInfo& args) { // to 0 (any). if (uv_inet_pton(AF_INET, *ip0, &addr0) == 0) { - ares_set_local_ip4(channel->cares_channel(), ReadUint32BE(addr0)); + ares_set_local_ip4(channel->cares_channel(), nbytes::ReadUint32BE(addr0)); type0 = 4; } else if (uv_inet_pton(AF_INET6, *ip0, &addr0) == 0) { ares_set_local_ip6(channel->cares_channel(), addr0); @@ -1820,7 +1820,8 @@ void SetLocalAddress(const FunctionCallbackInfo& args) { THROW_ERR_INVALID_ARG_VALUE(env, "Cannot specify two IPv4 addresses."); return; } else { - ares_set_local_ip4(channel->cares_channel(), ReadUint32BE(addr1)); + ares_set_local_ip4(channel->cares_channel(), + nbytes::ReadUint32BE(addr1)); } } else if (uv_inet_pton(AF_INET6, *ip1, &addr1) == 0) { if (type0 == 6) { diff --git a/src/crypto/crypto_common.cc b/src/crypto/crypto_common.cc index 962018583360a1..4da42cf4147bf6 100644 --- a/src/crypto/crypto_common.cc +++ b/src/crypto/crypto_common.cc @@ -2,6 +2,7 @@ #include "base_object-inl.h" #include "env-inl.h" #include "memory_tracker-inl.h" +#include "nbytes.h" #include "node.h" #include "node_buffer.h" #include "node_crypto.h" @@ -90,10 +91,10 @@ void LogSecret( } std::string line = name; - line += " " + StringBytes::hex_encode(reinterpret_cast(crandom), - kTlsClientRandomSize); - line += " " + StringBytes::hex_encode( - reinterpret_cast(secret), secretlen); + line += " " + nbytes::HexEncode(reinterpret_cast(crandom), + kTlsClientRandomSize); + line += + " " + nbytes::HexEncode(reinterpret_cast(secret), secretlen); keylog_cb(ssl.get(), line.c_str()); } diff --git a/src/inspector_socket.cc b/src/inspector_socket.cc index b6059b49410868..5246b9170a7a78 100644 --- a/src/inspector_socket.cc +++ b/src/inspector_socket.cc @@ -1,7 +1,7 @@ #include "inspector_socket.h" #include "llhttp.h" -#include "base64.h" +#include "nbytes.h" #include "simdutf.h" #include "util-inl.h" @@ -11,7 +11,7 @@ #include #include -#define ACCEPT_KEY_LENGTH base64_encoded_size(20) +#define ACCEPT_KEY_LENGTH nbytes::Base64EncodedSize(20) #define DUMP_READS 0 #define DUMP_WRITES 0 @@ -149,7 +149,7 @@ static void generate_accept_string(const std::string& client_key, std::string input(client_key + ws_magic); char hash[SHA_DIGEST_LENGTH]; - CHECK(ACCEPT_KEY_LENGTH >= base64_encoded_size(SHA_DIGEST_LENGTH) && + CHECK(ACCEPT_KEY_LENGTH >= nbytes::Base64EncodedSize(SHA_DIGEST_LENGTH) && "not enough space provided for base64 encode"); USE(SHA1(reinterpret_cast(input.data()), input.size(), diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 871324f687617a..02a6a79492cf12 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -30,13 +30,14 @@ #include "env-inl.h" #include "simdutf.h" #include "string_bytes.h" -#include "string_search.h" + #include "util-inl.h" #include "v8-fast-api-calls.h" #include "v8.h" -#include #include +#include +#include "nbytes.h" #define THROW_AND_RETURN_UNLESS_BUFFER(env, obj) \ THROW_AND_RETURN_IF_NOT_BUFFER(env, obj, "argument") \ @@ -667,7 +668,7 @@ void Fill(const FunctionCallbackInfo& args) { str_length = str_obj->Length() * sizeof(uint16_t); node::TwoByteValue str(env->isolate(), args[1]); if constexpr (IsBigEndian()) - SwapBytes16(reinterpret_cast(&str[0]), str_length); + CHECK(nbytes::SwapBytes16(reinterpret_cast(&str[0]), str_length)); memcpy(ts_obj_data + start, *str, std::min(str_length, fill_length)); @@ -969,19 +970,20 @@ void IndexOfString(const FunctionCallbackInfo& args) { if (decoded_string == nullptr) return args.GetReturnValue().Set(-1); - result = SearchString(reinterpret_cast(haystack), - haystack_length / 2, - decoded_string, - decoder.size() / 2, - offset / 2, - is_forward); + result = nbytes::SearchString(reinterpret_cast(haystack), + haystack_length / 2, + decoded_string, + decoder.size() / 2, + offset / 2, + is_forward); } else { - result = SearchString(reinterpret_cast(haystack), - haystack_length / 2, - reinterpret_cast(*needle_value), - needle_value.length(), - offset / 2, - is_forward); + result = + nbytes::SearchString(reinterpret_cast(haystack), + haystack_length / 2, + reinterpret_cast(*needle_value), + needle_value.length(), + offset / 2, + is_forward); } result *= 2; } else if (enc == UTF8) { @@ -989,12 +991,13 @@ void IndexOfString(const FunctionCallbackInfo& args) { if (*needle_value == nullptr) return args.GetReturnValue().Set(-1); - result = SearchString(reinterpret_cast(haystack), - haystack_length, - reinterpret_cast(*needle_value), - needle_length, - offset, - is_forward); + result = + nbytes::SearchString(reinterpret_cast(haystack), + haystack_length, + reinterpret_cast(*needle_value), + needle_length, + offset, + is_forward); } else if (enc == LATIN1) { uint8_t* needle_data = node::UncheckedMalloc(needle_length); if (needle_data == nullptr) { @@ -1003,12 +1006,12 @@ void IndexOfString(const FunctionCallbackInfo& args) { needle->WriteOneByte( isolate, needle_data, 0, needle_length, String::NO_NULL_TERMINATION); - result = SearchString(reinterpret_cast(haystack), - haystack_length, - needle_data, - needle_length, - offset, - is_forward); + result = nbytes::SearchString(reinterpret_cast(haystack), + haystack_length, + needle_data, + needle_length, + offset, + is_forward); free(needle_data); } @@ -1067,22 +1070,20 @@ void IndexOfBuffer(const FunctionCallbackInfo& args) { if (haystack_length < 2 || needle_length < 2) { return args.GetReturnValue().Set(-1); } - result = SearchString( - reinterpret_cast(haystack), - haystack_length / 2, - reinterpret_cast(needle), - needle_length / 2, - offset / 2, - is_forward); + result = nbytes::SearchString(reinterpret_cast(haystack), + haystack_length / 2, + reinterpret_cast(needle), + needle_length / 2, + offset / 2, + is_forward); result *= 2; } else { - result = SearchString( - reinterpret_cast(haystack), - haystack_length, - reinterpret_cast(needle), - needle_length, - offset, - is_forward); + result = nbytes::SearchString(reinterpret_cast(haystack), + haystack_length, + reinterpret_cast(needle), + needle_length, + offset, + is_forward); } args.GetReturnValue().Set( @@ -1105,7 +1106,7 @@ int32_t IndexOfNumber(const uint8_t* buffer_data, if (is_forward) { ptr = memchr(buffer_data + offset, needle, buffer_length - offset); } else { - ptr = node::stringsearch::MemrchrFill(buffer_data, needle, offset + 1); + ptr = nbytes::stringsearch::MemrchrFill(buffer_data, needle, offset + 1); } const uint8_t* ptr_uint8 = static_cast(ptr); return ptr != nullptr ? static_cast(ptr_uint8 - buffer_data) : -1; @@ -1145,7 +1146,7 @@ void Swap16(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]); SPREAD_BUFFER_ARG(args[0], ts_obj); - SwapBytes16(ts_obj_data, ts_obj_length); + CHECK(nbytes::SwapBytes16(ts_obj_data, ts_obj_length)); args.GetReturnValue().Set(args[0]); } @@ -1154,7 +1155,7 @@ void Swap32(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]); SPREAD_BUFFER_ARG(args[0], ts_obj); - SwapBytes32(ts_obj_data, ts_obj_length); + CHECK(nbytes::SwapBytes32(ts_obj_data, ts_obj_length)); args.GetReturnValue().Set(args[0]); } @@ -1163,7 +1164,7 @@ void Swap64(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]); SPREAD_BUFFER_ARG(args[0], ts_obj); - SwapBytes64(ts_obj_data, ts_obj_length); + CHECK(nbytes::SwapBytes64(ts_obj_data, ts_obj_length)); args.GetReturnValue().Set(args[0]); } diff --git a/src/node_http2.cc b/src/node_http2.cc index 56297ba2a3b909..50636d24763078 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -13,6 +13,8 @@ #include "stream_base-inl.h" #include "util-inl.h" +#include "nbytes.h" + #include #include #include @@ -455,8 +457,8 @@ Origins::Origins( } // Make sure the start address is aligned appropriately for an nghttp2_nv*. - char* start = AlignUp(static_cast(bs_->Data()), - alignof(nghttp2_origin_entry)); + char* start = nbytes::AlignUp(static_cast(bs_->Data()), + alignof(nghttp2_origin_entry)); char* origin_contents = start + (count_ * sizeof(nghttp2_origin_entry)); nghttp2_origin_entry* const nva = reinterpret_cast(start); diff --git a/src/node_http_common-inl.h b/src/node_http_common-inl.h index e78a6fdd2f95bd..dba1a5e051b3e0 100644 --- a/src/node_http_common-inl.h +++ b/src/node_http_common-inl.h @@ -8,6 +8,7 @@ #include "v8.h" #include +#include "nbytes.h" namespace node { @@ -31,7 +32,7 @@ NgHeaders::NgHeaders(Environment* env, v8::Local headers) { count_ * sizeof(nv_t) + header_string_len); - char* start = AlignUp(buf_.out(), alignof(nv_t)); + char* start = nbytes::AlignUp(buf_.out(), alignof(nv_t)); char* header_contents = start + (count_ * sizeof(nv_t)); nv_t* const nva = reinterpret_cast(start); diff --git a/src/node_i18n.cc b/src/node_i18n.cc index 743ea8c872cef4..7a13f35d2f2bcb 100644 --- a/src/node_i18n.cc +++ b/src/node_i18n.cc @@ -69,6 +69,7 @@ #include #include #include +#include "nbytes.h" #ifdef NODE_HAVE_SMALL_ICU /* if this is defined, we have a 'secondary' entry point. @@ -113,7 +114,7 @@ MaybeLocal ToBufferEndian(Environment* env, MaybeStackBuffer* buf) { "Currently only one- or two-byte buffers are supported"); if constexpr (sizeof(T) > 1 && IsBigEndian()) { SPREAD_BUFFER_ARG(ret.ToLocalChecked(), retbuf); - SwapBytes16(retbuf_data, retbuf_length); + CHECK(nbytes::SwapBytes16(retbuf_data, retbuf_length)); } return ret; @@ -129,7 +130,7 @@ void CopySourceBuffer(MaybeStackBuffer* dest, char* dst = reinterpret_cast(**dest); memcpy(dst, data, length); if constexpr (IsBigEndian()) { - SwapBytes16(dst, length); + CHECK(nbytes::SwapBytes16(dst, length)); } } @@ -528,7 +529,7 @@ void ConverterObject::Decode(const FunctionCallbackInfo& args) { char* value = reinterpret_cast(output) + beginning; if constexpr (IsBigEndian()) { - SwapBytes16(value, length); + CHECK(nbytes::SwapBytes16(value, length)); } MaybeLocal encoded = diff --git a/src/node_metadata.cc b/src/node_metadata.cc index 3b7493f82b91b8..937e415eb55857 100644 --- a/src/node_metadata.cc +++ b/src/node_metadata.cc @@ -5,6 +5,7 @@ #include "brotli/encode.h" #include "cjs_module_lexer_version.h" #include "llhttp.h" +#include "nbytes.h" #include "nghttp2/nghttp2ver.h" #include "node.h" #include "simdjson.h" @@ -133,6 +134,7 @@ Metadata::Versions::Versions() { simdutf = SIMDUTF_VERSION; sqlite = SQLITE_VERSION; ada = ADA_VERSION; + nbytes = NBYTES_VERSION; } Metadata::Release::Release() : name(NODE_RELEASE) { diff --git a/src/node_metadata.h b/src/node_metadata.h index 5400220424e8d7..90c7dbf22c8e85 100644 --- a/src/node_metadata.h +++ b/src/node_metadata.h @@ -50,6 +50,7 @@ namespace node { V(simdutf) \ V(sqlite) \ V(ada) \ + V(nbytes) \ NODE_VERSIONS_KEY_UNDICI(V) \ V(cjs_module_lexer) diff --git a/src/node_sockaddr.cc b/src/node_sockaddr.cc index 99af64d7259d48..e1572187437f1b 100644 --- a/src/node_sockaddr.cc +++ b/src/node_sockaddr.cc @@ -1,9 +1,10 @@ -#include "node_sockaddr-inl.h" // NOLINT(build/include) -#include "env-inl.h" -#include "base64-inl.h" +#include "node_sockaddr.h" // NOLINT(build/include_inline) #include "base_object-inl.h" +#include "env-inl.h" #include "memory_tracker-inl.h" +#include "nbytes.h" #include "node_errors.h" +#include "node_sockaddr-inl.h" // NOLINT(build/include_inline) #include "uv.h" #include @@ -308,7 +309,7 @@ bool in_network_ipv6_ipv4( return false; ptr += sizeof(mask); - uint32_t check = ReadUint32BE(ptr); + uint32_t check = nbytes::ReadUint32BE(ptr); return (check & m) == (htonl(net_in->sin_addr.s_addr) & m); } diff --git a/src/quic/cid.cc b/src/quic/cid.cc index 7c30d0d542aeaf..404b98c47d6c19 100644 --- a/src/quic/cid.cc +++ b/src/quic/cid.cc @@ -4,6 +4,7 @@ #include #include #include +#include "nbytes.h" #include "quic/defs.h" namespace node { @@ -71,11 +72,10 @@ size_t CID::length() const { std::string CID::ToString() const { char dest[kMaxLength * 2]; - size_t written = - StringBytes::hex_encode(reinterpret_cast(ptr_->data), - ptr_->datalen, - dest, - arraysize(dest)); + size_t written = nbytes::HexEncode(reinterpret_cast(ptr_->data), + ptr_->datalen, + dest, + arraysize(dest)); return std::string(dest, written); } diff --git a/src/quic/tokens.cc b/src/quic/tokens.cc index 9ffdab2575cb42..e2c03d49c1b32f 100644 --- a/src/quic/tokens.cc +++ b/src/quic/tokens.cc @@ -7,6 +7,7 @@ #include #include #include +#include "nbytes.h" namespace node { namespace quic { @@ -49,8 +50,8 @@ TokenSecret::operator const char*() const { std::string TokenSecret::ToString() const { char dest[QUIC_TOKENSECRET_LEN * 2]; - size_t written = StringBytes::hex_encode( - *this, QUIC_TOKENSECRET_LEN, dest, arraysize(dest)); + size_t written = + nbytes::HexEncode(*this, QUIC_TOKENSECRET_LEN, dest, arraysize(dest)); DCHECK_EQ(written, arraysize(dest)); return std::string(dest, written); } @@ -117,7 +118,7 @@ std::string StatelessResetToken::ToString() const { if (ptr_ == nullptr) return std::string(); char dest[kStatelessTokenLen * 2]; size_t written = - StringBytes::hex_encode(*this, kStatelessTokenLen, dest, arraysize(dest)); + nbytes::HexEncode(*this, kStatelessTokenLen, dest, arraysize(dest)); DCHECK_EQ(written, arraysize(dest)); return std::string(dest, written); } @@ -230,7 +231,7 @@ std::string RetryToken::ToString() const { if (ptr_.base == nullptr) return std::string(); MaybeStackBuffer dest(ptr_.len * 2); size_t written = - StringBytes::hex_encode(*this, ptr_.len, dest.out(), dest.length()); + nbytes::HexEncode(*this, ptr_.len, dest.out(), dest.length()); DCHECK_EQ(written, dest.length()); return std::string(dest.out(), written); } @@ -289,7 +290,7 @@ std::string RegularToken::ToString() const { if (ptr_.base == nullptr) return std::string(); MaybeStackBuffer dest(ptr_.len * 2); size_t written = - StringBytes::hex_encode(*this, ptr_.len, dest.out(), dest.length()); + nbytes::HexEncode(*this, ptr_.len, dest.out(), dest.length()); DCHECK_EQ(written, dest.length()); return std::string(dest.out(), written); } diff --git a/src/spawn_sync.cc b/src/spawn_sync.cc index d03803fe3abc5b..36570d069ad00b 100644 --- a/src/spawn_sync.cc +++ b/src/spawn_sync.cc @@ -28,7 +28,7 @@ #include "util-inl.h" #include - +#include "nbytes.h" namespace node { @@ -1069,7 +1069,7 @@ Maybe SyncProcessRunner::CopyJsStringArray(Local js_value, Maybe maybe_size = StringBytes::StorageSize(isolate, value, UTF8); if (maybe_size.IsNothing()) return Nothing(); data_size += maybe_size.FromJust() + 1; - data_size = RoundUp(data_size, sizeof(void*)); + data_size = nbytes::RoundUp(data_size, sizeof(void*)); } buffer = new char[list_size + data_size]; @@ -1086,7 +1086,7 @@ Maybe SyncProcessRunner::CopyJsStringArray(Local js_value, value, UTF8); buffer[data_offset++] = '\0'; - data_offset = RoundUp(data_offset, sizeof(void*)); + data_offset = nbytes::RoundUp(data_offset, sizeof(void*)); } list[length] = nullptr; diff --git a/src/string_bytes.cc b/src/string_bytes.cc index 94e6079023284d..3e2b29005a2012 100644 --- a/src/string_bytes.cc +++ b/src/string_bytes.cc @@ -21,8 +21,8 @@ #include "string_bytes.h" -#include "base64-inl.h" #include "env-inl.h" +#include "nbytes.h" #include "node_buffer.h" #include "node_errors.h" #include "simdutf.h" @@ -200,67 +200,6 @@ MaybeLocal ExternTwoByteString::NewSimpleFromCopy(Isolate* isolate, } // anonymous namespace -// supports regular and URL-safe base64 -const int8_t unbase64_table[256] = - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, -2, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 - }; - - -static const int8_t unhex_table[256] = - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 - }; - -static inline unsigned unhex(uint8_t x) { - return unhex_table[x]; -} - -template -static size_t hex_decode(char* buf, - size_t len, - const TypeName* src, - const size_t srcLen) { - size_t i; - for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) { - unsigned a = unhex(static_cast(src[i * 2 + 0])); - unsigned b = unhex(static_cast(src[i * 2 + 1])); - if (!~a || !~b) - return i; - buf[i] = (a << 4) | b; - } - - return i; -} - size_t StringBytes::WriteUCS2( Isolate* isolate, char* buf, size_t buflen, Local str, int flags) { uint16_t* const dst = reinterpret_cast(buf); @@ -270,7 +209,7 @@ size_t StringBytes::WriteUCS2( return 0; } - uint16_t* const aligned_dst = AlignUp(dst, sizeof(*dst)); + uint16_t* const aligned_dst = nbytes::AlignUp(dst, sizeof(*dst)); size_t nchars; if (aligned_dst == dst) { nchars = str->Write(isolate, dst, 0, max_chars, flags); @@ -339,7 +278,7 @@ size_t StringBytes::Write(Isolate* isolate, // the Buffer, so we need to reorder on BE platforms. See // https://nodejs.org/api/buffer.html regarding Node's "ucs2" // encoding specification - if constexpr (IsBigEndian()) SwapBytes16(buf, nbytes); + if constexpr (IsBigEndian()) CHECK(nbytes::SwapBytes16(buf, nbytes)); break; } @@ -356,7 +295,8 @@ size_t StringBytes::Write(Isolate* isolate, // The input does not follow the WHATWG forgiving-base64 specification // adapted for base64url // https://infra.spec.whatwg.org/#forgiving-base64-decode - nbytes = base64_decode(buf, buflen, ext->data(), ext->length()); + nbytes = + nbytes::Base64Decode(buf, buflen, ext->data(), ext->length()); } } else if (str->IsOneByte()) { MaybeStackBuffer stack_buf(str->Length()); @@ -378,7 +318,8 @@ size_t StringBytes::Write(Isolate* isolate, // The input does not follow the WHATWG forgiving-base64 specification // (adapted for base64url with + and / replaced by - and _). // https://infra.spec.whatwg.org/#forgiving-base64-decode - nbytes = base64_decode(buf, buflen, *stack_buf, stack_buf.length()); + nbytes = + nbytes::Base64Decode(buf, buflen, *stack_buf, stack_buf.length()); } } else { String::Value value(isolate, str); @@ -395,7 +336,7 @@ size_t StringBytes::Write(Isolate* isolate, // The input does not follow the WHATWG forgiving-base64 specification // (adapted for base64url with + and / replaced by - and _). // https://infra.spec.whatwg.org/#forgiving-base64-decode - nbytes = base64_decode(buf, buflen, *value, value.length()); + nbytes = nbytes::Base64Decode(buf, buflen, *value, value.length()); } } break; @@ -411,7 +352,8 @@ size_t StringBytes::Write(Isolate* isolate, } else { // The input does not follow the WHATWG forgiving-base64 specification // https://infra.spec.whatwg.org/#forgiving-base64-decode - nbytes = base64_decode(buf, buflen, ext->data(), ext->length()); + nbytes = + nbytes::Base64Decode(buf, buflen, ext->data(), ext->length()); } } else if (str->IsOneByte()) { MaybeStackBuffer stack_buf(str->Length()); @@ -432,7 +374,8 @@ size_t StringBytes::Write(Isolate* isolate, // The input does not follow the WHATWG forgiving-base64 specification // (adapted for base64url with + and / replaced by - and _). // https://infra.spec.whatwg.org/#forgiving-base64-decode - nbytes = base64_decode(buf, buflen, *stack_buf, stack_buf.length()); + nbytes = + nbytes::Base64Decode(buf, buflen, *stack_buf, stack_buf.length()); } } else { String::Value value(isolate, str); @@ -447,7 +390,7 @@ size_t StringBytes::Write(Isolate* isolate, } else { // The input does not follow the WHATWG base64 specification // https://infra.spec.whatwg.org/#forgiving-base64-decode - nbytes = base64_decode(buf, buflen, *value, value.length()); + nbytes = nbytes::Base64Decode(buf, buflen, *value, value.length()); } } break; @@ -455,10 +398,10 @@ size_t StringBytes::Write(Isolate* isolate, case HEX: if (str->IsExternalOneByte()) { auto ext = str->GetExternalOneByteStringResource(); - nbytes = hex_decode(buf, buflen, ext->data(), ext->length()); + nbytes = nbytes::HexDecode(buf, buflen, ext->data(), ext->length()); } else { String::Value value(isolate, str); - nbytes = hex_decode(buf, buflen, *value, value.length()); + nbytes = nbytes::HexDecode(buf, buflen, *value, value.length()); } break; @@ -568,85 +511,6 @@ Maybe StringBytes::Size(Isolate* isolate, UNREACHABLE(); } -static void force_ascii_slow(const char* src, char* dst, size_t len) { - for (size_t i = 0; i < len; ++i) { - dst[i] = src[i] & 0x7f; - } -} - - -static void force_ascii(const char* src, char* dst, size_t len) { - if (len < 16) { - force_ascii_slow(src, dst, len); - return; - } - - const unsigned bytes_per_word = sizeof(uintptr_t); - const unsigned align_mask = bytes_per_word - 1; - const unsigned src_unalign = reinterpret_cast(src) & align_mask; - const unsigned dst_unalign = reinterpret_cast(dst) & align_mask; - - if (src_unalign > 0) { - if (src_unalign == dst_unalign) { - const unsigned unalign = bytes_per_word - src_unalign; - force_ascii_slow(src, dst, unalign); - src += unalign; - dst += unalign; - len -= src_unalign; - } else { - force_ascii_slow(src, dst, len); - return; - } - } - -#if defined(_WIN64) || defined(_LP64) - const uintptr_t mask = ~0x8080808080808080ll; -#else - const uintptr_t mask = ~0x80808080l; -#endif - - const uintptr_t* srcw = reinterpret_cast(src); - uintptr_t* dstw = reinterpret_cast(dst); - - for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) { - dstw[i] = srcw[i] & mask; - } - - const unsigned remainder = len & align_mask; - if (remainder > 0) { - const size_t offset = len - remainder; - force_ascii_slow(src + offset, dst + offset, remainder); - } -} - - -size_t StringBytes::hex_encode( - const char* src, - size_t slen, - char* dst, - size_t dlen) { - // We know how much we'll write, just make sure that there's space. - CHECK(dlen >= MultiplyWithOverflowCheck(slen, 2u) && - "not enough space provided for hex encode"); - - dlen = slen * 2; - for (size_t i = 0, k = 0; k < dlen; i += 1, k += 2) { - static const char hex[] = "0123456789abcdef"; - uint8_t val = static_cast(src[i]); - dst[k + 0] = hex[val >> 4]; - dst[k + 1] = hex[val & 15]; - } - - return dlen; -} - -std::string StringBytes::hex_encode(const char* src, size_t slen) { - size_t dlen = slen * 2; - std::string dst(dlen, '\0'); - hex_encode(src, slen, dst.data(), dlen); - return dst; -} - #define CHECK_BUFLEN_IN_RANGE(len) \ do { \ if ((len) > Buffer::kMaxLength) { \ @@ -688,7 +552,7 @@ MaybeLocal StringBytes::Encode(Isolate* isolate, *error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate); return MaybeLocal(); } - force_ascii(buf, out, buflen); + nbytes::ForceAscii(buf, out, buflen); return ExternOneByteString::New(isolate, out, buflen, error); } else { return ExternOneByteString::NewFromCopy(isolate, buf, buflen, error); @@ -747,7 +611,7 @@ MaybeLocal StringBytes::Encode(Isolate* isolate, *error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate); return MaybeLocal(); } - size_t written = hex_encode(buf, buflen, dst, dlen); + size_t written = nbytes::HexEncode(buf, buflen, dst, dlen); CHECK_EQ(written, dlen); return ExternOneByteString::New(isolate, dst, dlen, error); @@ -810,7 +674,7 @@ MaybeLocal StringBytes::Encode(Isolate* isolate, } size_t nbytes = buflen * sizeof(uint16_t); memcpy(dst, buf, nbytes); - SwapBytes16(reinterpret_cast(dst), nbytes); + CHECK(nbytes::SwapBytes16(reinterpret_cast(dst), nbytes)); return ExternTwoByteString::New(isolate, dst, buflen, error); } else { return ExternTwoByteString::NewFromCopy(isolate, buf, buflen, error); diff --git a/src/string_bytes.h b/src/string_bytes.h index ad1f15b05704c8..fde5070ffb66a7 100644 --- a/src/string_bytes.h +++ b/src/string_bytes.h @@ -98,13 +98,6 @@ class StringBytes { enum encoding encoding, v8::Local* error); - static size_t hex_encode(const char* src, - size_t slen, - char* dst, - size_t dlen); - - static std::string hex_encode(const char* src, size_t slen); - private: static size_t WriteUCS2(v8::Isolate* isolate, char* buf, diff --git a/src/util-inl.h b/src/util-inl.h index 463f982c91c71b..88d0cfee7f257f 100644 --- a/src/util-inl.h +++ b/src/util-inl.h @@ -30,41 +30,6 @@ #include "node_revert.h" #include "util.h" -// These are defined by or on some systems. -// To avoid warnings, undefine them before redefining them. -#ifdef BSWAP_2 -# undef BSWAP_2 -#endif -#ifdef BSWAP_4 -# undef BSWAP_4 -#endif -#ifdef BSWAP_8 -# undef BSWAP_8 -#endif - -#if defined(_MSC_VER) -#include -#define BSWAP_2(x) _byteswap_ushort(x) -#define BSWAP_4(x) _byteswap_ulong(x) -#define BSWAP_8(x) _byteswap_uint64(x) -#else -#define BSWAP_2(x) ((x) << 8) | ((x) >> 8) -#define BSWAP_4(x) \ - (((x) & 0xFF) << 24) | \ - (((x) & 0xFF00) << 8) | \ - (((x) >> 8) & 0xFF00) | \ - (((x) >> 24) & 0xFF) -#define BSWAP_8(x) \ - (((x) & 0xFF00000000000000ull) >> 56) | \ - (((x) & 0x00FF000000000000ull) >> 40) | \ - (((x) & 0x0000FF0000000000ull) >> 24) | \ - (((x) & 0x000000FF00000000ull) >> 8) | \ - (((x) & 0x00000000FF000000ull) << 8) | \ - (((x) & 0x0000000000FF0000ull) << 24) | \ - (((x) & 0x000000000000FF00ull) << 40) | \ - (((x) & 0x00000000000000FFull) << 56) -#endif - #define CHAR_TEST(bits, name, expr) \ template \ bool name(const T ch) { \ @@ -214,75 +179,6 @@ inline v8::Local OneByteString(v8::Isolate* isolate, .ToLocalChecked(); } -void SwapBytes16(char* data, size_t nbytes) { - CHECK_EQ(nbytes % 2, 0); - -#if defined(_MSC_VER) - if (AlignUp(data, sizeof(uint16_t)) == data) { - // MSVC has no strict aliasing, and is able to highly optimize this case. - uint16_t* data16 = reinterpret_cast(data); - size_t len16 = nbytes / sizeof(*data16); - for (size_t i = 0; i < len16; i++) { - data16[i] = BSWAP_2(data16[i]); - } - return; - } -#endif - - uint16_t temp; - for (size_t i = 0; i < nbytes; i += sizeof(temp)) { - memcpy(&temp, &data[i], sizeof(temp)); - temp = BSWAP_2(temp); - memcpy(&data[i], &temp, sizeof(temp)); - } -} - -void SwapBytes32(char* data, size_t nbytes) { - CHECK_EQ(nbytes % 4, 0); - -#if defined(_MSC_VER) - // MSVC has no strict aliasing, and is able to highly optimize this case. - if (AlignUp(data, sizeof(uint32_t)) == data) { - uint32_t* data32 = reinterpret_cast(data); - size_t len32 = nbytes / sizeof(*data32); - for (size_t i = 0; i < len32; i++) { - data32[i] = BSWAP_4(data32[i]); - } - return; - } -#endif - - uint32_t temp; - for (size_t i = 0; i < nbytes; i += sizeof(temp)) { - memcpy(&temp, &data[i], sizeof(temp)); - temp = BSWAP_4(temp); - memcpy(&data[i], &temp, sizeof(temp)); - } -} - -void SwapBytes64(char* data, size_t nbytes) { - CHECK_EQ(nbytes % 8, 0); - -#if defined(_MSC_VER) - if (AlignUp(data, sizeof(uint64_t)) == data) { - // MSVC has no strict aliasing, and is able to highly optimize this case. - uint64_t* data64 = reinterpret_cast(data); - size_t len64 = nbytes / sizeof(*data64); - for (size_t i = 0; i < len64; i++) { - data64[i] = BSWAP_8(data64[i]); - } - return; - } -#endif - - uint64_t temp; - for (size_t i = 0; i < nbytes; i += sizeof(temp)) { - memcpy(&temp, &data[i], sizeof(temp)); - temp = BSWAP_8(temp); - memcpy(&data[i], &temp, sizeof(temp)); - } -} - char ToLower(char c) { return std::tolower(c, std::locale::classic()); } diff --git a/src/util.h b/src/util.h index a0cee453ee43a7..d3ad830e162a36 100644 --- a/src/util.h +++ b/src/util.h @@ -358,14 +358,6 @@ inline v8::Local FIXED_ONE_BYTE_STRING( return OneByteString(isolate, arr.data(), N - 1); } - - -// Swaps bytes in place. nbytes is the number of bytes to swap and must be a -// multiple of the word size (checked by function). -inline void SwapBytes16(char* data, size_t nbytes); -inline void SwapBytes32(char* data, size_t nbytes); -inline void SwapBytes64(char* data, size_t nbytes); - // tolower() is locale-sensitive. Use ToLower() instead. inline char ToLower(char c); inline std::string ToLower(const std::string& in); @@ -794,19 +786,6 @@ constexpr inline bool IsBigEndian() { static_assert(IsLittleEndian() || IsBigEndian(), "Node.js does not support mixed-endian systems"); -// Round up a to the next highest multiple of b. -template -constexpr T RoundUp(T a, T b) { - return a % b != 0 ? a + b - (a % b) : a; -} - -// Align ptr to an `alignment`-bytes boundary. -template -constexpr T* AlignUp(T* ptr, U alignment) { - return reinterpret_cast( - RoundUp(reinterpret_cast(ptr), alignment)); -} - class SlicedArguments : public MaybeStackBuffer> { public: inline explicit SlicedArguments( diff --git a/test/cctest/test_base64.cc b/test/cctest/test_base64.cc index ce960a6fc8dd56..4f1bc9173b6818 100644 --- a/test/cctest/test_base64.cc +++ b/test/cctest/test_base64.cc @@ -1,13 +1,12 @@ -#include "base64-inl.h" +#include "nbytes.h" #include "simdutf.h" +#include "util-inl.h" #include #include #include "gtest/gtest.h" -using node::base64_decode; - TEST(Base64Test, Encode) { auto test = [](const char* string, const char* base64_string) { const size_t len = strlen(base64_string); @@ -70,7 +69,7 @@ TEST(Base64Test, Decode) { const size_t len = strlen(string); char* const buffer = new char[len + 1]; buffer[len] = 0; - base64_decode(buffer, len, base64_string, strlen(base64_string)); + nbytes::Base64Decode(buffer, len, base64_string, strlen(base64_string)); EXPECT_STREQ(string, buffer); delete[] buffer; }; diff --git a/test/parallel/test-process-versions.js b/test/parallel/test-process-versions.js index 374c339cd814f5..bab483a7e2637e 100644 --- a/test/parallel/test-process-versions.js +++ b/test/parallel/test-process-versions.js @@ -23,6 +23,7 @@ const expected_keys = [ 'sqlite', 'ada', 'cjs_module_lexer', + 'nbytes', ]; const hasUndici = process.config.variables.node_builtin_shareable_builtins.includes('deps/undici/undici.js'); @@ -62,6 +63,7 @@ assert.match(process.versions.brotli, commonTemplate); assert.match(process.versions.llhttp, commonTemplate); assert.match(process.versions.node, commonTemplate); assert.match(process.versions.uv, commonTemplate); +assert.match(process.versions.nbytes, commonTemplate); assert.match(process.versions.zlib, /^\d+(?:\.\d+){1,3}(?:-.*)?$/); if (hasUndici) {