Bug Summary

File:jdk/test/hotspot/gtest/gtestMain.cpp
Warning:line 289, column 16
Potential leak of memory pointed to by 'argv'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name gtestMain.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mthread-model posix -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-10/lib/clang/10.0.0 -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -D __STDC_CONSTANT_MACROS -D _GNU_SOURCE -D _REENTRANT -D LIBC=gnu -D LINUX -D VM_LITTLE_ENDIAN -D _LP64=1 -D ASSERT -D CHECK_UNHANDLED_OOPS -D TARGET_ARCH_x86 -D INCLUDE_SUFFIX_OS=_linux -D INCLUDE_SUFFIX_CPU=_x86 -D INCLUDE_SUFFIX_COMPILER=_gcc -D TARGET_COMPILER_gcc -D AMD64 -D HOTSPOT_LIB_ARCH="amd64" -D COMPILER1 -D COMPILER2 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/hotspot/variant-server/gensrc/adfiles -I /home/daniel/Projects/java/jdk/src/hotspot/share -I /home/daniel/Projects/java/jdk/src/hotspot/os/linux -I /home/daniel/Projects/java/jdk/src/hotspot/os/posix -I /home/daniel/Projects/java/jdk/src/hotspot/cpu/x86 -I /home/daniel/Projects/java/jdk/src/hotspot/os_cpu/linux_x86 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/hotspot/variant-server/gensrc -I /home/daniel/Projects/java/jdk/src/hotspot/share/precompiled -I /home/daniel/Projects/java/jdk/src/hotspot/share/include -I /home/daniel/Projects/java/jdk/src/hotspot/os/posix/include -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base/linux -I /home/daniel/Projects/java/jdk/src/java.base/share/native/libjimage -I /home/daniel/Projects/java/googletest/googletest/include -I /home/daniel/Projects/java/googletest/googlemock/include -I /home/daniel/Projects/java/jdk/test/hotspot/gtest -I /home/daniel/Projects/java/jdk/test/hotspot/gtest -D _FORTIFY_SOURCE=2 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/x86_64-linux-gnu/c++/7.5.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/x86_64-linux-gnu/c++/7.5.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-10/lib/clang/10.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-format-zero-length -Wno-unused-parameter -Wno-unused -Wno-parentheses -Wno-comment -Wno-unknown-pragmas -Wno-address -Wno-delete-non-virtual-dtor -Wno-char-subscripts -Wno-array-bounds -Wno-int-in-bool-context -Wno-ignored-qualifiers -Wno-missing-field-initializers -Wno-implicit-fallthrough -Wno-empty-body -Wno-strict-overflow -Wno-sequence-point -Wno-maybe-uninitialized -Wno-misleading-indentation -Wno-cast-function-type -Wno-shift-negative-value -Wno-undef -Wno-stringop-overflow -std=c++14 -fdeprecated-macro -fdebug-compilation-dir /home/daniel/Projects/java/jdk/make/hotspot -ferror-limit 19 -fmessage-length 0 -fvisibility hidden -stack-protector 1 -fno-rtti -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /home/daniel/Projects/java/scan/2021-12-21-193737-8510-1 -x c++ /home/daniel/Projects/java/jdk/test/hotspot/gtest/gtestMain.cpp
1/*
2 * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#include <stdio.h>
26#include <string.h>
27#include <stdlib.h>
28#ifdef __APPLE__
29# include <dlfcn.h>
30#endif
31
32#ifdef _WIN32
33#include <windows.h>
34#else
35#include <pthread.h>
36#endif
37
38#include "jni.h"
39#include "unittest.hpp"
40
41#include "runtime/thread.inline.hpp"
42
43// Default value for -new-thread option: true on AIX because we run into
44// problems when attempting to initialize the JVM on the primordial thread.
45#ifdef _AIX
46const static bool DEFAULT_SPAWN_IN_NEW_THREAD = true;
47#else
48const static bool DEFAULT_SPAWN_IN_NEW_THREAD = false;
49#endif
50
51static bool is_prefix(const char* prefix, const char* str) {
52 return strncmp(str, prefix, strlen(prefix)) == 0;
53}
54
55static bool is_suffix(const char* suffix, const char* str) {
56 size_t suffix_len = strlen(suffix);
57 size_t str_len = strlen(str);
58 if (str_len < suffix_len) {
59 return false;
60 }
61 return strncmp(str + (str_len - suffix_len), suffix, suffix_len) == 0;
62}
63
64static int init_jvm(int argc, char **argv, bool disable_error_handling, JavaVM** jvm_ptr) {
65 // don't care about the program name
66 argc--;
67 argv++;
68
69 int extra_jvm_args = disable_error_handling ? 4 : 2;
70 int num_jvm_options = argc + extra_jvm_args;
71
72 JavaVMOption* options = new JavaVMOption[num_jvm_options];
73 options[0].optionString = (char*) "-Dsun.java.launcher.is_altjvm=true";
74 options[1].optionString = (char*) "-XX:+ExecutingUnitTests";
75
76 if (disable_error_handling) {
77 // don't create core files or hs_err files executing assert tests
78 options[2].optionString = (char*) "-XX:+SuppressFatalErrorMessage";
79 options[3].optionString = (char*) "-XX:-CreateCoredumpOnCrash";
80 }
81
82 for (int i = 0; i < argc; i++) {
83 options[extra_jvm_args + i].optionString = argv[i];
84 }
85
86 JavaVMInitArgs args;
87 args.version = JNI_VERSION_1_80x00010008;
88 args.nOptions = num_jvm_options;
89 args.options = options;
90 args.ignoreUnrecognized = JNI_FALSE0;
91
92 JNIEnv* env;
93
94 int ret = JNI_CreateJavaVM(jvm_ptr, (void**)&env, &args);
95 if (ret == JNI_OK0) {
96 // CreateJavaVM leaves WXExec context, while gtests
97 // calls internal functions assuming running in WXWwrite.
98 // Switch to WXWrite once for all test cases.
99 MACOS_AARCH64_ONLY(Thread::current()->enable_wx(WXWrite));
100 }
101 return ret;
102}
103
104static bool is_same_vm_test(const char* name) {
105 return is_suffix("_vm", name) && !is_suffix("_other_vm", name);
106}
107
108class JVMInitializerListener : public ::testing::EmptyTestEventListener {
109 private:
110 int _argc;
111 char** _argv;
112 JavaVM* _jvm;
113
114 public:
115 JVMInitializerListener(int argc, char** argv) :
116 _argc(argc), _argv(argv), _jvm(nullptr) {
117 }
118
119 virtual void OnTestStart(const ::testing::TestInfo& test_info) {
120 const char* name = test_info.name();
121 if (_jvm == nullptr && is_same_vm_test(name)) {
122 // we want to have hs_err and core files when we execute regular tests
123 int ret_val = init_jvm(_argc, _argv, false, &_jvm);
124 if (ret_val != 0) {
125 ADD_FAILURE()::testing::internal::AssertHelper(::testing::TestPartResult::
kNonFatalFailure, "/home/daniel/Projects/java/jdk/test/hotspot/gtest/gtestMain.cpp"
, 125, "Failed") = ::testing::Message()
<< "Could not initialize the JVM: " << ret_val;
126 exit(1);
127 }
128 }
129 }
130
131 void destroy_jvm() {
132 if (_jvm != NULL__null) {
133 int ret = _jvm->DestroyJavaVM();
134 if (ret != 0) {
135 fprintf(stderrstderr, "Warning: DestroyJavaVM error %d\n", ret);
136 }
137 }
138 }
139};
140
141static char* get_java_home_arg(int argc, char** argv) {
142 for (int i = 0; i < argc; i++) {
143 if (strncmp(argv[i], "-jdk", strlen(argv[i])) == 0) {
144 return argv[i+1];
145 }
146 if (is_prefix("--jdk=", argv[i])) {
147 return argv[i] + strlen("--jdk=");
148 }
149 if (is_prefix("-jdk:", argv[i])) {
150 return argv[i] + strlen("-jdk:");
151 }
152 }
153 return NULL__null;
154}
155
156static bool get_spawn_new_main_thread_arg(int argc, char** argv) {
157 // -new-thread[=(true|false)]
158 for (int i = 0; i < argc; i++) {
159 if (is_prefix("-new-thread", argv[i])) {
160 const char* v = argv[i] + strlen("-new-thread");
161 if (strlen(v) == 0) {
162 return true;
163 } else {
164 if (strcmp(v, "=true") == 0) {
165 return true;
166 } else if (strcmp(v, "=false") == 0) {
167 return false;
168 } else {
169 fprintf(stderrstderr, "Invalid value for -new-thread (%s)", v);
170 }
171 }
172 }
173 }
174 return DEFAULT_SPAWN_IN_NEW_THREAD;
175}
176
177static int num_args_to_skip(char* arg) {
178 if (strcmp(arg, "-jdk") == 0) {
179 return 2; // skip the argument after -jdk as well
180 }
181 if (is_prefix("--jdk=", arg)) {
182 return 1;
183 }
184 if (is_prefix("-jdk:", arg)) {
185 return 1;
186 }
187 if (is_prefix("-new-thread", arg)) {
188 return 1;
189 }
190 return 0;
191}
192
193static char** remove_test_runner_arguments(int* argcp, char **argv) {
194 int argc = *argcp;
195 char** new_argv = (char**) malloc(sizeof(char*) * argc);
9
Memory is allocated
196 int new_argc = 0;
197
198 int i = 0;
199 while (i < argc) {
10
Assuming 'i' is >= 'argc'
11
Loop condition is false. Execution continues on line 210
200 int args_to_skip = num_args_to_skip(argv[i]);
201 if (args_to_skip == 0) {
202 new_argv[new_argc] = argv[i];
203 i++;
204 new_argc++;
205 } else {
206 i += num_args_to_skip(argv[i]);
207 }
208 }
209
210 *argcp = new_argc;
211 return new_argv;
212}
213
214// This is generally run once for a set of tests. But if that set includes a vm_assert or
215// other_vm test, then a new process is forked, and runUnitTestsInner is called, passing
216// just that test as the one to be executed.
217//
218// When we execute a vm_assert or other_vm test we create and initialize the JVM below.
219//
220// A vm_assert test crashes the VM so no cleanup is needed, but for other_vm we call
221// DestroyJavaVM via the TEST_OTHER_VM macro prior to the call to exit().
222//
223// For same_vm tests we use an event listener to create the JVM when the first same_vm
224// test is executed. Once all tests are completed we can then call DestroyJavaVM on that
225// JVM directly.
226static void runUnitTestsInner(int argc, char** argv) {
227 ::testing::InitGoogleMock(&argc, argv);
228 ::testing::GTEST_FLAG(death_test_style)FLAGS_gtest_death_test_style = "threadsafe";
229
230 bool is_vmassert_test = false;
231 bool is_othervm_test = false;
232 // death tests facility is used for both regular death tests, other vm and vmassert tests
233 if (::testing::internal::GTEST_FLAG(internal_run_death_test)FLAGS_gtest_internal_run_death_test.length() > 0) {
3
Assuming the condition is true
4
Taking true branch
234 // when we execute death test, filter value equals to test name
235 const char* test_name = ::testing::GTEST_FLAG(filter)FLAGS_gtest_filter.c_str();
236 const char* const othervm_suffix = "_other_vm"; // TEST_OTHER_VM
237 const char* const vmassert_suffix = "_vm_assert"; // TEST_VM_ASSERT(_MSG)
238 if (is_suffix(othervm_suffix, test_name)) {
5
Taking true branch
239 is_othervm_test = true;
240 } else if (is_suffix(vmassert_suffix, test_name)) {
241 is_vmassert_test = true;
242 }
243 }
244
245 char* java_home = get_java_home_arg(argc, argv);
246 if (java_home == NULL__null) {
6
Assuming 'java_home' is not equal to NULL
7
Taking false branch
247 fprintf(stderrstderr, "ERROR: You must specify a JDK to use for running the unit tests.\n");
248 exit(1);
249 }
250#ifndef _WIN32
251 int overwrite = 1; // overwrite an eventual existing value for JAVA_HOME
252 setenv("JAVA_HOME", java_home, overwrite);
253
254// workaround for JDK-7131356
255#ifdef __APPLE__
256 size_t len = strlen(java_home) + strlen("/lib/jli/libjli.dylib") + 1;
257 char* path = new char[len];
258 snprintf(path, len, "%s/lib/jli/libjli.dylib", java_home);
259 dlopen(path, RTLD_NOW0x00002 | RTLD_GLOBAL0x00100);
260#endif // __APPLE__
261
262#else // _WIN32
263 const char* java_home_var = "_ALT_JAVA_HOME_DIR";
264 size_t len = strlen(java_home) + strlen(java_home_var) + 2;
265 char * envString = new char[len];
266 sprintf_s(envString, len, "%s=%s", java_home_var, java_home);
267 _putenv(envString);
268#endif // _WIN32
269 argv = remove_test_runner_arguments(&argc, argv);
8
Calling 'remove_test_runner_arguments'
12
Returned allocated memory
270
271
272 JVMInitializerListener* jvm_listener = NULL__null;
273
274 if (is_vmassert_test
12.1
'is_vmassert_test' is false
|| is_othervm_test
12.2
'is_othervm_test' is true
) {
13
Taking true branch
275 JavaVM* jvm = NULL__null;
276 // both vmassert and other vm tests require inited jvm
277 // but only vmassert tests disable hs_err and core file generation
278 int ret;
279 if ((ret = init_jvm(argc, argv, is_vmassert_test, &jvm)) != 0) {
14
Taking false branch
280 fprintf(stderrstderr, "ERROR: JNI_CreateJavaVM failed: %d\n", ret);
281 abort();
282 }
283 } else {
284 ::testing::TestEventListeners& listeners = ::testing::UnitTest::GetInstance()->listeners();
285 jvm_listener = new JVMInitializerListener(argc, argv);
286 listeners.Append(jvm_listener);
287 }
288
289 int result = RUN_ALL_TESTS();
15
Potential leak of memory pointed to by 'argv'
290
291 // vm_assert and other_vm tests never reach this point as they either abort, or call
292 // exit() - see TEST_OTHER_VM macro. We will reach here when all same_vm tests have
293 // completed for this run, so we can terminate the VM used for that case.
294
295 if (result != 0) {
296 fprintf(stderrstderr, "ERROR: RUN_ALL_TESTS() failed. Error %d\n", result);
297 exit(2);
298 }
299
300 if (jvm_listener != NULL__null) {
301 jvm_listener->destroy_jvm();
302 }
303}
304
305// Thread support for -new-thread option
306
307struct args_t {
308 int argc; char** argv;
309};
310
311#define STACK_SIZE0x200000 0x200000
312
313#ifdef _WIN32
314
315static DWORD WINAPI thread_wrapper(void* p) {
316 const args_t* const p_args = (const args_t*) p;
317 runUnitTestsInner(p_args->argc, p_args->argv);
318 return 0;
319}
320
321static void run_in_new_thread(const args_t* args) {
322 HANDLE hdl;
323 hdl = CreateThread(NULL__null, STACK_SIZE0x200000, thread_wrapper, (void*)args, 0, NULL__null);
324 if (hdl == NULL__null) {
325 fprintf(stderrstderr, "Failed to create main thread\n");
326 exit(2);
327 }
328 WaitForSingleObject(hdl, INFINITE);
329}
330
331#else
332
333extern "C" void* thread_wrapper(void* p) {
334 const args_t* const p_args = (const args_t*) p;
335 runUnitTestsInner(p_args->argc, p_args->argv);
336 return 0;
337}
338
339static void run_in_new_thread(const args_t* args) {
340 pthread_t tid;
341 pthread_attr_t attr;
342
343 pthread_attr_init(&attr);
344 pthread_attr_setstacksize(&attr, STACK_SIZE0x200000);
345
346 if (pthread_create(&tid, &attr, thread_wrapper, (void*)args) != 0) {
347 fprintf(stderrstderr, "Failed to create main thread\n");
348 exit(2);
349 }
350
351 if (pthread_join(tid, NULL__null) != 0) {
352 fprintf(stderrstderr, "Failed to join main thread\n");
353 exit(2);
354 }
355}
356
357#endif
358
359extern "C"
360JNIEXPORT__attribute__((visibility("default"))) void JNICALL runUnitTests(int argc, char** argv) {
361 const bool spawn_new_main_thread = get_spawn_new_main_thread_arg(argc, argv);
362 if (spawn_new_main_thread
0.1
'spawn_new_main_thread' is false
) {
1
Taking false branch
363 args_t args;
364 args.argc = argc;
365 args.argv = argv;
366 run_in_new_thread(&args);
367 } else {
368 runUnitTestsInner(argc, argv);
2
Calling 'runUnitTestsInner'
369 }
370}