Coverage Report

Created: 2025-08-28 09:57

/src/node/test/fuzzers/fuzz_strings.cc
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * A fuzzer focused on C string -> Javascript String.
3
*/
4
5
#include <stdlib.h>
6
#include "js_native_api.h"
7
#include "js_native_api_v8.h"
8
#include "node.h"
9
#include "node_platform.h"
10
#include "node_internals.h"
11
#include "node_api_internals.h"
12
#include "node_url.h"
13
#include "env-inl.h"
14
#include "util-inl.h"
15
#include "v8.h"
16
#include "libplatform/libplatform.h"
17
#include "aliased_buffer.h"
18
#include "fuzz_helper.h"
19
20
using node::AliasedBufferBase;
21
22
/* General set up */
23
using ArrayBufferUniquePtr = std::unique_ptr<node::ArrayBufferAllocator,
24
  decltype(&node::FreeArrayBufferAllocator)>;
25
using TracingAgentUniquePtr = std::unique_ptr<node::tracing::Agent>;
26
using NodePlatformUniquePtr = std::unique_ptr<node::NodePlatform>;
27
28
static TracingAgentUniquePtr tracing_agent;
29
static NodePlatformUniquePtr platform;
30
static uv_loop_t current_loop;
31
static napi_env addon_env;
32
33
inline napi_env NewEnv(v8::Local<v8::Context> context,
34
                       const std::string& module_filename,
35
                       int32_t module_api_version);
36
37
0
static void free_string(node_api_nogc_env env, void* data, void* hint) {
38
0
  free(data);
39
0
}
40
41
122k
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
42
122k
  uv_os_unsetenv("NODE_OPTIONS");
43
122k
  std::vector<std::string> node_argv{ "fuzz_string_conversion" };
44
122k
  std::vector<std::string> exec_argv;
45
122k
  std::vector<std::string> errors;
46
47
122k
  node::InitializeNodeWithArgs(&node_argv, &exec_argv, &errors);
48
49
122k
  tracing_agent = std::make_unique<node::tracing::Agent>();
50
122k
  node::tracing::TraceEventHelper::SetAgent(tracing_agent.get());
51
122k
  node::tracing::TracingController* tracing_controller =
52
122k
    tracing_agent->GetTracingController();  
53
122k
  CHECK_EQ(0, uv_loop_init(&current_loop));
54
122k
  static constexpr int kV8ThreadPoolSize = 4;
55
122k
  platform.reset(
56
122k
    new node::NodePlatform(kV8ThreadPoolSize, tracing_controller));
57
122k
  v8::V8::InitializePlatform(platform.get());
58
122k
  cppgc::InitializeProcess(platform->GetPageAllocator());
59
122k
  v8::V8::Initialize();
60
122k
  return 0;
