Bug Summary

File:jdk/src/hotspot/os/linux/attachListener_linux.cpp
Warning:line 314, column 9
Value stored to 'v' during its initialization is never read

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 attachListener_linux.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 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/hotspot/variant-server/libjvm/objs/precompiled -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/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 -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 -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/src/hotspot/os/linux/attachListener_linux.cpp
1/*
2 * Copyright (c) 2005, 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 "precompiled.hpp"
26#include "logging/log.hpp"
27#include "memory/allocation.inline.hpp"
28#include "runtime/interfaceSupport.inline.hpp"
29#include "runtime/os.inline.hpp"
30#include "services/attachListener.hpp"
31#include "services/dtraceAttacher.hpp"
32
33#include <unistd.h>
34#include <signal.h>
35#include <sys/types.h>
36#include <sys/socket.h>
37#include <sys/un.h>
38#include <sys/stat.h>
39
40#ifndef UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)
41#define UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path) sizeof(((struct sockaddr_un *)0)->sun_path)
42#endif
43
44// The attach mechanism on Linux uses a UNIX domain socket. An attach listener
45// thread is created at startup or is created on-demand via a signal from
46// the client tool. The attach listener creates a socket and binds it to a file
47// in the filesystem. The attach listener then acts as a simple (single-
48// threaded) server - it waits for a client to connect, reads the request,
49// executes it, and returns the response to the client via the socket
50// connection.
51//
52// As the socket is a UNIX domain socket it means that only clients on the
53// local machine can connect. In addition there are two other aspects to
54// the security:
55// 1. The well known file that the socket is bound to has permission 400
56// 2. When a client connect, the SO_PEERCRED socket option is used to
57// obtain the credentials of client. We check that the effective uid
58// of the client matches this process.
59
60// forward reference
61class LinuxAttachOperation;
62
63class LinuxAttachListener: AllStatic {
64 private:
65 // the path to which we bind the UNIX domain socket
66 static char _path[UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)];
67 static bool _has_path;
68
69 // the file descriptor for the listening socket
70 static volatile int _listener;
71
72 static bool _atexit_registered;
73
74 // reads a request from the given connected socket
75 static LinuxAttachOperation* read_request(int s);
76
77 public:
78 enum {
79 ATTACH_PROTOCOL_VER = 1 // protocol version
80 };
81 enum {
82 ATTACH_ERROR_BADVERSION = 101 // error codes
83 };
84
85 static void set_path(char* path) {
86 if (path == NULL__null) {
87 _path[0] = '\0';
88 _has_path = false;
89 } else {
90 strncpy(_path, path, UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path));
91 _path[UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)-1] = '\0';
92 _has_path = true;
93 }
94 }
95
96 static void set_listener(int s) { _listener = s; }
97
98 // initialize the listener, returns 0 if okay
99 static int init();
100
101 static char* path() { return _path; }
102 static bool has_path() { return _has_path; }
103 static int listener() { return _listener; }
104
105 // write the given buffer to a socket
106 static int write_fully(int s, char* buf, int len);
107
108 static LinuxAttachOperation* dequeue();
109};
110
111class LinuxAttachOperation: public AttachOperation {
112 private:
113 // the connection to the client
114 int _socket;
115
116 public:
117 void complete(jint res, bufferedStream* st);
118
119 void set_socket(int s) { _socket = s; }
120 int socket() const { return _socket; }
121
122 LinuxAttachOperation(char* name) : AttachOperation(name) {
123 set_socket(-1);
124 }
125};
126
127// statics
128char LinuxAttachListener::_path[UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)];
129bool LinuxAttachListener::_has_path;
130volatile int LinuxAttachListener::_listener = -1;
131bool LinuxAttachListener::_atexit_registered = false;
132
133// Supporting class to help split a buffer into individual components
134class ArgumentIterator : public StackObj {
135 private:
136 char* _pos;
137 char* _end;
138 public:
139 ArgumentIterator(char* arg_buffer, size_t arg_size) {
140 _pos = arg_buffer;
141 _end = _pos + arg_size - 1;
142 }
143 char* next() {
144 if (*_pos == '\0') {
145 // advance the iterator if possible (null arguments)
146 if (_pos < _end) {
147 _pos += 1;
148 }
149 return NULL__null;
150 }
151 char* res = _pos;
152 char* next_pos = strchr(_pos, '\0');
153 if (next_pos < _end) {
154 next_pos++;
155 }
156 _pos = next_pos;
157 return res;
158 }
159};
160
161
162// atexit hook to stop listener and unlink the file that it is
163// bound too.
164extern "C" {
165 static void listener_cleanup() {
166 int s = LinuxAttachListener::listener();
167 if (s != -1) {
168 LinuxAttachListener::set_listener(-1);
169 ::shutdown(s, SHUT_RDWRSHUT_RDWR);
170 ::close(s);
171 }
172 if (LinuxAttachListener::has_path()) {
173 ::unlink(LinuxAttachListener::path());
174 LinuxAttachListener::set_path(NULL__null);
175 }
176 }
177}
178
179// Initialization - create a listener socket and bind it to a file
180
181int LinuxAttachListener::init() {
182 char path[UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)]; // socket file
183 char initial_path[UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)]; // socket file during setup
184 int listener; // listener socket (file descriptor)
185
186 // register function to cleanup
187 if (!_atexit_registered) {
188 _atexit_registered = true;
189 ::atexit(listener_cleanup);
190 }
191
192 int n = snprintf(path, UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path), "%s/.java_pid%d",
193 os::get_temp_directory(), os::current_process_id());
194 if (n < (int)UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)) {
195 n = snprintf(initial_path, UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path), "%s.tmp", path);
196 }
197 if (n >= (int)UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)) {
198 return -1;
199 }
200
201 // create the listener socket
202 listener = ::socket(PF_UNIX1, SOCK_STREAMSOCK_STREAM, 0);
203 if (listener == -1) {
204 return -1;
205 }
206
207 // bind socket
208 struct sockaddr_un addr;
209 memset((void *)&addr, 0, sizeof(addr));
210 addr.sun_family = AF_UNIX1;
211 strcpy(addr.sun_path, initial_path);
212 ::unlink(initial_path);
213 int res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr));
214 if (res == -1) {
215 ::close(listener);
216 return -1;
217 }
218
219 // put in listen mode, set permissions, and rename into place
220 res = ::listen(listener, 5);
221 if (res == 0) {
222 RESTARTABLE(::chmod(initial_path, S_IREAD|S_IWRITE), res)do { res = ::chmod(initial_path, 0400|0200); } while(((int)res
== OS_ERR) && ((*__errno_location ()) == 4))
;
223 if (res == 0) {
224 // make sure the file is owned by the effective user and effective group
225 // e.g. the group could be inherited from the directory in case the s bit is set
226 RESTARTABLE(::chown(initial_path, geteuid(), getegid()), res)do { res = ::chown(initial_path, geteuid(), getegid()); } while
(((int)res == OS_ERR) && ((*__errno_location ()) == 4
))
;
227 if (res == 0) {
228 res = ::rename(initial_path, path);
229 }
230 }
231 }
232 if (res == -1) {
233 ::close(listener);
234 ::unlink(initial_path);
235 return -1;
236 }
237 set_path(path);
238 set_listener(listener);
239
240 return 0;
241}
242
243// Given a socket that is connected to a peer we read the request and
244// create an AttachOperation. As the socket is blocking there is potential
245// for a denial-of-service if the peer does not response. However this happens
246// after the peer credentials have been checked and in the worst case it just
247// means that the attach listener thread is blocked.
248//
249LinuxAttachOperation* LinuxAttachListener::read_request(int s) {
250 char ver_str[8];
251 sprintf(ver_str, "%d", ATTACH_PROTOCOL_VER);
252
253 // The request is a sequence of strings so we first figure out the
254 // expected count and the maximum possible length of the request.
255 // The request is:
256 // <ver>0<cmd>0<arg>0<arg>0<arg>0
257 // where <ver> is the protocol version (1), <cmd> is the command
258 // name ("load", "datadump", ...), and <arg> is an argument
259 int expected_str_count = 2 + AttachOperation::arg_count_max;
260 const int max_len = (sizeof(ver_str) + 1) + (AttachOperation::name_length_max + 1) +
261 AttachOperation::arg_count_max*(AttachOperation::arg_length_max + 1);
262
263 char buf[max_len];
264 int str_count = 0;
265
266 // Read until all (expected) strings have been read, the buffer is
267 // full, or EOF.
268
269 int off = 0;
270 int left = max_len;
271
272 do {
273 int n;
274 RESTARTABLE(read(s, buf+off, left), n)do { n = read(s, buf+off, left); } while(((int)n == OS_ERR) &&
((*__errno_location ()) == 4))
;
275 assert(n <= left, "buffer was too small, impossible!")do { if (!(n <= left)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/os/linux/attachListener_linux.cpp"
, 275, "assert(" "n <= left" ") failed", "buffer was too small, impossible!"
); ::breakpoint(); } } while (0)
;
276 buf[max_len - 1] = '\0';
277 if (n == -1) {
278 return NULL__null; // reset by peer or other error
279 }
280 if (n == 0) {
281 break;
282 }
283 for (int i=0; i<n; i++) {
284 if (buf[off+i] == 0) {
285 // EOS found
286 str_count++;
287
288 // The first string is <ver> so check it now to
289 // check for protocol mis-match
290 if (str_count == 1) {
291 if ((strlen(buf) != strlen(ver_str)) ||
292 (atoi(buf) != ATTACH_PROTOCOL_VER)) {
293 char msg[32];
294 sprintf(msg, "%d\n", ATTACH_ERROR_BADVERSION);
295 write_fully(s, msg, strlen(msg));
296 return NULL__null;
297 }
298 }
299 }
300 }
301 off += n;
302 left -= n;
303 } while (left > 0 && str_count < expected_str_count);
304
305 if (str_count != expected_str_count) {
306 return NULL__null; // incomplete request
307 }
308
309 // parse request
310
311 ArgumentIterator args(buf, (max_len)-left);
312
313 // version already checked
314 char* v = args.next();
Value stored to 'v' during its initialization is never read
315
316 char* name = args.next();
317 if (name == NULL__null || strlen(name) > AttachOperation::name_length_max) {
318 return NULL__null;
319 }
320
321 LinuxAttachOperation* op = new LinuxAttachOperation(name);
322
323 for (int i=0; i<AttachOperation::arg_count_max; i++) {
324 char* arg = args.next();
325 if (arg == NULL__null) {
326 op->set_arg(i, NULL__null);
327 } else {
328 if (strlen(arg) > AttachOperation::arg_length_max) {
329 delete op;
330 return NULL__null;
331 }
332 op->set_arg(i, arg);
333 }
334 }
335
336 op->set_socket(s);
337 return op;
338}
339
340
341// Dequeue an operation
342//
343// In the Linux implementation there is only a single operation and clients
344// cannot queue commands (except at the socket level).
345//
346LinuxAttachOperation* LinuxAttachListener::dequeue() {
347 for (;;) {
348 int s;
349
350 // wait for client to connect
351 struct sockaddr addr;
352 socklen_t len = sizeof(addr);
353 RESTARTABLE(::accept(listener(), &addr, &len), s)do { s = ::accept(listener(), &addr, &len); } while((
(int)s == OS_ERR) && ((*__errno_location ()) == 4))
;
354 if (s == -1) {
355 return NULL__null; // log a warning?
356 }
357
358 // get the credentials of the peer and check the effective uid/guid
359 struct ucred cred_info;
360 socklen_t optlen = sizeof(cred_info);
361 if (::getsockopt(s, SOL_SOCKET1, SO_PEERCRED17, (void*)&cred_info, &optlen) == -1) {
362 log_debug(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag::
__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag
::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::
__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<
LogLevel::Debug>
("Failed to get socket option SO_PEERCRED");
363 ::close(s);
364 continue;
365 }
366
367 if (!os::Posix::matches_effective_uid_and_gid_or_root(cred_info.uid, cred_info.gid)) {
368 log_debug(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag::
__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag
::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::
__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<
LogLevel::Debug>
("euid/egid check failed (%d/%d vs %d/%d)",
369 cred_info.uid, cred_info.gid, geteuid(), getegid());
370 ::close(s);
371 continue;
372 }
373
374 // peer credential look okay so we read the request
375 LinuxAttachOperation* op = read_request(s);
376 if (op == NULL__null) {
377 ::close(s);
378 continue;
379 } else {
380 return op;
381 }
382 }
383}
384
385// write the given buffer to the socket
386int LinuxAttachListener::write_fully(int s, char* buf, int len) {
387 do {
388 int n = ::write(s, buf, len);
389 if (n == -1) {
390 if (errno(*__errno_location ()) != EINTR4) return -1;
391 } else {
392 buf += n;
393 len -= n;
394 }
395 }
396 while (len > 0);
397 return 0;
398}
399
400// Complete an operation by sending the operation result and any result
401// output to the client. At this time the socket is in blocking mode so
402// potentially we can block if there is a lot of data and the client is
403// non-responsive. For most operations this is a non-issue because the
404// default send buffer is sufficient to buffer everything. In the future
405// if there are operations that involves a very big reply then it the
406// socket could be made non-blocking and a timeout could be used.
407
408void LinuxAttachOperation::complete(jint result, bufferedStream* st) {
409 JavaThread* thread = JavaThread::current();
410 ThreadBlockInVM tbivm(thread);
411
412 // write operation result
413 char msg[32];
414 sprintf(msg, "%d\n", result);
415 int rc = LinuxAttachListener::write_fully(this->socket(), msg, strlen(msg));
416
417 // write any result data
418 if (rc == 0) {
419 LinuxAttachListener::write_fully(this->socket(), (char*) st->base(), st->size());
420 ::shutdown(this->socket(), 2);
421 }
422
423 // done
424 ::close(this->socket());
425
426 delete this;
427}
428
429
430// AttachListener functions
431
432AttachOperation* AttachListener::dequeue() {
433 JavaThread* thread = JavaThread::current();
434 ThreadBlockInVM tbivm(thread);
435
436 AttachOperation* op = LinuxAttachListener::dequeue();
437
438 return op;
439}
440
441// Performs initialization at vm startup
442// For Linux we remove any stale .java_pid file which could cause
443// an attaching process to think we are ready to receive on the
444// domain socket before we are properly initialized
445
446void AttachListener::vm_start() {
447 char fn[UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)];
448 struct stat64 st;
449 int ret;
450
451 int n = snprintf(fn, UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path), "%s/.java_pid%d",
452 os::get_temp_directory(), os::current_process_id());
453 assert(n < (int)UNIX_PATH_MAX, "java_pid file name buffer overflow")do { if (!(n < (int)sizeof(((struct sockaddr_un *)0)->sun_path
))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/os/linux/attachListener_linux.cpp"
, 453, "assert(" "n < (int)sizeof(((struct sockaddr_un *)0)->sun_path)"
") failed", "java_pid file name buffer overflow"); ::breakpoint
(); } } while (0)
;
454
455 RESTARTABLE(::stat64(fn, &st), ret)do { ret = ::stat64(fn, &st); } while(((int)ret == OS_ERR
) && ((*__errno_location ()) == 4))
;
456 if (ret == 0) {
457 ret = ::unlink(fn);
458 if (ret == -1) {
459 log_debug(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag::
__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag
::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::
__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<
LogLevel::Debug>
("Failed to remove stale attach pid file at %s", fn);
460 }
461 }
462}
463
464int AttachListener::pd_init() {
465 JavaThread* thread = JavaThread::current();
466 ThreadBlockInVM tbivm(thread);
467
468 int ret_code = LinuxAttachListener::init();
469
470 return ret_code;
471}
472
473bool AttachListener::check_socket_file() {
474 int ret;
475 struct stat64 st;
476 ret = stat64(LinuxAttachListener::path(), &st);
477 if (ret == -1) { // need to restart attach listener.
478 log_debug(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag::
__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag
::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::
__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<
LogLevel::Debug>
("Socket file %s does not exist - Restart Attach Listener",
479 LinuxAttachListener::path());
480
481 listener_cleanup();
482
483 // wait to terminate current attach listener instance...
484 {
485 // avoid deadlock if AttachListener thread is blocked at safepoint
486 ThreadBlockInVM tbivm(JavaThread::current());
487 while (AttachListener::transit_state(AL_INITIALIZING,
488 AL_NOT_INITIALIZED) != AL_NOT_INITIALIZED) {
489 os::naked_yield();
490 }
491 }
492 return is_init_trigger();
493 }
494 return false;
495}
496
497// Attach Listener is started lazily except in the case when
498// +ReduseSignalUsage is used
499bool AttachListener::init_at_startup() {
500 if (ReduceSignalUsage) {
501 return true;
502 } else {
503 return false;
504 }
505}
506
507// If the file .attach_pid<pid> exists in the working directory
508// or /tmp then this is the trigger to start the attach mechanism
509bool AttachListener::is_init_trigger() {
510 if (init_at_startup() || is_initialized()) {
511 return false; // initialized at startup or already initialized
512 }
513 char fn[PATH_MAX4096 + 1];
514 int ret;
515 struct stat64 st;
516 sprintf(fn, ".attach_pid%d", os::current_process_id());
517 RESTARTABLE(::stat64(fn, &st), ret)do { ret = ::stat64(fn, &st); } while(((int)ret == OS_ERR
) && ((*__errno_location ()) == 4))
;
518 if (ret == -1) {
519 log_trace(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag::
__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
)>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl<(LogTag
::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::
__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<
LogLevel::Trace>
("Failed to find attach file: %s, trying alternate", fn);
520 snprintf(fn, sizeof(fn), "%s/.attach_pid%d",
521 os::get_temp_directory(), os::current_process_id());
522 RESTARTABLE(::stat64(fn, &st), ret)do { ret = ::stat64(fn, &st); } while(((int)ret == OS_ERR
) && ((*__errno_location ()) == 4))
;
523 if (ret == -1) {
524 log_debug(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag::
__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag
::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::
__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<
LogLevel::Debug>
("Failed to find attach file: %s", fn);
525 }
526 }
527 if (ret == 0) {
528 // simple check to avoid starting the attach mechanism when
529 // a bogus non-root user creates the file
530 if (os::Posix::matches_effective_uid_or_root(st.st_uid)) {
531 init();
532 log_trace(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag::
__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
)>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl<(LogTag
::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::
__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<
LogLevel::Trace>
("Attach triggered by %s", fn);
533 return true;
534 } else {
535 log_debug(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag::
__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag
::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::
__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<
LogLevel::Debug>
("File %s has wrong user id %d (vs %d). Attach is not triggered", fn, st.st_uid, geteuid());
536 }
537 }
538 return false;
539}
540
541// if VM aborts then remove listener
542void AttachListener::abort() {
543 listener_cleanup();
544}
545
546void AttachListener::pd_data_dump() {
547 os::signal_notify(SIGQUIT3);
548}
549
550AttachOperationFunctionInfo* AttachListener::pd_find_operation(const char* n) {
551 return NULL__null;
552}
553
554jint AttachListener::pd_set_flag(AttachOperation* op, outputStream* out) {
555 out->print_cr("flag '%s' cannot be changed", op->arg(0));
556 return JNI_ERR(-1);
557}
558
559void AttachListener::pd_detachall() {
560 // do nothing for now
561}