-
Notifications
You must be signed in to change notification settings - Fork 29.7k
/
node_sea.cc
130 lines (105 loc) Β· 3.67 KB
/
node_sea.cc
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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "node_sea.h"
#include "env-inl.h"
#include "node_external_reference.h"
#include "node_internals.h"
#include "node_union_bytes.h"
#include "simdutf.h"
#include "v8.h"
// The POSTJECT_SENTINEL_FUSE macro is a string of random characters selected by
// the Node.js project that is present only once in the entire binary. It is
// used by the postject_has_resource() function to efficiently detect if a
// resource has been injected. See
// https://github.com/nodejs/postject/blob/35343439cac8c488f2596d7c4c1dddfec1fddcae/postject-api.h#L42-L45.
#define POSTJECT_SENTINEL_FUSE "NODE_JS_FUSE_fce680ab2cc467b6e072b8b5df1996b2"
#include "postject-api.h"
#undef POSTJECT_SENTINEL_FUSE
#include <memory>
#include <string_view>
#include <tuple>
#include <vector>
#if !defined(DISABLE_SINGLE_EXECUTABLE_APPLICATION)
using v8::Context;
using v8::FunctionCallbackInfo;
using v8::Local;
using v8::Object;
using v8::Value;
namespace {
const std::string_view FindSingleExecutableCode() {
static const std::string_view sea_code = []() -> std::string_view {
size_t size;
#ifdef __APPLE__
postject_options options;
postject_options_init(&options);
options.macho_segment_name = "NODE_JS";
const char* code = static_cast<const char*>(
postject_find_resource("NODE_JS_CODE", &size, &options));
#else
const char* code = static_cast<const char*>(
postject_find_resource("NODE_JS_CODE", &size, nullptr));
#endif
return {code, size};
}();
return sea_code;
}
void GetSingleExecutableCode(const FunctionCallbackInfo<Value>& args) {
node::Environment* env = node::Environment::GetCurrent(args);
static const std::string_view sea_code = FindSingleExecutableCode();
if (sea_code.empty()) {
return;
}
// TODO(joyeecheung): Use one-byte strings for ASCII-only source to save
// memory/binary size - using UTF16 by default results in twice of the size
// than necessary.
static const node::UnionBytes sea_code_union_bytes =
[]() -> node::UnionBytes {
size_t expected_u16_length =
simdutf::utf16_length_from_utf8(sea_code.data(), sea_code.size());
auto out = std::make_shared<std::vector<uint16_t>>(expected_u16_length);
size_t u16_length = simdutf::convert_utf8_to_utf16(
sea_code.data(),
sea_code.size(),
reinterpret_cast<char16_t*>(out->data()));
out->resize(u16_length);
return node::UnionBytes{out};
}();
args.GetReturnValue().Set(
sea_code_union_bytes.ToStringChecked(env->isolate()));
}
} // namespace
namespace node {
namespace sea {
bool IsSingleExecutable() {
return postject_has_resource();
}
std::tuple<int, char**> FixupArgsForSEA(int argc, char** argv) {
// Repeats argv[0] at position 1 on argv as a replacement for the missing
// entry point file path.
if (IsSingleExecutable()) {
char** new_argv = new char*[argc + 2];
int new_argc = 0;
new_argv[new_argc++] = argv[0];
new_argv[new_argc++] = argv[0];
for (int i = 1; i < argc; ++i) {
new_argv[new_argc++] = argv[i];
}
new_argv[new_argc] = nullptr;
argc = new_argc;
argv = new_argv;
}
return {argc, argv};
}
void Initialize(Local<Object> target,
Local<Value> unused,
Local<Context> context,
void* priv) {
SetMethod(
context, target, "getSingleExecutableCode", GetSingleExecutableCode);
}
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(GetSingleExecutableCode);
}
} // namespace sea
} // namespace node
NODE_BINDING_CONTEXT_AWARE_INTERNAL(sea, node::sea::Initialize)
NODE_BINDING_EXTERNAL_REFERENCE(sea, node::sea::RegisterExternalReferences)
#endif // !defined(DISABLE_SINGLE_EXECUTABLE_APPLICATION)