• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef INSPECTOR_UTILS_H
17 #define INSPECTOR_UTILS_H
18 #include <cstring>
19 #include <securec.h>
20 #include <sstream>
21 #include <string>
22 
23 #include "jsvm_dfx.h"
24 #include "jsvm_util.h"
25 #include "uv.h"
26 #include "v8-inspector.h"
27 
28 #ifdef __GNUC__
29 #define MUST_USE_RESULT __attribute__((warn_unused_result))
30 #else
31 #define MUST_USE_RESULT
32 #endif
33 
34 namespace jsvm {
35 namespace inspector {
36 template<typename Inner, typename Outer>
37 class ContainerOfHelper {
38 public:
39     // The helper is for doing safe downcasts from base types to derived types.
40     inline ContainerOfHelper(Inner Outer::* field, Inner* pointer);
41     template<typename TypeName>
42     inline operator TypeName*() const;
43 
44 private:
45     Outer* const pointer;
46 };
47 
ToLower(char c)48 inline char ToLower(char c)
49 {
50     return std::tolower(c, std::locale::classic());
51 }
52 
StringEqualNoCase(const char * a,const char * b)53 inline bool StringEqualNoCase(const char* a, const char* b)
54 {
55     while (ToLower(*a) == ToLower(*b++)) {
56         if (*a++ == '\0') {
57             return true;
58         }
59     }
60     return false;
61 }
62 
StringEqualNoCaseN(const char * a,const char * b,size_t length)63 inline bool StringEqualNoCaseN(const char* a, const char* b, size_t length)
64 {
65     for (size_t i = 0; i < length; i++) {
66         if (ToLower(a[i]) != ToLower(b[i])) {
67             return false;
68         }
69         if (a[i] == '\0') {
70             return true;
71         }
72     }
73     return true;
74 }
75 
76 // Use this when a variable or parameter is unused in order to explicitly
77 // silence a compiler warning about that.
78 template<typename T>
USE(T &&)79 inline void USE(T&&)
80 {}
81 
82 template<typename T, void (*function)(T*)>
83 struct FunctionDeleter {
operatorFunctionDeleter84     void operator()(T* pointer) const
85     {
86         function(pointer);
87     }
88     typedef std::unique_ptr<T, FunctionDeleter> Pointer;
89 };
90 
91 template<typename T, void (*function)(T*)>
92 using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer;
93 
94 template<typename Inner, typename Outer>
OffsetOf(Inner Outer::* field)95 constexpr uintptr_t OffsetOf(Inner Outer::* field)
96 {
97     return reinterpret_cast<uintptr_t>(&(static_cast<Outer*>(nullptr)->*field));
98 }
99 
100 template<typename Inner, typename Outer>
ContainerOfHelper(Inner Outer::* field,Inner * pointer)101 ContainerOfHelper<Inner, Outer>::ContainerOfHelper(Inner Outer::* field, Inner* pointer)
102     : pointer(reinterpret_cast<Outer*>(reinterpret_cast<uintptr_t>(pointer) - OffsetOf(field)))
103 {}
104 
105 template<typename Inner, typename Outer>
106 template<typename TypeName>
107 ContainerOfHelper<Inner, Outer>::operator TypeName*() const
108 {
109     return static_cast<TypeName*>(pointer);
110 }
111 
112 // Calculate the address of the outer (i.e. embedding) struct from
113 // the interior pointer to a data member.
114 template<typename Inner, typename Outer>
ContainerOf(Inner Outer::* field,Inner * pointer)115 constexpr ContainerOfHelper<Inner, Outer> ContainerOf(Inner Outer::* field, Inner* pointer)
116 {
117     return ContainerOfHelper<Inner, Outer>(field, pointer);
118 }
119 
120 template<typename T, size_t kStackStorageSize = 1024>
121 class MaybeStackBuffer {
122 public:
Out()123     const T* Out() const
124     {
125         return buf;
126     }
127 
Out()128     T* Out()
129     {
130         return buf;
131     }
132 
133     // operator* for compatibility with `v8::String::(Utf8)Value`
134     T* operator*()
135     {
136         return buf;
137     }
138 
139     const T* operator*() const
140     {
141         return buf;
142     }
143 
144     T& operator[](size_t index)
145     {
146         CHECK_LT(index, GetLength());
147         return buf[index];
148     }
149 
150     const T& operator[](size_t index) const
151     {
152         CHECK_LT(index, GetLength());
153         return buf[index];
154     }
155 
GetLength()156     size_t GetLength() const
157     {
158         return length;
159     }
160 
161     // Current maximum capacity of the buffer with which SetLength() can be used
162     // without first calling AllocateSufficientStorage().
GetCapacity()163     size_t GetCapacity() const
164     {
165         return capacity;
166     }
167 
168     void AllocateSufficientStorage(size_t storage);
169 
SetLength(size_t lengthParam)170     void SetLength(size_t lengthParam)
171     {
172         // GetCapacity() returns how much memory is actually available.
173         CHECK_LE(lengthParam, GetCapacity());
174         length = lengthParam;
175     }
176 
SetLengthAndZeroTerminate(size_t len)177     void SetLengthAndZeroTerminate(size_t len)
178     {
179         // GetCapacity() returns how much memory is actually available.
180         CHECK_LE(len + 1, GetCapacity());
181         SetLength(len);
182 
183         // T() is 0 for integer types, nullptr for pointers, etc.
184         buf[len] = T();
185     }
186 
Invalidate()187     void Invalidate()
188     {
189         CHECK(!IsAllocated());
190         capacity = 0;
191         length = 0;
192         buf = nullptr;
193     }
194 
195     // If the buffer is stored in the heap rather than on the stack.
IsAllocated()196     bool IsAllocated() const
197     {
198         return !IsInvalidated() && buf != bufSt;
199     }
200 
201     // If Invalidate() has been called.
IsInvalidated()202     bool IsInvalidated() const
203     {
204         return buf == nullptr;
205     }
206 
207     // Release ownership of the malloc'd buffer.
208     // Note: This does not free the buffer.
Release()209     void Release()
210     {
211         CHECK(IsAllocated());
212         buf = bufSt;
213         length = 0;
214         capacity = jsvm::ArraySize(bufSt);
215     }
216 
MaybeStackBuffer()217     MaybeStackBuffer() : length(0), capacity(jsvm::ArraySize(bufSt)), buf(bufSt)
218     {
219         // Default to a zero-length, null-terminated buffer.
220         buf[0] = T();
221     }
222 
MaybeStackBuffer(size_t storage)223     explicit MaybeStackBuffer(size_t storage) : MaybeStackBuffer()
224     {
225         AllocateSufficientStorage(storage);
226     }
227 
~MaybeStackBuffer()228     ~MaybeStackBuffer()
229     {
230         if (IsAllocated()) {
231             free(buf);
232         }
233     }
234 
ToString()235     inline std::basic_string<T> ToString() const
236     {
237         return { Out(), GetLength() };
238     }
ToStringView()239     inline std::basic_string_view<T> ToStringView() const
240     {
241         return { Out(), GetLength() };
242     }
243 
244 private:
245     size_t length;
246     // capacity of the malloc'ed buf
247     size_t capacity;
248     T* buf;
249     T bufSt[kStackStorageSize];
250 };
251 
252 class TwoByteValue : public MaybeStackBuffer<uint16_t> {
253 public:
254     explicit TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
255 };
256 
257 template<typename T>
Realloc(T * pointer,size_t n,size_t oldN)258 T* Realloc(T* pointer, size_t n, size_t oldN)
259 {
260     CHECK(n > 0);
261     size_t newSize = sizeof(T) * n;
262     T* newPtr = static_cast<T*>(malloc(newSize));
263 
264     CHECK_NOT_NULL(newPtr);
265 
266     if (!pointer) {
267         return newPtr;
268     }
269 
270     size_t oldSize = sizeof(T) * oldN;
271     CHECK(newSize > oldSize);
272     errno_t ret = memcpy_s(newPtr, newSize, pointer, oldSize);
273     CHECK(ret == EOK);
274     free(pointer);
275 
276     return newPtr;
277 }
278 
279 template<typename T, size_t kStackStorageSize>
AllocateSufficientStorage(size_t storage)280 void MaybeStackBuffer<T, kStackStorageSize>::AllocateSufficientStorage(size_t storage)
281 {
282     CHECK(!IsInvalidated());
283     if (storage > GetCapacity()) {
284         bool wasAllocated = IsAllocated();
285         T* allocatedPtr = wasAllocated ? buf : nullptr;
286         buf = Realloc(allocatedPtr, storage, length);
287         capacity = storage;
288         if (!wasAllocated && length > 0) {
289             int ret = memcpy_s(buf, length * sizeof(buf[0]), bufSt, length * sizeof(buf[0]));
290             CHECK(ret == EOK);
291         }
292     }
293 
294     length = storage;
295 }
296 
297 // Convertion between v8_inspector::StringView and std::string
298 std::string StringViewToUtf8(v8_inspector::StringView view);
299 std::unique_ptr<v8_inspector::StringBuffer> Utf8ToStringView(const std::string_view message);
300 
301 constexpr size_t TO_TRANSFORM_CHAR_NUM = 3;
302 constexpr size_t TRANSFORMED_CHAR_NUM = 4;
303 
304 enum ByteOffset : uint8_t {
305     BYTE_0 = 0,
306     BYTE_1 = 1,
307     BYTE_2 = 2,
308     BYTE_3 = 3,
309     BYTE_4 = 4,
310     BYTE_5 = 5,
311     BYTE_6 = 6,
312     BYTE_7 = 7,
313     BIT_0 = 0,
314     BIT_1 = 1,
315     BIT_2 = 2,
316     BIT_3 = 3,
317     BIT_4 = 4,
318     BIT_5 = 5,
319     BIT_6 = 6,
320     BIT_7 = 7,
321     BIT_8 = 8,
322 };
323 
324 // Encode base64
Base64EncodeSize(size_t size)325 inline constexpr size_t Base64EncodeSize(size_t size)
326 {
327     return ((size + TO_TRANSFORM_CHAR_NUM - 1) / TO_TRANSFORM_CHAR_NUM * TRANSFORMED_CHAR_NUM);
328 }
329 
330 // Be careful: If dlen is less than expected encode size, it will crash.
331 size_t Base64Encode(const char* inputString, size_t slen, char* outputBuffer, size_t dlen);
332 
333 std::string GetHumanReadableProcessName();
334 
335 // Either succeeds with exactly |length| bytes of cryptographically
336 // strong pseudo-random data, or fails. This function may block.
337 // Don't assume anything about the contents of |buffer| on error.
338 // As a special case, |length == 0| can be used to check if the CSPRNG
339 // is properly seeded without consuming entropy.
340 MUST_USE_RESULT bool CSPRNG(void* buffer, size_t length);
341 
342 void CheckedUvLoopClose(uv_loop_t* loop);
343 } // namespace inspector
344 } // namespace jsvm
345 #endif
346