< prev index next >

src/share/back/invoker.c

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


 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     }


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


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

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


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

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


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


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


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


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



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


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












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










 739 }
 740 
 741 jboolean
 742 invoker_isPending(jthread thread)
 743 {
 744     InvokeRequest *request;
 745 
 746     JDI_ASSERT(thread);
 747     request = threadControl_getInvokeRequest(thread);
 748     if (request == NULL) {
 749         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
 750     }
 751     return request->pending;
 752 }
 753 
 754 jboolean
 755 invoker_isEnabled(jthread thread)
 756 {
 757     InvokeRequest *request;
 758 


 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 saved global references - if any - for:
 216  * - a potentially thrown Exception
 217  * - a returned refernce/array value
 218  * See invoker_doInvoke() and invoke* methods where global references
 219  * are being saved.
 220  */
 221 static void
 222 deletePotentiallySavedGlobalRefs(JNIEnv *env, InvokeRequest *request)
 223 {
 224     /* Delete potentially saved return value */
 225     if ((request->invokeType == INVOKE_CONSTRUCTOR) ||
 226         (returnTypeTag(request->methodSignature) == JDWP_TAG(OBJECT)) ||
 227         (returnTypeTag(request->methodSignature) == JDWP_TAG(ARRAY))) {
 228         if (request->returnValue.l != NULL) {
 229             tossGlobalRef(env, &(request->returnValue.l));
 230         }
 231     }
 232     /* Delete potentially saved exception */
 233     if (request->exception != NULL) {
 234         tossGlobalRef(env, &(request->exception));
 235     }
 236 }
 237 
 238 /*
 239  * Delete global argument references from the request which got put there before a
 240  * invoke request was carried out. See fillInvokeRequest().
 241  */
 242 static void
 243 deleteGlobalArgumentRefs(JNIEnv *env, InvokeRequest *request)
 244 {
 245     void *cursor;
 246     jint argIndex = 0;
 247     jvalue *argument = request->arguments;
 248     jbyte argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor);
 249 
 250     if (request->clazz != NULL) {
 251         tossGlobalRef(env, &(request->clazz));
 252     }
 253     if (request->instance != NULL) {
 254         tossGlobalRef(env, &(request->instance));
 255     }
 256     /* Delete global argument references */
 257     while (argIndex < request->argumentCount) {
 258         if ((argumentTag == JDWP_TAG(OBJECT)) ||
 259             (argumentTag == JDWP_TAG(ARRAY))) {
 260             if (argument->l != NULL) {
 261                 tossGlobalRef(env, &(argument->l));
 262             }
 263         }
 264         argument++;
 265         argIndex++;
 266         argumentTag = nextArgumentTypeTag(&cursor);
 267     }
 268 }
 269 
 270 static jvmtiError
 271 fillInvokeRequest(JNIEnv *env, InvokeRequest *request,
 272                   jbyte invokeType, jbyte options, jint id,
 273                   jthread thread, jclass clazz, jmethodID method,
 274                   jobject instance,
 275                   jvalue *arguments, jint argumentCount)
 276 {
 277     jvmtiError error;
 278     if (!request->available) {
 279         /*
 280          * Thread is not at a point where it can invoke.
 281          */
 282         return AGENT_ERROR_INVALID_THREAD;
 283     }
 284     if (request->pending) {
 285         /*
 286          * Pending invoke
 287          */
 288         return AGENT_ERROR_ALREADY_INVOKING;
 289     }


 359                                   arguments, argumentCount);
 360     }
 361     debugMonitorExit(invokerLock);
 362 
 363     if (error == JVMTI_ERROR_NONE) {
 364         if (options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED) ) {
 365             /* true means it is okay to unblock the commandLoop thread */
 366             (void)threadControl_resumeThread(thread, JNI_TRUE);
 367         } else {
 368             (void)threadControl_resumeAll();
 369         }
 370     }
 371 
 372     return error;
 373 }
 374 
 375 static void
 376 invokeConstructor(JNIEnv *env, InvokeRequest *request)
 377 {
 378     jobject object;
 379 
 380     JDI_ASSERT_MSG(request->clazz, "Request clazz null");
 381     object = JNI_FUNC_PTR(env,NewObjectA)(env, request->clazz,
 382                                      request->method,
 383                                      request->arguments);
 384     request->returnValue.l = NULL;
 385     if (object != NULL) {
 386         saveGlobalRef(env, object, &(request->returnValue.l));
 387     }
 388 }
 389 
 390 static void
 391 invokeStatic(JNIEnv *env, InvokeRequest *request)
 392 {
 393     switch(returnTypeTag(request->methodSignature)) {
 394         case JDWP_TAG(OBJECT):
 395         case JDWP_TAG(ARRAY): {
 396             jobject object;
 397             JDI_ASSERT_MSG(request->clazz, "Request clazz null");
 398             object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env,
 399                                        request->clazz,
 400                                        request->method,
 401                                        request->arguments);
 402             request->returnValue.l = NULL;
 403             if (object != NULL) {
 404                 saveGlobalRef(env, object, &(request->returnValue.l));
 405             }
 406             break;
 407         }
 408 
 409 
 410         case JDWP_TAG(BYTE):
 411             request->returnValue.b = JNI_FUNC_PTR(env,CallStaticByteMethodA)(env,
 412                                                        request->clazz,
 413                                                        request->method,
 414                                                        request->arguments);
 415             break;
 416 
 417         case JDWP_TAG(CHAR):


 466         case JDWP_TAG(VOID):
 467             JNI_FUNC_PTR(env,CallStaticVoidMethodA)(env,
 468                                           request->clazz,
 469                                           request->method,
 470                                           request->arguments);
 471             break;
 472 
 473         default:
 474             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
 475             break;
 476     }
 477 }
 478 
 479 static void
 480 invokeVirtual(JNIEnv *env, InvokeRequest *request)
 481 {
 482     switch(returnTypeTag(request->methodSignature)) {
 483         case JDWP_TAG(OBJECT):
 484         case JDWP_TAG(ARRAY): {
 485             jobject object;
 486             JDI_ASSERT_MSG(request->instance, "Request instance null");
 487             object = JNI_FUNC_PTR(env,CallObjectMethodA)(env,
 488                                  request->instance,
 489                                  request->method,
 490                                  request->arguments);
 491             request->returnValue.l = NULL;
 492             if (object != NULL) {
 493                 saveGlobalRef(env, object, &(request->returnValue.l));
 494             }
 495             break;
 496         }
 497 
 498         case JDWP_TAG(BYTE):
 499             request->returnValue.b = JNI_FUNC_PTR(env,CallByteMethodA)(env,
 500                                                  request->instance,
 501                                                  request->method,
 502                                                  request->arguments);
 503             break;
 504 
 505         case JDWP_TAG(CHAR):
 506             request->returnValue.c = JNI_FUNC_PTR(env,CallCharMethodA)(env,


 554         case JDWP_TAG(VOID):
 555             JNI_FUNC_PTR(env,CallVoidMethodA)(env,
 556                                     request->instance,
 557                                     request->method,
 558                                     request->arguments);
 559             break;
 560 
 561         default:
 562             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
 563             break;
 564     }
 565 }
 566 
 567 static void
 568 invokeNonvirtual(JNIEnv *env, InvokeRequest *request)
 569 {
 570     switch(returnTypeTag(request->methodSignature)) {
 571         case JDWP_TAG(OBJECT):
 572         case JDWP_TAG(ARRAY): {
 573             jobject object;
 574             JDI_ASSERT_MSG(request->clazz, "Request clazz null");
 575             JDI_ASSERT_MSG(request->instance, "Request instance null");
 576             object = JNI_FUNC_PTR(env,CallNonvirtualObjectMethodA)(env,
 577                                            request->instance,
 578                                            request->clazz,
 579                                            request->method,
 580                                            request->arguments);
 581             request->returnValue.l = NULL;
 582             if (object != NULL) {
 583                 saveGlobalRef(env, object, &(request->returnValue.l));
 584             }
 585             break;
 586         }
 587 
 588         case JDWP_TAG(BYTE):
 589             request->returnValue.b = JNI_FUNC_PTR(env,CallNonvirtualByteMethodA)(env,
 590                                                  request->instance,
 591                                                  request->clazz,
 592                                                  request->method,
 593                                                  request->arguments);
 594             break;
 595 


 652         case JDWP_TAG(VOID):
 653             JNI_FUNC_PTR(env,CallNonvirtualVoidMethodA)(env,
 654                                     request->instance,
 655                                     request->clazz,
 656                                     request->method,
 657                                     request->arguments);
 658             break;
 659 
 660         default:
 661             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
 662             break;
 663     }
 664 }
 665 
 666 jboolean
 667 invoker_doInvoke(jthread thread)
 668 {
 669     JNIEnv *env;
 670     jboolean startNow;
 671     InvokeRequest *request;
 672     jbyte options;
 673     jbyte invokeType;
 674 
 675     JDI_ASSERT(thread);
 676 
 677     debugMonitorEnter(invokerLock);
 678 
 679     request = threadControl_getInvokeRequest(thread);
 680     if (request == NULL) {
 681         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
 682     }
 683 
 684     request->available = JNI_FALSE;
 685     startNow = request->pending && !request->started;
 686 
 687     if (startNow) {
 688         request->started = JNI_TRUE;
 689     }
 690     options = request->options;
 691     invokeType = request->invokeType;
 692 
 693     debugMonitorExit(invokerLock);
 694 
 695     if (!startNow) {
 696         return JNI_FALSE;
 697     }
 698 
 699     env = getEnv();
 700 
 701     WITH_LOCAL_REFS(env, 2) {  /* 1 for obj return values, 1 for exception */
 702 
 703         jobject exception;
 704 
 705         JNI_FUNC_PTR(env,ExceptionClear)(env);
 706 
 707         switch (invokeType) {
 708             case INVOKE_CONSTRUCTOR:
 709                 invokeConstructor(env, request);
 710                 break;
 711             case INVOKE_STATIC:
 712                 invokeStatic(env, request);
 713                 break;
 714             case INVOKE_INSTANCE:
 715                 if (options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) {
 716                     invokeNonvirtual(env, request);
 717                 } else {
 718                     invokeVirtual(env, request);
 719                 }
 720                 break;
 721             default:
 722                 JDI_ASSERT(JNI_FALSE);
 723         }
 724         request->exception = NULL;
 725         exception = JNI_FUNC_PTR(env,ExceptionOccurred)(env);
 726         if (exception != NULL) {
 727             JNI_FUNC_PTR(env,ExceptionClear)(env);
 728             saveGlobalRef(env, exception, &(request->exception));
 729         }
 730 
 731     } END_WITH_LOCAL_REFS(env);
 732 
 733     return JNI_TRUE;
 734 }
 735 


 773             (void)threadControl_suspendThread(thread, JNI_FALSE);
 774         } else {
 775             (void)threadControl_suspendAll();
 776         }
 777 
 778         if (request->invokeType == INVOKE_CONSTRUCTOR) {
 779             /*
 780              * Although constructors technically have a return type of
 781              * void, we return the object created.
 782              */
 783             tag = specificTypeKey(env, request->returnValue.l);
 784         } else {
 785             tag = returnTypeTag(request->methodSignature);
 786         }
 787         id = request->id;
 788         exc = request->exception;
 789         returnValue = request->returnValue;
 790     }
 791 
 792     /*
 793      * At this time, there's no need to retain global references on
 794      * arguments since the reply is processed. No one will deal with
 795      * this request ID anymore, so we must call deleteGlobalArgumentRefs().
 796      *
 797      * We cannot delete saved exception or return value references
 798      * since otherwise a deleted handle would escape when writing
 799      * the response to the stream. Instead, we clean those refs up
 800      * after writing the respone.
 801      */
 802     deleteGlobalArgumentRefs(env, request);
 803 
 804     /*
 805      * Give up the lock before I/O operation
 806      */
 807     debugMonitorExit(invokerLock);
 808     eventHandler_unlock();
 809 

 810     if (!detached) {
 811         outStream_initReply(&out, id);
 812         (void)outStream_writeValue(env, &out, tag, returnValue);
 813         (void)outStream_writeObjectTag(env, &out, exc);
 814         (void)outStream_writeObjectRef(env, &out, exc);
 815         outStream_sendReply(&out);
 816     }
 817 
 818     /*
 819      * Delete potentially saved global references of return value
 820      * and exception
 821      */
 822     eventHandler_lock(); // for proper lock order
 823     debugMonitorEnter(invokerLock);
 824     deletePotentiallySavedGlobalRefs(env, request);
 825     debugMonitorExit(invokerLock);
 826     eventHandler_unlock();
 827 }
 828 
 829 jboolean
 830 invoker_isPending(jthread thread)
 831 {
 832     InvokeRequest *request;
 833 
 834     JDI_ASSERT(thread);
 835     request = threadControl_getInvokeRequest(thread);
 836     if (request == NULL) {
 837         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
 838     }
 839     return request->pending;
 840 }
 841 
 842 jboolean
 843 invoker_isEnabled(jthread thread)
 844 {
 845     InvokeRequest *request;
 846 
< prev index next >