< prev index next >

src/jdk.jdwp.agent/share/native/libjdwp/invoker.c

Print this page
@  rev 15550 : 8153711: [REDO] JDWP: Memory Leak: GlobalRefs never deleted when processing invokeMethod command
|  Summary: Delete global references in invoker_completeInvokeRequest()
|  Reviewed-by: duke


 194         /* Delete global references */
 195         if ( clazz != NULL ) {
 196             tossGlobalRef(env, &clazz);
 197         }
 198         if ( instance != NULL ) {
 199             tossGlobalRef(env, &instance);
 200         }
 201         if ( argRefs!=NULL ) {
 202             for ( argIndex=0; argIndex < request->argumentCount; argIndex++ ) {
 203                 if ( argRefs[argIndex] != NULL ) {
 204                     tossGlobalRef(env, &argRefs[argIndex]);
 205                 }
 206             }
 207             jvmtiDeallocate(argRefs);
 208         }
 209     }
 210 
 211     return error;
 212 }
 213 
































 214 static jvmtiError
 215 fillInvokeRequest(JNIEnv *env, InvokeRequest *request,
 216                   jbyte invokeType, jbyte options, jint id,
 217                   jthread thread, jclass clazz, jmethodID method,
 218                   jobject instance,
 219                   jvalue *arguments, jint argumentCount)
 220 {
 221     jvmtiError error;
 222     if (!request->available) {
 223         /*
 224          * Thread is not at a point where it can invoke.
 225          */
 226         return AGENT_ERROR_INVALID_THREAD;
 227     }
 228     if (request->pending) {
 229         /*
 230          * Pending invoke
 231          */
 232         return AGENT_ERROR_ALREADY_INVOKING;
 233     }


 305                                   arguments, argumentCount);
 306     }
 307     debugMonitorExit(invokerLock);
 308 
 309     if (error == JVMTI_ERROR_NONE) {
 310         if (options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED) ) {
 311             /* true means it is okay to unblock the commandLoop thread */
 312             (void)threadControl_resumeThread(thread, JNI_TRUE);
 313         } else {
 314             (void)threadControl_resumeAll();
 315         }
 316     }
 317 
 318     return error;
 319 }
 320 
 321 static void
 322 invokeConstructor(JNIEnv *env, InvokeRequest *request)
 323 {
 324     jobject object;


 325     object = JNI_FUNC_PTR(env,NewObjectA)(env, request->clazz,
 326                                      request->method,
 327                                      request->arguments);
 328     request->returnValue.l = NULL;
 329     if (object != NULL) {
 330         saveGlobalRef(env, object, &(request->returnValue.l));
 331     }
 332 }
 333 
 334 static void
 335 invokeStatic(JNIEnv *env, InvokeRequest *request)
 336 {
 337     switch(returnTypeTag(request->methodSignature)) {
 338         case JDWP_TAG(OBJECT):
 339         case JDWP_TAG(ARRAY): {
 340             jobject object;

 341             object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env,
 342                                        request->clazz,
 343                                        request->method,
 344                                        request->arguments);
 345             request->returnValue.l = NULL;
 346             if (object != NULL) {
 347                 saveGlobalRef(env, object, &(request->returnValue.l));
 348             }
 349             break;
 350         }
 351 
 352 
 353         case JDWP_TAG(BYTE):
 354             request->returnValue.b = JNI_FUNC_PTR(env,CallStaticByteMethodA)(env,
 355                                                        request->clazz,
 356                                                        request->method,
 357                                                        request->arguments);
 358             break;
 359 
 360         case JDWP_TAG(CHAR):


 409         case JDWP_TAG(VOID):
 410             JNI_FUNC_PTR(env,CallStaticVoidMethodA)(env,
 411                                           request->clazz,
 412                                           request->method,
 413                                           request->arguments);
 414             break;
 415 
 416         default:
 417             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
 418             break;
 419     }
 420 }
 421 
 422 static void
 423 invokeVirtual(JNIEnv *env, InvokeRequest *request)
 424 {
 425     switch(returnTypeTag(request->methodSignature)) {
 426         case JDWP_TAG(OBJECT):
 427         case JDWP_TAG(ARRAY): {
 428             jobject object;

 429             object = JNI_FUNC_PTR(env,CallObjectMethodA)(env,
 430                                  request->instance,
 431                                  request->method,
 432                                  request->arguments);
 433             request->returnValue.l = NULL;
 434             if (object != NULL) {
 435                 saveGlobalRef(env, object, &(request->returnValue.l));
 436             }
 437             break;
 438         }
 439 
 440         case JDWP_TAG(BYTE):
 441             request->returnValue.b = JNI_FUNC_PTR(env,CallByteMethodA)(env,
 442                                                  request->instance,
 443                                                  request->method,
 444                                                  request->arguments);
 445             break;
 446 
 447         case JDWP_TAG(CHAR):
 448             request->returnValue.c = JNI_FUNC_PTR(env,CallCharMethodA)(env,


 496         case JDWP_TAG(VOID):
 497             JNI_FUNC_PTR(env,CallVoidMethodA)(env,
 498                                     request->instance,
 499                                     request->method,
 500                                     request->arguments);
 501             break;
 502 
 503         default:
 504             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
 505             break;
 506     }
 507 }
 508 
 509 static void
 510 invokeNonvirtual(JNIEnv *env, InvokeRequest *request)
 511 {
 512     switch(returnTypeTag(request->methodSignature)) {
 513         case JDWP_TAG(OBJECT):
 514         case JDWP_TAG(ARRAY): {
 515             jobject object;


 516             object = JNI_FUNC_PTR(env,CallNonvirtualObjectMethodA)(env,
 517                                            request->instance,
 518                                            request->clazz,
 519                                            request->method,
 520                                            request->arguments);
 521             request->returnValue.l = NULL;
 522             if (object != NULL) {
 523                 saveGlobalRef(env, object, &(request->returnValue.l));
 524             }
 525             break;
 526         }
 527 
 528         case JDWP_TAG(BYTE):
 529             request->returnValue.b = JNI_FUNC_PTR(env,CallNonvirtualByteMethodA)(env,
 530                                                  request->instance,
 531                                                  request->clazz,
 532                                                  request->method,
 533                                                  request->arguments);
 534             break;
 535 


 592         case JDWP_TAG(VOID):
 593             JNI_FUNC_PTR(env,CallNonvirtualVoidMethodA)(env,
 594                                     request->instance,
 595                                     request->clazz,
 596                                     request->method,
 597                                     request->arguments);
 598             break;
 599 
 600         default:
 601             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
 602             break;
 603     }
 604 }
 605 
 606 jboolean
 607 invoker_doInvoke(jthread thread)
 608 {
 609     JNIEnv *env;
 610     jboolean startNow;
 611     InvokeRequest *request;


 612 
 613     JDI_ASSERT(thread);
 614 
 615     debugMonitorEnter(invokerLock);
 616 
 617     request = threadControl_getInvokeRequest(thread);
 618     if (request == NULL) {
 619         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
 620     }
 621 
 622     request->available = JNI_FALSE;
 623     startNow = request->pending && !request->started;
 624 
 625     if (startNow) {
 626         request->started = JNI_TRUE;
 627     }



 628     debugMonitorExit(invokerLock);
 629 
 630     if (!startNow) {
 631         return JNI_FALSE;
 632     }
 633 
 634     env = getEnv();
 635 
 636     WITH_LOCAL_REFS(env, 2) {  /* 1 for obj return values, 1 for exception */
 637 
 638         jobject exception;
 639 
 640         JNI_FUNC_PTR(env,ExceptionClear)(env);
 641 
 642         switch (request->invokeType) {
 643             case INVOKE_CONSTRUCTOR:
 644                 invokeConstructor(env, request);
 645                 break;
 646             case INVOKE_STATIC:
 647                 invokeStatic(env, request);
 648                 break;
 649             case INVOKE_INSTANCE:
 650                 if (request->options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) {
 651                     invokeNonvirtual(env, request);
 652                 } else {
 653                     invokeVirtual(env, request);
 654                 }
 655                 break;
 656             default:
 657                 JDI_ASSERT(JNI_FALSE);
 658         }
 659         request->exception = NULL;
 660         exception = JNI_FUNC_PTR(env,ExceptionOccurred)(env);
 661         if (exception != NULL) {
 662             JNI_FUNC_PTR(env,ExceptionClear)(env);
 663             saveGlobalRef(env, exception, &(request->exception));
 664         }
 665 
 666     } END_WITH_LOCAL_REFS(env);
 667 
 668     return JNI_TRUE;
 669 }
 670 


 708             (void)threadControl_suspendThread(thread, JNI_FALSE);
 709         } else {
 710             (void)threadControl_suspendAll();
 711         }
 712 
 713         if (request->invokeType == INVOKE_CONSTRUCTOR) {
 714             /*
 715              * Although constructors technically have a return type of
 716              * void, we return the object created.
 717              */
 718             tag = specificTypeKey(env, request->returnValue.l);
 719         } else {
 720             tag = returnTypeTag(request->methodSignature);
 721         }
 722         id = request->id;
 723         exc = request->exception;
 724         returnValue = request->returnValue;
 725     }
 726 
 727     /*












 728      * Give up the lock before I/O operation
 729      */
 730     debugMonitorExit(invokerLock);
 731     eventHandler_unlock();
 732 
 733 
 734     if (!detached) {
 735         outStream_initReply(&out, id);
 736         (void)outStream_writeValue(env, &out, tag, returnValue);
 737         (void)outStream_writeObjectTag(env, &out, exc);
 738         (void)outStream_writeObjectRef(env, &out, exc);
 739         outStream_sendReply(&out);
 740     }





















 741 }
 742 
 743 jboolean
 744 invoker_isEnabled(jthread thread)
 745 {
 746     InvokeRequest *request;
 747     jboolean isEnabled;
 748 
 749     JDI_ASSERT(thread);
 750     debugMonitorEnter(invokerLock);
 751     request = threadControl_getInvokeRequest(thread);
 752     if (request == NULL) {
 753         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
 754     }
 755     isEnabled = request->available;
 756     debugMonitorExit(invokerLock);
 757     return isEnabled;
 758 }
 759 
 760 void


 194         /* Delete global references */
 195         if ( clazz != NULL ) {
 196             tossGlobalRef(env, &clazz);
 197         }
 198         if ( instance != NULL ) {
 199             tossGlobalRef(env, &instance);
 200         }
 201         if ( argRefs!=NULL ) {
 202             for ( argIndex=0; argIndex < request->argumentCount; argIndex++ ) {
 203                 if ( argRefs[argIndex] != NULL ) {
 204                     tossGlobalRef(env, &argRefs[argIndex]);
 205                 }
 206             }
 207             jvmtiDeallocate(argRefs);
 208         }
 209     }
 210 
 211     return error;
 212 }
 213 
 214 /*
 215  * Delete global argument references from the request which got put there before a
 216  * invoke request was carried out. See fillInvokeRequest().
 217  */
 218 static void
 219 deleteGlobalArgumentRefs(JNIEnv *env, InvokeRequest *request)
 220 {
 221     void *cursor;
 222     jint argIndex = 0;
 223     jvalue *argument = request->arguments;
 224     jbyte argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor);
 225 
 226     if (request->clazz != NULL) {
 227         tossGlobalRef(env, &(request->clazz));
 228     }
 229     if (request->instance != NULL) {
 230         tossGlobalRef(env, &(request->instance));
 231     }
 232     /* Delete global argument references */
 233     while (argIndex < request->argumentCount) {
 234         if ((argumentTag == JDWP_TAG(OBJECT)) ||
 235             (argumentTag == JDWP_TAG(ARRAY))) {
 236             if (argument->l != NULL) {
 237                 tossGlobalRef(env, &(argument->l));
 238             }
 239         }
 240         argument++;
 241         argIndex++;
 242         argumentTag = nextArgumentTypeTag(&cursor);
 243     }
 244 }
 245 
 246 static jvmtiError
 247 fillInvokeRequest(JNIEnv *env, InvokeRequest *request,
 248                   jbyte invokeType, jbyte options, jint id,
 249                   jthread thread, jclass clazz, jmethodID method,
 250                   jobject instance,
 251                   jvalue *arguments, jint argumentCount)
 252 {
 253     jvmtiError error;
 254     if (!request->available) {
 255         /*
 256          * Thread is not at a point where it can invoke.
 257          */
 258         return AGENT_ERROR_INVALID_THREAD;
 259     }
 260     if (request->pending) {
 261         /*
 262          * Pending invoke
 263          */
 264         return AGENT_ERROR_ALREADY_INVOKING;
 265     }


 337                                   arguments, argumentCount);
 338     }
 339     debugMonitorExit(invokerLock);
 340 
 341     if (error == JVMTI_ERROR_NONE) {
 342         if (options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED) ) {
 343             /* true means it is okay to unblock the commandLoop thread */
 344             (void)threadControl_resumeThread(thread, JNI_TRUE);
 345         } else {
 346             (void)threadControl_resumeAll();
 347         }
 348     }
 349 
 350     return error;
 351 }
 352 
 353 static void
 354 invokeConstructor(JNIEnv *env, InvokeRequest *request)
 355 {
 356     jobject object;
 357     
 358     JDI_ASSERT_MSG(request->clazz, "Request clazz null");
 359     object = JNI_FUNC_PTR(env,NewObjectA)(env, request->clazz,
 360                                      request->method,
 361                                      request->arguments);
 362     request->returnValue.l = NULL;
 363     if (object != NULL) {
 364         saveGlobalRef(env, object, &(request->returnValue.l));
 365     }
 366 }
 367 
 368 static void
 369 invokeStatic(JNIEnv *env, InvokeRequest *request)
 370 {
 371     switch(returnTypeTag(request->methodSignature)) {
 372         case JDWP_TAG(OBJECT):
 373         case JDWP_TAG(ARRAY): {
 374             jobject object;
 375             JDI_ASSERT_MSG(request->clazz, "Request clazz null");
 376             object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env,
 377                                        request->clazz,
 378                                        request->method,
 379                                        request->arguments);
 380             request->returnValue.l = NULL;
 381             if (object != NULL) {
 382                 saveGlobalRef(env, object, &(request->returnValue.l));
 383             }
 384             break;
 385         }
 386 
 387 
 388         case JDWP_TAG(BYTE):
 389             request->returnValue.b = JNI_FUNC_PTR(env,CallStaticByteMethodA)(env,
 390                                                        request->clazz,
 391                                                        request->method,
 392                                                        request->arguments);
 393             break;
 394 
 395         case JDWP_TAG(CHAR):


 444         case JDWP_TAG(VOID):
 445             JNI_FUNC_PTR(env,CallStaticVoidMethodA)(env,
 446                                           request->clazz,
 447                                           request->method,
 448                                           request->arguments);
 449             break;
 450 
 451         default:
 452             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
 453             break;
 454     }
 455 }
 456 
 457 static void
 458 invokeVirtual(JNIEnv *env, InvokeRequest *request)
 459 {
 460     switch(returnTypeTag(request->methodSignature)) {
 461         case JDWP_TAG(OBJECT):
 462         case JDWP_TAG(ARRAY): {
 463             jobject object;
 464             JDI_ASSERT_MSG(request->instance, "Request instance null");
 465             object = JNI_FUNC_PTR(env,CallObjectMethodA)(env,
 466                                  request->instance,
 467                                  request->method,
 468                                  request->arguments);
 469             request->returnValue.l = NULL;
 470             if (object != NULL) {
 471                 saveGlobalRef(env, object, &(request->returnValue.l));
 472             }
 473             break;
 474         }
 475 
 476         case JDWP_TAG(BYTE):
 477             request->returnValue.b = JNI_FUNC_PTR(env,CallByteMethodA)(env,
 478                                                  request->instance,
 479                                                  request->method,
 480                                                  request->arguments);
 481             break;
 482 
 483         case JDWP_TAG(CHAR):
 484             request->returnValue.c = JNI_FUNC_PTR(env,CallCharMethodA)(env,


 532         case JDWP_TAG(VOID):
 533             JNI_FUNC_PTR(env,CallVoidMethodA)(env,
 534                                     request->instance,
 535                                     request->method,
 536                                     request->arguments);
 537             break;
 538 
 539         default:
 540             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
 541             break;
 542     }
 543 }
 544 
 545 static void
 546 invokeNonvirtual(JNIEnv *env, InvokeRequest *request)
 547 {
 548     switch(returnTypeTag(request->methodSignature)) {
 549         case JDWP_TAG(OBJECT):
 550         case JDWP_TAG(ARRAY): {
 551             jobject object;
 552             JDI_ASSERT_MSG(request->clazz, "Request clazz null");
 553             JDI_ASSERT_MSG(request->instance, "Request instance null");
 554             object = JNI_FUNC_PTR(env,CallNonvirtualObjectMethodA)(env,
 555                                            request->instance,
 556                                            request->clazz,
 557                                            request->method,
 558                                            request->arguments);
 559             request->returnValue.l = NULL;
 560             if (object != NULL) {
 561                 saveGlobalRef(env, object, &(request->returnValue.l));
 562             }
 563             break;
 564         }
 565 
 566         case JDWP_TAG(BYTE):
 567             request->returnValue.b = JNI_FUNC_PTR(env,CallNonvirtualByteMethodA)(env,
 568                                                  request->instance,
 569                                                  request->clazz,
 570                                                  request->method,
 571                                                  request->arguments);
 572             break;
 573 


 630         case JDWP_TAG(VOID):
 631             JNI_FUNC_PTR(env,CallNonvirtualVoidMethodA)(env,
 632                                     request->instance,
 633                                     request->clazz,
 634                                     request->method,
 635                                     request->arguments);
 636             break;
 637 
 638         default:
 639             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
 640             break;
 641     }
 642 }
 643 
 644 jboolean
 645 invoker_doInvoke(jthread thread)
 646 {
 647     JNIEnv *env;
 648     jboolean startNow;
 649     InvokeRequest *request;
 650     jbyte options;
 651     jbyte invokeType;
 652 
 653     JDI_ASSERT(thread);
 654 
 655     debugMonitorEnter(invokerLock);
 656 
 657     request = threadControl_getInvokeRequest(thread);
 658     if (request == NULL) {
 659         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
 660     }
 661 
 662     request->available = JNI_FALSE;
 663     startNow = request->pending && !request->started;
 664 
 665     if (startNow) {
 666         request->started = JNI_TRUE;
 667     }
 668     options = request->options;
 669     invokeType = request->invokeType;
 670 
 671     debugMonitorExit(invokerLock);
 672 
 673     if (!startNow) {
 674         return JNI_FALSE;
 675     }
 676 
 677     env = getEnv();
 678 
 679     WITH_LOCAL_REFS(env, 2) {  /* 1 for obj return values, 1 for exception */
 680 
 681         jobject exception;
 682 
 683         JNI_FUNC_PTR(env,ExceptionClear)(env);
 684 
 685         switch (invokeType) {
 686             case INVOKE_CONSTRUCTOR:
 687                 invokeConstructor(env, request);
 688                 break;
 689             case INVOKE_STATIC:
 690                 invokeStatic(env, request);
 691                 break;
 692             case INVOKE_INSTANCE:
 693                 if (options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) {
 694                     invokeNonvirtual(env, request);
 695                 } else {
 696                     invokeVirtual(env, request);
 697                 }
 698                 break;
 699             default:
 700                 JDI_ASSERT(JNI_FALSE);
 701         }
 702         request->exception = NULL;
 703         exception = JNI_FUNC_PTR(env,ExceptionOccurred)(env);
 704         if (exception != NULL) {
 705             JNI_FUNC_PTR(env,ExceptionClear)(env);
 706             saveGlobalRef(env, exception, &(request->exception));
 707         }
 708 
 709     } END_WITH_LOCAL_REFS(env);
 710 
 711     return JNI_TRUE;
 712 }
 713 


 751             (void)threadControl_suspendThread(thread, JNI_FALSE);
 752         } else {
 753             (void)threadControl_suspendAll();
 754         }
 755 
 756         if (request->invokeType == INVOKE_CONSTRUCTOR) {
 757             /*
 758              * Although constructors technically have a return type of
 759              * void, we return the object created.
 760              */
 761             tag = specificTypeKey(env, request->returnValue.l);
 762         } else {
 763             tag = returnTypeTag(request->methodSignature);
 764         }
 765         id = request->id;
 766         exc = request->exception;
 767         returnValue = request->returnValue;
 768     }
 769 
 770     /*
 771      * At this time, there's no need to retain global references on
 772      * arguments since the reply is processed. No one will deal with
 773      * this request ID anymore, so we must call deleteGlobalArgumentRefs().
 774      *
 775      * We cannot delete saved exception or return value references
 776      * since otherwise a deleted handle would escape when writing
 777      * the response to the stream. Instead, we clean those refs up
 778      * after writing the respone.
 779      */
 780     deleteGlobalArgumentRefs(env, request);
 781 
 782     /*
 783      * Give up the lock before I/O operation
 784      */
 785     debugMonitorExit(invokerLock);
 786     eventHandler_unlock();
 787 

 788     if (!detached) {
 789         outStream_initReply(&out, id);
 790         (void)outStream_writeValue(env, &out, tag, returnValue);
 791         (void)outStream_writeObjectTag(env, &out, exc);
 792         (void)outStream_writeObjectRef(env, &out, exc);
 793         outStream_sendReply(&out);
 794     }
 795 
 796     /*
 797      * Delete potentially saved global references of return value
 798      * and exception
 799      */
 800     eventHandler_lock(); // for proper lock order
 801     debugMonitorEnter(invokerLock);
 802     /* Delete potentially saved return value */
 803     if ((request->invokeType == INVOKE_CONSTRUCTOR) ||
 804         (returnTypeTag(request->methodSignature) == JDWP_TAG(OBJECT)) ||
 805         (returnTypeTag(request->methodSignature) == JDWP_TAG(ARRAY))) {
 806         if (request->returnValue.l != NULL) {
 807             tossGlobalRef(env, &(request->returnValue.l));
 808         }
 809     }
 810     /* Delete potentially saved exception */
 811     if (request->exception != NULL) {
 812         tossGlobalRef(env, &(request->exception));
 813     }
 814     debugMonitorExit(invokerLock);
 815     eventHandler_unlock();
 816 }
 817 
 818 jboolean
 819 invoker_isEnabled(jthread thread)
 820 {
 821     InvokeRequest *request;
 822     jboolean isEnabled;
 823 
 824     JDI_ASSERT(thread);
 825     debugMonitorEnter(invokerLock);
 826     request = threadControl_getInvokeRequest(thread);
 827     if (request == NULL) {
 828         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
 829     }
 830     isEnabled = request->available;
 831     debugMonitorExit(invokerLock);
 832     return isEnabled;
 833 }
 834 
 835 void
< prev index next >