File: | jdk/src/jdk.jdwp.agent/share/native/libjdwp/debugLoop.c |
Warning: | line 271, column 16 Access to field 'packet' results in a dereference of a null pointer (loaded from variable 'pL') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright (c) 1998, 2020, 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. Oracle designates this | |||
8 | * particular file as subject to the "Classpath" exception as provided | |||
9 | * by Oracle in the LICENSE file that accompanied this code. | |||
10 | * | |||
11 | * This code is distributed in the hope that it will be useful, but WITHOUT | |||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
14 | * version 2 for more details (a copy is included in the LICENSE file that | |||
15 | * accompanied this code). | |||
16 | * | |||
17 | * You should have received a copy of the GNU General Public License version | |||
18 | * 2 along with this work; if not, write to the Free Software Foundation, | |||
19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |||
20 | * | |||
21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |||
22 | * or visit www.oracle.com if you need additional information or have any | |||
23 | * questions. | |||
24 | */ | |||
25 | ||||
26 | #include "util.h" | |||
27 | #include "transport.h" | |||
28 | #include "debugLoop.h" | |||
29 | #include "debugDispatch.h" | |||
30 | #include "standardHandlers.h" | |||
31 | #include "inStream.h" | |||
32 | #include "outStream.h" | |||
33 | #include "threadControl.h" | |||
34 | ||||
35 | ||||
36 | static void JNICALL reader(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg); | |||
37 | static void enqueue(jdwpPacket *p); | |||
38 | static jboolean dequeue(jdwpPacket *p); | |||
39 | static void notifyTransportError(void); | |||
40 | ||||
41 | struct PacketList { | |||
42 | jdwpPacket packet; | |||
43 | struct PacketList *next; | |||
44 | }; | |||
45 | ||||
46 | static volatile struct PacketList *cmdQueue; | |||
47 | static jrawMonitorID cmdQueueLock; | |||
48 | static jrawMonitorID vmDeathLock; | |||
49 | static jboolean transportError; | |||
50 | ||||
51 | static jboolean | |||
52 | lastCommand(jdwpCmdPacket *cmd) | |||
53 | { | |||
54 | if ((cmd->cmdSet == JDWP_COMMAND_SET(VirtualMachine)1) && | |||
55 | ((cmd->cmd == JDWP_COMMAND(VirtualMachine, Dispose)6) || | |||
56 | (cmd->cmd == JDWP_COMMAND(VirtualMachine, Exit)10))) { | |||
57 | return JNI_TRUE1; | |||
58 | } else { | |||
59 | return JNI_FALSE0; | |||
60 | } | |||
61 | } | |||
62 | ||||
63 | void | |||
64 | debugLoop_initialize(void) | |||
65 | { | |||
66 | vmDeathLock = debugMonitorCreate("JDWP VM_DEATH Lock"); | |||
67 | } | |||
68 | ||||
69 | void | |||
70 | debugLoop_sync(void) | |||
71 | { | |||
72 | debugMonitorEnter(vmDeathLock); | |||
73 | debugMonitorExit(vmDeathLock); | |||
74 | } | |||
75 | ||||
76 | /* | |||
77 | * This is where all the work gets done. | |||
78 | */ | |||
79 | ||||
80 | void | |||
81 | debugLoop_run(void) | |||
82 | { | |||
83 | jboolean shouldListen; | |||
84 | jdwpPacket p; | |||
85 | jvmtiStartFunction func; | |||
86 | ||||
87 | /* Initialize all statics */ | |||
88 | /* We may be starting a new connection after an error */ | |||
89 | cmdQueue = NULL((void*)0); | |||
90 | cmdQueueLock = debugMonitorCreate("JDWP Command Queue Lock"); | |||
91 | transportError = JNI_FALSE0; | |||
92 | ||||
93 | shouldListen = JNI_TRUE1; | |||
94 | ||||
95 | func = &reader; | |||
96 | (void)spawnNewThread(func, NULL((void*)0), "JDWP Command Reader"); | |||
97 | ||||
98 | standardHandlers_onConnect(); | |||
99 | threadControl_onConnect(); | |||
100 | ||||
101 | /* Okay, start reading cmds! */ | |||
102 | while (shouldListen) { | |||
103 | if (!dequeue(&p)) { | |||
104 | break; | |||
105 | } | |||
106 | ||||
107 | if (p.type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) { | |||
108 | /* | |||
109 | * Its a reply packet. | |||
110 | */ | |||
111 | continue; | |||
112 | } else { | |||
113 | /* | |||
114 | * Its a cmd packet. | |||
115 | */ | |||
116 | jdwpCmdPacket *cmd = &p.type.cmd; | |||
117 | PacketInputStream in; | |||
118 | PacketOutputStream out; | |||
119 | CommandHandler func; | |||
120 | const char *cmdSetName; | |||
121 | const char *cmdName; | |||
122 | ||||
123 | /* Should reply be sent to sender. | |||
124 | * For error handling, assume yes, since | |||
125 | * only VM/exit does not reply | |||
126 | */ | |||
127 | jboolean replyToSender = JNI_TRUE1; | |||
128 | ||||
129 | /* | |||
130 | * For all commands we hold the vmDeathLock | |||
131 | * while executing and replying to the command. This ensures | |||
132 | * that a command after VM_DEATH will be allowed to complete | |||
133 | * before the thread posting the VM_DEATH continues VM | |||
134 | * termination. | |||
135 | */ | |||
136 | debugMonitorEnter(vmDeathLock); | |||
137 | ||||
138 | /* Initialize the input and output streams */ | |||
139 | inStream_init(&in, p); | |||
140 | outStream_initReply(&out, inStream_id(&in)); | |||
141 | ||||
142 | func = debugDispatch_getHandler(cmd->cmdSet, cmd->cmd, &cmdSetName, &cmdName); | |||
143 | LOG_MISC(("Command set %s(%d), command %s(%d)",((gdata->log_flags & (0x00000008)) ?(log_message_begin ("MISC","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/debugLoop.c" ,144), log_message_end ("Command set %s(%d), command %s(%d)", cmdSetName, cmd->cmdSet, cmdName, cmd->cmd)):((void)0) ) | |||
144 | cmdSetName, cmd->cmdSet, cmdName, cmd->cmd))((gdata->log_flags & (0x00000008)) ?(log_message_begin ("MISC","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/debugLoop.c" ,144), log_message_end ("Command set %s(%d), command %s(%d)", cmdSetName, cmd->cmdSet, cmdName, cmd->cmd)):((void)0) ); | |||
145 | if (func == NULL((void*)0)) { | |||
146 | /* we've never heard of this, so I guess we | |||
147 | * haven't implemented it. | |||
148 | * Handle gracefully for future expansion | |||
149 | * and platform / vendor expansion. | |||
150 | */ | |||
151 | outStream_setError(&out, JDWP_ERROR(NOT_IMPLEMENTED)99); | |||
152 | } else if (gdata->vmDead && | |||
153 | ((cmd->cmdSet) != JDWP_COMMAND_SET(VirtualMachine)1)) { | |||
154 | /* Protect the VM from calls while dead. | |||
155 | * VirtualMachine cmdSet quietly ignores some cmds | |||
156 | * after VM death, so, it sends it's own errors. | |||
157 | */ | |||
158 | outStream_setError(&out, JDWP_ERROR(VM_DEAD)112); | |||
159 | } else { | |||
160 | /* Call the command handler */ | |||
161 | replyToSender = func(&in, &out); | |||
162 | } | |||
163 | ||||
164 | /* Reply to the sender */ | |||
165 | if (replyToSender) { | |||
166 | if (inStream_error(&in)) { | |||
167 | outStream_setError(&out, inStream_error(&in)); | |||
168 | } | |||
169 | outStream_sendReply(&out); | |||
170 | } | |||
171 | ||||
172 | /* | |||
173 | * Release the vmDeathLock as the reply has been posted. | |||
174 | */ | |||
175 | debugMonitorExit(vmDeathLock); | |||
176 | ||||
177 | inStream_destroy(&in); | |||
178 | outStream_destroy(&out); | |||
179 | ||||
180 | shouldListen = !lastCommand(cmd); | |||
181 | } | |||
182 | } | |||
183 | threadControl_onDisconnect(); | |||
184 | standardHandlers_onDisconnect(); | |||
185 | ||||
186 | /* | |||
187 | * Cut off the transport immediately. This has the effect of | |||
188 | * cutting off any events that the eventHelper thread might | |||
189 | * be trying to send. | |||
190 | */ | |||
191 | transport_close(); | |||
192 | debugMonitorDestroy(cmdQueueLock); | |||
193 | ||||
194 | /* Reset for a new connection to this VM if it's still alive */ | |||
195 | if ( ! gdata->vmDead ) { | |||
196 | debugInit_reset(getEnv()); | |||
197 | } | |||
198 | } | |||
199 | ||||
200 | /* Command reader */ | |||
201 | static void JNICALL | |||
202 | reader(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg) | |||
203 | { | |||
204 | jdwpPacket packet; | |||
205 | jdwpCmdPacket *cmd; | |||
206 | jboolean shouldListen = JNI_TRUE1; | |||
207 | ||||
208 | LOG_MISC(("Begin reader thread"))((gdata->log_flags & (0x00000008)) ?(log_message_begin ("MISC","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/debugLoop.c" ,208), log_message_end ("Begin reader thread")):((void)0)); | |||
| ||||
209 | ||||
210 | while (shouldListen) { | |||
211 | jint rc; | |||
212 | ||||
213 | rc = transport_receivePacket(&packet); | |||
214 | ||||
215 | /* I/O error or EOF */ | |||
216 | if (rc != 0 || (rc
| |||
217 | shouldListen = JNI_FALSE0; | |||
218 | notifyTransportError(); | |||
219 | } else if (packet.type.cmd.flags != JDWPTRANSPORT_FLAGS_NONE) { | |||
220 | /* | |||
221 | * Close the connection when we get a jdwpCmdPacket with an | |||
222 | * invalid flags field value. This is a protocol violation | |||
223 | * so we drop the connection. Also this could be a web | |||
224 | * browser generating an HTTP request that passes the JDWP | |||
225 | * handshake. HTTP requests requires that everything be in | |||
226 | * the ASCII printable range so a flags value of | |||
227 | * JDWPTRANSPORT_FLAGS_NONE(0) cannot be generated via HTTP. | |||
228 | */ | |||
229 | ERROR_MESSAGE(("Received jdwpPacket with flags != 0x%d (actual=0x%x) when a jdwpCmdPacket was expected.",( ((gdata->log_flags & (0x00000080))?(log_message_begin ("ERROR","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/debugLoop.c" ,230), log_message_end ("Received jdwpPacket with flags != 0x%d (actual=0x%x) when a jdwpCmdPacket was expected." , JDWPTRANSPORT_FLAGS_NONE, packet.type.cmd.flags)):((void)0) ), error_message ("Received jdwpPacket with flags != 0x%d (actual=0x%x) when a jdwpCmdPacket was expected." , JDWPTRANSPORT_FLAGS_NONE, packet.type.cmd.flags) ) | |||
230 | JDWPTRANSPORT_FLAGS_NONE, packet.type.cmd.flags))( ((gdata->log_flags & (0x00000080))?(log_message_begin ("ERROR","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/debugLoop.c" ,230), log_message_end ("Received jdwpPacket with flags != 0x%d (actual=0x%x) when a jdwpCmdPacket was expected." , JDWPTRANSPORT_FLAGS_NONE, packet.type.cmd.flags)):((void)0) ), error_message ("Received jdwpPacket with flags != 0x%d (actual=0x%x) when a jdwpCmdPacket was expected." , JDWPTRANSPORT_FLAGS_NONE, packet.type.cmd.flags) ); | |||
231 | shouldListen = JNI_FALSE0; | |||
232 | notifyTransportError(); | |||
233 | } else { | |||
234 | const char *cmdSetName; | |||
235 | const char *cmdName; | |||
236 | cmd = &packet.type.cmd; | |||
237 | ||||
238 | debugDispatch_getHandler(cmd->cmdSet, cmd->cmd, &cmdSetName, &cmdName); | |||
239 | LOG_MISC(("Command set %s(%d), command %s(%d)",((gdata->log_flags & (0x00000008)) ?(log_message_begin ("MISC","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/debugLoop.c" ,240), log_message_end ("Command set %s(%d), command %s(%d)", cmdSetName, cmd->cmdSet, cmdName, cmd->cmd)):((void)0) ) | |||
240 | cmdSetName, cmd->cmdSet, cmdName, cmd->cmd))((gdata->log_flags & (0x00000008)) ?(log_message_begin ("MISC","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/debugLoop.c" ,240), log_message_end ("Command set %s(%d), command %s(%d)", cmdSetName, cmd->cmdSet, cmdName, cmd->cmd)):((void)0) ); | |||
241 | ||||
242 | /* | |||
243 | * FIXME! We need to deal with high priority | |||
244 | * packets and queue flushes! | |||
245 | */ | |||
246 | enqueue(&packet); | |||
247 | ||||
248 | shouldListen = !lastCommand(cmd); | |||
249 | } | |||
250 | } | |||
251 | LOG_MISC(("End reader thread"))((gdata->log_flags & (0x00000008)) ?(log_message_begin ("MISC","/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/debugLoop.c" ,251), log_message_end ("End reader thread")):((void)0)); | |||
252 | } | |||
253 | ||||
254 | /* | |||
255 | * The current system for queueing packets is highly | |||
256 | * inefficient, and should be rewritten! It'd be nice | |||
257 | * to avoid any additional memory allocations. | |||
258 | */ | |||
259 | ||||
260 | static void | |||
261 | enqueue(jdwpPacket *packet) | |||
262 | { | |||
263 | struct PacketList *pL; | |||
264 | struct PacketList *walker; | |||
265 | ||||
266 | pL = jvmtiAllocate((jint)sizeof(struct PacketList)); | |||
267 | if (pL == NULL((void*)0)) { | |||
268 | EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"packet list"){ print_message(stderr, "JDWP exit error ", "\n", "%s(%d): %s [%s:%d]" , jvmtiErrorText((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX+64 +8))), ((jvmtiError)(JVMTI_ERROR_MAX+64+8)), ("packet list"== ((void*)0)?"":"packet list"), "/home/daniel/Projects/java/jdk/src/jdk.jdwp.agent/share/native/libjdwp/debugLoop.c" , 268); debugInit_exit((jvmtiError)((jvmtiError)(JVMTI_ERROR_MAX +64+8)), "packet list"); }; | |||
269 | } | |||
270 | ||||
271 | pL->packet = *packet; | |||
| ||||
272 | pL->next = NULL((void*)0); | |||
273 | ||||
274 | debugMonitorEnter(cmdQueueLock); | |||
275 | ||||
276 | if (cmdQueue == NULL((void*)0)) { | |||
277 | cmdQueue = pL; | |||
278 | debugMonitorNotify(cmdQueueLock); | |||
279 | } else { | |||
280 | walker = (struct PacketList *)cmdQueue; | |||
281 | while (walker->next != NULL((void*)0)) | |||
282 | walker = walker->next; | |||
283 | ||||
284 | walker->next = pL; | |||
285 | } | |||
286 | ||||
287 | debugMonitorExit(cmdQueueLock); | |||
288 | } | |||
289 | ||||
290 | static jboolean | |||
291 | dequeue(jdwpPacket *packet) { | |||
292 | struct PacketList *node = NULL((void*)0); | |||
293 | ||||
294 | debugMonitorEnter(cmdQueueLock); | |||
295 | ||||
296 | while (!transportError && (cmdQueue == NULL((void*)0))) { | |||
297 | debugMonitorWait(cmdQueueLock); | |||
298 | } | |||
299 | ||||
300 | if (cmdQueue != NULL((void*)0)) { | |||
301 | node = (struct PacketList *)cmdQueue; | |||
302 | cmdQueue = node->next; | |||
303 | } | |||
304 | debugMonitorExit(cmdQueueLock); | |||
305 | ||||
306 | if (node != NULL((void*)0)) { | |||
307 | *packet = node->packet; | |||
308 | jvmtiDeallocate(node); | |||
309 | } | |||
310 | return (node != NULL((void*)0)); | |||
311 | } | |||
312 | ||||
313 | static void | |||
314 | notifyTransportError(void) { | |||
315 | debugMonitorEnter(cmdQueueLock); | |||
316 | transportError = JNI_TRUE1; | |||
317 | debugMonitorNotify(cmdQueueLock); | |||
318 | debugMonitorExit(cmdQueueLock); | |||
319 | } |