61
122k
}
62
63
class FuzzerFixtureHelper {
64
public:
65
  v8::Isolate* isolate_;
66
  ArrayBufferUniquePtr allocator;
67
68
  FuzzerFixtureHelper()
69
122k
    : allocator(ArrayBufferUniquePtr(node::CreateArrayBufferAllocator(),
70
122k
                                     &node::FreeArrayBufferAllocator)) {
71
122k
    isolate_ = NewIsolate(allocator.get(), &current_loop, platform.get());
72
122k
    CHECK_NOT_NULL(isolate_);
73
122k
    isolate_->Enter();
74
122k
  };
75
76
122k
  void Teardown() {
77
122k
    platform->DrainTasks(isolate_);
78
122k
    isolate_->Exit();
79
122k
    platform->UnregisterIsolate(isolate_);
80
122k
    isolate_->Dispose();
81
122k
    isolate_ = nullptr;
82
122k
  }
83
};
84
85
7.51k
void EnvTest(v8::Isolate* isolate_, char* env_string, size_t size) {
86
7.51k
  const v8::HandleScope handle_scope(isolate_);
87
7.51k
  Argv argv;
88
89
7.51k
  node::EnvironmentFlags::Flags flags = node::EnvironmentFlags::kDefaultFlags;
90
7.51k
  auto isolate = handle_scope.GetIsolate();
91
7.51k
  v8::Local<v8::Context> context_ = node::NewContext(isolate);
92
7.51k
  context_->Enter();
93
94
7.51k
  node::IsolateData* isolate_data_ = node::CreateIsolateData(isolate, &current_loop,
95
7.51k
                                                             platform.get());
96
7.51k
  std::vector<std::string> args(*argv, *argv + 1);
97
7.51k
  std::vector<std::string> exec_args(*argv, *argv + 1);
98
7.51k
  node::Environment* environment_ = node::CreateEnvironment(isolate_data_,
99
7.51k
                                          context_, args, exec_args, flags);
100
7.51k
  node::Environment* envi = environment_;
101
7.51k
  SetProcessExitHandler(envi, [&](node::Environment* env_, int exit_code) {
102
0
    node::Stop(envi);
103
0
  });
104
7.51k
  node::LoadEnvironment(envi, "");
105
106
107
7.51k
  napi_addon_register_func init = [](napi_env env, napi_value exports) {
108
7.51k
    addon_env = env;
109
7.51k
    return exports;
110
7.51k
  };
111
7.51k
  v8::Local<v8::Object> module_obj = v8::Object::New(isolate);
112
7.51k
  v8::Local<v8::Object> exports_obj = v8::Object::New(isolate);
113
7.51k
  napi_module_register_by_symbol(
114
7.51k
      exports_obj, module_obj, context_, init, NAPI_VERSION);
115
7.51k
  size_t copied1, copied2;
116
7.51k
  bool copied3;
117
7.51k
  napi_value output1, output2, output3, output4, output5, output6, output7, output8, output9, output10, output11, output12;
118
7.51k
  char *buf1 = (char *)malloc(size);
119
7.51k
  char *buf2 = (char *)malloc(size);
120
7.51k
  napi_create_string_utf8(addon_env, env_string, size, &output1);
121
7.51k
  napi_get_value_string_utf8(addon_env, output1, buf1, size, &copied1);
122
7.51k
  napi_create_string_latin1(addon_env, env_string, size, &output2);
123
7.51k
  napi_get_value_string_latin1(addon_env, output2, buf2, size, &copied2);
124
125
7.51k
  char* string_copy;
126
7.51k
  const size_t actual_length =
127
7.51k
      (size == NAPI_AUTO_LENGTH ? strlen(env_string) : size);
128
7.51k
  const size_t length_bytes = (actual_length + 1) * sizeof(*string_copy);
129
7.51k
  string_copy = (char *)malloc(length_bytes);
130
7.51k
  memcpy(string_copy, env_string, length_bytes);
131
7.51k
  string_copy[actual_length] = 0;
132
133
  //node_api_create_external_string_latin1(addon_env, string_copy, size, free_string, NULL, output3, &copied3);
134
135
7.51k
  node_api_symbol_for(addon_env, env_string, size, &output4);
136
137
7.51k
  napi_set_named_property(addon_env, output1, env_string, output2); // could use other napi_values than 'output1'
138
139
7.51k
  napi_get_named_property(addon_env, output1, env_string, &output6); // could use other napi_values than 'output1'
140
141
7.51k
  napi_has_named_property(addon_env, output1, env_string, &copied3); // could use other napi_values than 'output1'
142
143
7.51k
  napi_get_property_names(addon_env, output1, &output7); // could use other napi_values than 'output1'
144
145
7.51k
  napi_has_property(addon_env, output1, output2, &copied3); // could use other napi_values than 'output1/2'
146
147
7.51k
  napi_get_property(addon_env, output1, output2, &output8); // could use other napi_values than 'output1/2'
148
149
7.51k
  napi_delete_property(addon_env, output1, output2, &copied3); // could use other napi_values than 'output1/2'
150
151
7.51k
  napi_has_own_property(addon_env, output1, output2, &copied3); // could use other napi_values than 'output1/2'
152
153
7.51k
  napi_create_type_error(addon_env, output1, output2, &output9); // could use other napi_values than 'output1/2'
154
155
7.51k
  napi_create_range_error(addon_env, output1, output2, &output10); // could use other napi_values than 'output1/2'
156
157
7.51k
  node_api_create_syntax_error(addon_env, output1, output2, &output11); // could use other napi_values than 'output1/2'
158
159
7.51k
  napi_run_script(addon_env, output2, &output12); // could use other napi_values than 'output2'
160
161
  //napi_is_array(addon_env, output1, copied3); // could use other napi_values than 'output1'
162
  
163
7.51k
  free(string_copy);
164
7.51k
  free(buf1);
165
7.51k
  free(buf2);
166
167
  // Cleanup!
168
7.51k
  node::FreeEnvironment(environment_);
169
7.51k
  node::FreeIsolateData(isolate_data_);
170
7.51k
  context_->Exit();
171
7.51k
}
172
173
33.0k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data2, size_t size) {
174
33.0k
  FuzzerFixtureHelper ffh;
175
33.0k
  std::string s(reinterpret_cast<const char*>(data2), size);
176
33.0k
  EnvTest(ffh.isolate_, (char*)s.c_str(), size);
177
33.0k
  ffh.Teardown();
178
33.0k
  return 0;
179
33.0k
}