| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent e62c42b commit fa9d82d
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -7,22 +7,14 @@ | |||
| 7 | 7 | #include "node.h" | |
| 8 | 8 | #include "env.h" | |
| 9 | 9 | #include "env-inl.h" | |
| 10 | + #include "util.h" | ||
| 10 | 11 | ||
| 11 | 12 | namespace node { | |
| 12 | 13 | ||
| 13 | 14 | class StringBytes { | |
| 14 | 15 | public: | |
| 15 | - class InlineDecoder { | ||
| 16 | + class InlineDecoder : public MaybeStackBuffer<char> { | ||
| 16 | 17 | public: | |
| 17 | - InlineDecoder() : out_(nullptr) { | ||
| 18 | - } | ||
| 19 | - | ||
| 20 | - ~InlineDecoder() { | ||
| 21 | - if (out_ != out_st_) | ||
| 22 | - delete[] out_; | ||
| 23 | - out_ = nullptr; | ||
| 24 | - } | ||
| 25 | - | ||
| 26 | 18 | inline bool Decode(Environment* env, | |
| 27 | 19 | v8::Local<v8::String> string, | |
| 28 | 20 | v8::Local<v8::Value> encoding, | |
@@ -33,28 +25,22 @@ class StringBytes { | |||
| 33 | 25 | return false; | |
| 34 | 26 | } | |
| 35 | 27 | ||
| 36 | - size_t buflen = StringBytes::StorageSize(env->isolate(), string, enc); | ||
| 37 | - if (buflen > sizeof(out_st_)) | ||
| 38 | - out_ = new char[buflen]; | ||
| 39 | - else | ||
| 40 | - out_ = out_st_; | ||
| 41 | - size_ = StringBytes::Write(env->isolate(), | ||
| 42 | - out_, | ||
| 43 | - buflen, | ||
| 44 | - string, | ||
| 45 | - enc); | ||
| 28 | + const size_t storage = StringBytes::StorageSize(env->isolate(), | ||
| 29 | + string, | ||
| 30 | + enc); | ||
| 31 | + AllocateSufficientStorage(storage); | ||
| 32 | + const size_t length = StringBytes::Write(env->isolate(), | ||
| 33 | + out(), | ||
| 34 | + storage, | ||
| 35 | + string, | ||
| 36 | + enc); | ||
| 37 | + | ||
| 38 | + // No zero terminator is included when using this method. | ||
| 39 | + SetLength(length); | ||
| 46 | 40 | return true; | |
| 47 | 41 | } | |
| 48 | 42 | ||
| 49 | - inline const char* out() const { return out_; } | ||
| 50 | - inline size_t size() const { return size_; } | ||
| 51 | - | ||
| 52 | - private: | ||
| 53 | - static const int kStorageSize = 1024; | ||
| 54 | - | ||
| 55 | - char out_st_[kStorageSize]; | ||
| 56 | - char* out_; | ||
| 57 | - size_t size_; | ||
| 43 | + inline size_t size() const { return length(); } | ||
| 58 | 44 | }; | |
| 59 | 45 | ||
| 60 | 46 | // Does the string match the encoding? Quick but non-exhaustive. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -10,76 +10,69 @@ using v8::Local; | |||
| 10 | 10 | using v8::String; | |
| 11 | 11 | using v8::Value; | |
| 12 | 12 | ||
| 13 | - static int MakeUtf8String(Isolate* isolate, | ||
| 14 | - Local<Value> value, | ||
| 15 | - char** dst, | ||
| 16 | - const size_t size) { | ||
| 13 | + template <typename T> | ||
| 14 | + static void MakeUtf8String(Isolate* isolate, | ||
| 15 | + Local<Value> value, | ||
| 16 | + T* target) { | ||
| 17 | 17 | Local<String> string = value->ToString(isolate); | |
| 18 | 18 | if (string.IsEmpty()) | |
| 19 | - return 0; | ||
| 20 | - size_t len = StringBytes::StorageSize(isolate, string, UTF8) + 1; | ||
| 21 | - if (len > size) { | ||
| 22 | - *dst = static_cast<char*>(malloc(len)); | ||
| 23 | - CHECK_NE(*dst, nullptr); | ||
| 24 | - } | ||
| 19 | + return; | ||
| 20 | + | ||
| 21 | + const size_t storage = StringBytes::StorageSize(isolate, string, UTF8) + 1; | ||
| 22 | + target->AllocateSufficientStorage(storage); | ||
| 25 | 23 | const int flags = | |
| 26 | 24 | String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8; | |
| 27 | - const int length = string->WriteUtf8(*dst, len, 0, flags); | ||
| 28 | - (*dst)[length] = '\0'; | ||
| 29 | - return length; | ||
| 25 | + const int length = string->WriteUtf8(target->out(), storage, 0, flags); | ||
| 26 | + target->SetLengthAndZeroTerminate(length); | ||
| 30 | 27 | } | |
| 31 | 28 | ||
| 32 | - Utf8Value::Utf8Value(Isolate* isolate, Local<Value> value) | ||
| 33 | - : length_(0), str_(str_st_) { | ||
| 29 | + Utf8Value::Utf8Value(Isolate* isolate, Local<Value> value) { | ||
| 34 | 30 | if (value.IsEmpty()) | |
| 35 | 31 | return; | |
| 36 | - length_ = MakeUtf8String(isolate, value, &str_, sizeof(str_st_)); | ||
| 32 | + | ||
| 33 | + MakeUtf8String(isolate, value, this); | ||
| 37 | 34 | } | |
| 38 | 35 | ||
| 39 | 36 | ||
| 40 | - TwoByteValue::TwoByteValue(Isolate* isolate, Local<Value> value) | ||
| 41 | - : length_(0), str_(str_st_) { | ||
| 42 | - if (value.IsEmpty()) | ||
| 37 | + TwoByteValue::TwoByteValue(Isolate* isolate, Local<Value> value) { | ||
| 38 | + if (value.IsEmpty()) { | ||
| 43 | 39 | return; | |
| 40 | + } | ||
| 44 | 41 | ||
| 45 | 42 | Local<String> string = value->ToString(isolate); | |
| 46 | 43 | if (string.IsEmpty()) | |
| 47 | 44 | return; | |
| 48 | 45 | ||
| 49 | 46 | // Allocate enough space to include the null terminator | |
| 50 | - size_t len = | ||
| 51 | - StringBytes::StorageSize(isolate, string, UCS2) + | ||
| 52 | - sizeof(uint16_t); | ||
| 53 | - if (len > sizeof(str_st_)) { | ||
| 54 | - str_ = static_cast<uint16_t*>(malloc(len)); | ||
| 55 | - CHECK_NE(str_, nullptr); | ||
| 56 | - } | ||
| 47 | + const size_t storage = string->Length() + 1; | ||
| 48 | + AllocateSufficientStorage(storage); | ||
| 57 | 49 | ||
| 58 | 50 | const int flags = | |
| 59 | 51 | String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8; | |
| 60 | - length_ = string->Write(str_, 0, len, flags); | ||
| 61 | - str_[length_] = '\0'; | ||
| 52 | + const int length = string->Write(out(), 0, storage, flags); | ||
| 53 | + SetLengthAndZeroTerminate(length); | ||
| 62 | 54 | } | |
| 63 | 55 | ||
| 64 | - BufferValue::BufferValue(Isolate* isolate, Local<Value> value) | ||
| 65 | - : str_(str_st_), fail_(true) { | ||
| 56 | + BufferValue::BufferValue(Isolate* isolate, Local<Value> value) { | ||
| 66 | 57 | // Slightly different take on Utf8Value. If value is a String, | |
| 67 | 58 | // it will return a Utf8 encoded string. If value is a Buffer, | |
| 68 | 59 | // it will copy the data out of the Buffer as is. | |
| 69 | - if (value.IsEmpty()) | ||
| 60 | + if (value.IsEmpty()) { | ||
| 61 | + // Dereferencing this object will return nullptr. | ||
| 62 | + Invalidate(); | ||
| 70 | 63 | return; | |
| 64 | + } | ||
| 65 | + | ||
| 71 | 66 | if (value->IsString()) { | |
| 72 | - MakeUtf8String(isolate, value, &str_, sizeof(str_st_)); | ||
| 73 | - fail_ = false; | ||
| 67 | + MakeUtf8String(isolate, value, this); | ||
| 74 | 68 | } else if (Buffer::HasInstance(value)) { | |
| 75 | - size_t len = Buffer::Length(value) + 1; | ||
| 76 | - if (len > sizeof(str_st_)) { | ||
| 77 | - str_ = static_cast<char*>(malloc(len)); | ||
| 78 | - CHECK_NE(str_, nullptr); | ||
| 79 | - } | ||
| 80 | - memcpy(str_, Buffer::Data(value), len); | ||
| 81 | - str_[len - 1] = '\0'; | ||
| 82 | - fail_ = false; | ||
| 69 | + const size_t len = Buffer::Length(value); | ||
| 70 | + // Leave place for the terminating '\0' byte. | ||
| 71 | + AllocateSufficientStorage(len + 1); | ||
| 72 | + memcpy(out(), Buffer::Data(value), len); | ||
| 73 | + SetLengthAndZeroTerminate(len); | ||
| 74 | + } else { | ||
| 75 | + Invalidate(); | ||
| 83 | 76 | } | |
| 84 | 77 | } | |
| 85 | 78 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -178,77 +178,102 @@ inline TypeName* Unwrap(v8::Local<v8::Object> object); | |||
| 178 | 178 | ||
| 179 | 179 | inline void SwapBytes(uint16_t* dst, const uint16_t* src, size_t buflen); | |
| 180 | 180 | ||
| 181 | - class Utf8Value { | ||
| 181 | + // Allocates an array of member type T. For up to kStackStorageSize items, | ||
| 182 | + // the stack is used, otherwise malloc(). | ||
| 183 | + template <typename T, size_t kStackStorageSize = 1024> | ||
| 184 | + class MaybeStackBuffer { | ||
| 182 | 185 | public: | |
| 183 | - explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value); | ||
| 186 | + const T* out() const { | ||
| 187 | + return buf_; | ||
| 188 | + } | ||
| 184 | 189 | ||
| 185 | - ~Utf8Value() { | ||
| 186 | - if (str_ != str_st_) | ||
| 187 | - free(str_); | ||
| 190 | + T* out() { | ||
| 191 | + return buf_; | ||
| 188 | 192 | } | |
| 189 | 193 | ||
| 190 | - char* operator*() { | ||
| 191 | - return str_; | ||
| 192 | - }; | ||
| 194 | + // operator* for compatibility with `v8::String::(Utf8)Value` | ||
| 195 | + T* operator*() { | ||
| 196 | + return buf_; | ||
| 197 | + } | ||
| 193 | 198 | ||
| 194 | - const char* operator*() const { | ||
| 195 | - return str_; | ||
| 196 | - }; | ||
| 199 | + const T* operator*() const { | ||
| 200 | + return buf_; | ||
| 201 | + } | ||
| 197 | 202 | ||
| 198 | 203 | size_t length() const { | |
| 199 | 204 | return length_; | |
| 200 | - }; | ||
| 201 | - | ||
| 202 | - private: | ||
| 203 | - size_t length_; | ||
| 204 | - char* str_; | ||
| 205 | - char str_st_[1024]; | ||
| 206 | - }; | ||
| 205 | + } | ||
| 207 | 206 | ||
| 208 | - class TwoByteValue { | ||
| 209 | - public: | ||
| 210 | - explicit TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value); | ||
| 207 | + // Call to make sure enough space for `storage` entries is available. | ||
| 208 | + // There can only be 1 call to AllocateSufficientStorage or Invalidate | ||
| 209 | + // per instance. | ||
| 210 | + void AllocateSufficientStorage(size_t storage) { | ||
| 211 | + if (storage <= kStackStorageSize) { | ||
| 212 | + buf_ = buf_st_; | ||
| 213 | + } else { | ||
| 214 | + // Guard against overflow. | ||
| 215 | + CHECK_LE(storage, sizeof(T) * storage); | ||
| 216 | + | ||
| 217 | + buf_ = static_cast<T*>(malloc(sizeof(T) * storage)); | ||
| 218 | + CHECK_NE(buf_, nullptr); | ||
| 219 | + } | ||
| 220 | + | ||
| 221 | + // Remember how much was allocated to check against that in SetLength(). | ||
| 222 | + length_ = storage; | ||
| 223 | + } | ||
| 211 | 224 | ||
| 212 | - ~TwoByteValue() { | ||
| 213 | - if (str_ != str_st_) | ||
| 214 | - free(str_); | ||
| 225 | + void SetLength(size_t length) { | ||
| 226 | + // length_ stores how much memory was allocated. | ||
| 227 | + CHECK_LE(length, length_); | ||
| 228 | + length_ = length; | ||
| 215 | 229 | } | |
| 216 | 230 | ||
| 217 | - uint16_t* operator*() { | ||
| 218 | - return str_; | ||
| 219 | - }; | ||
| 231 | + void SetLengthAndZeroTerminate(size_t length) { | ||
| 232 | + // length_ stores how much memory was allocated. | ||
| 233 | + CHECK_LE(length + 1, length_); | ||
| 234 | + SetLength(length); | ||
| 220 | 235 | ||
| 221 | - const uint16_t* operator*() const { | ||
| 222 | - return str_; | ||
| 223 | - }; | ||
| 236 | + // T() is 0 for integer types, nullptr for pointers, etc. | ||
| 237 | + buf_[length] = T(); | ||
| 238 | + } | ||
| 224 | 239 | ||
| 225 | - size_t length() const { | ||
| 226 | - return length_; | ||
| 227 | - }; | ||
| 240 | + // Make derefencing this object return nullptr. | ||
| 241 | + // Calling this is mutually exclusive with calling | ||
| 242 | + // AllocateSufficientStorage. | ||
| 243 | + void Invalidate() { | ||
| 244 | + CHECK_EQ(buf_, buf_st_); | ||
| 245 | + length_ = 0; | ||
| 246 | + buf_ = nullptr; | ||
| 247 | + } | ||
| 248 | + | ||
| 249 | + MaybeStackBuffer() : length_(0), buf_(buf_st_) { | ||
| 250 | + // Default to a zero-length, null-terminated buffer. | ||
| 251 | + buf_[0] = T(); | ||
| 252 | + } | ||
| 228 | 253 | ||
| 254 | + ~MaybeStackBuffer() { | ||
| 255 | + if (buf_ != buf_st_) | ||
| 256 | + free(buf_); | ||
| 257 | + } | ||
| 229 | 258 | private: | |
| 230 | 259 | size_t length_; | |
| 231 | - uint16_t* str_; | ||
| 232 | - uint16_t str_st_[1024]; | ||
| 260 | + T* buf_; | ||
| 261 | + T buf_st_[kStackStorageSize]; | ||
| 233 | 262 | }; | |
| 234 | 263 | ||
| 235 | - class BufferValue { | ||
| 264 | + class Utf8Value : public MaybeStackBuffer<char> { | ||
| 236 | 265 | public: | |
| 237 | - explicit BufferValue(v8::Isolate* isolate, v8::Local<v8::Value> value); | ||
| 238 | - | ||
| 239 | - ~BufferValue() { | ||
| 240 | - if (str_ != str_st_) | ||
| 241 | - free(str_); | ||
| 242 | - } | ||
| 266 | + explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value); | ||
| 267 | + }; | ||
| 243 | 268 | ||
| 244 | - const char* operator*() const { | ||
| 245 | - return fail_ ? nullptr : str_; | ||
| 246 | - }; | ||
| 269 | + class TwoByteValue : public MaybeStackBuffer<uint16_t> { | ||
| 270 | + public: | ||
| 271 | + explicit TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value); | ||
| 272 | + }; | ||
| 247 | 273 | ||
| 248 | - private: | ||
| 249 | - char* str_; | ||
| 250 | - char str_st_[1024]; | ||
| 251 | - bool fail_; | ||
| 274 | + class BufferValue : public MaybeStackBuffer<char> { | ||
| 275 | + public: | ||
| 276 | + explicit BufferValue(v8::Isolate* isolate, v8::Local<v8::Value> value); | ||
| 252 | 277 | }; | |
| 253 | 278 | ||
| 254 | 279 | } // namespace node | |
| Back | FazBrowse Home | New Git URL |
0 commit comments