-
Bug
-
Resolution: Fixed
-
P4
-
1.1.4
-
b01
-
x86
-
windows_nt
The following write-up is curtesy our friends at SAS Institute:
The Problem
There are currently two versions of the java VM shipped with the JDK: An
optimized, production VM (java.exe) and a debug VM (java_g.exe). It is
only possible to run an application under a Java debugger with the debug
VM.
The debug VM attempts to serve two purposes:
1.Provide a debuggable version of the VM.
2.Provide an environment for Java programs to run under the control of a
debugger.
These two uses are designed for completely different audiences: The
first use is aimed at JavaSoft internal developers and testers and to
partners who are porting the JDK to new platforms. The second use is
aimed at end users who wish to debug their own Java applications.
It is not effective to use the same VM for both purposes. For testing
and diagnosing bugs in the VM itself, it is desirable to provide
instrumentation that allow assertion failures to either invoke a native
debugger or to cause the application to immediately bail out with an
appropriate error message. It is not important for the VM to remain up,
it is important that problems are detected. Typically debuggable
applications that contain assertion code are not shipped to customers.
When debugging an end user's Java application with a professional
quality IDE, we should expect that the VM be as robust and reliable as
the production VM, although we must be willing to accept certain
performance limitations that are necessary when debugging an
application. The end user shouldn't see assertions in the java VM that
are quietly overlooked in the production VM.
Currently, there are some assertions in AWT code that have been found
while running java_g while debugging user applications. These assertions
make it impossible for our end users to debug their applications. See
bug 4042898 for an example of such a bug.
Obviously, it is highly desirable to fix the underlying problems that
cause these assertions. Removing the assertion completely would just
hide the problem.
Realistically, there are over 400 assertions just in AWT code alone. I
recently counted:
- 189 uses of ASSERT.
- 189 uses of VERIFY (which calls ASSERT).
- 23 uses of CHECK_OBJ (which also calls ASSERT)
Our Proposal
>From our conversation with several JavaSoft sources, it is my
understanding that the VM is being restructured to phase out java_g with
the 1.2 JDK release. We agree with this strategy for all of the above
reasons. Unfortunately, for those of us trying to ship tools that must
work with the 1.1.* set of releases, something should be done sooner.
I propose that for the 1.1.5 release, the version of java_g that is
built and shipped to customers have changes made to the CallDebugger()
function (found in ..\src\win32\sun\windows\awt_Toolkit.cpp) so that the
assertion code will not abort the VM. Test versions of the toolkit could
still be built with the usual assertion behavior for diagnostic
purposes.
Even with this proposed change, there is still a difficulty debugging
around some of the problems that lead to assertions. About 43 of these
assertions (including the one involved with bug 4042898) check for an
uncaught Java Exception. The debugger will have received notification of
these exceptions before the ASSERT code would check for it. The debugger
user (or possibly debugger writer) will have to deal with these uncaught
exceptions, however with the proposed solution, they can simply allow
the application to continue execution.
Current ASSERT and CallDebugger sources
>From ..\src\win32\sun\windows\awt.h:
#define ASSERT(exp) (void)( (exp) || (CallDebugger(#exp, __FILE__, __LINE__), 0) )
>From ..\src\win32\sun\windows\awt_Toolkit.cpp:
////////////////////////////////////////////////////////////////////////
////
// Diagnostic routines
#if defined(DEBUG)
void CallDebugger(char* expr, char* file, unsigned line) {
DWORD lastError = GetLastError();
if (AwtToolkit::GetInstance().BreakOnError() == FALSE) {
printf("Fatal error: %d\n", lastError);
_assert(expr, file, line);
return;
}
BOOL ignoreError = FALSE;
# if defined(_M_IX86)
_asm { int 3 };
# else
DebugBreak();
# endif
// Modify ignoreError in the debugger to continue
if (!ignoreError) {
_assert(expr, file, line);
}
}
#endif // DEBUG
Proposed CallDebugger() source
////////////////////////////////////////////////////////////////////////
////
// Diagnostic routines
#if defined(DEBUG)
#if defined(INTERNAL_DEBUG)
// This form of CallDebugger would get built if
void CallDebugger(char* expr, char* file, unsigned line) {
DWORD lastError = GetLastError();
if (AwtToolkit::GetInstance().BreakOnError() == FALSE) {
printf("Fatal error: %d\n", lastError);
_assert(expr, file, line);
return;
}
BOOL ignoreError = FALSE;
# if defined(_M_IX86)
_asm { int 3 };
# else
DebugBreak();
# endif
// Modify ignoreError in the debugger to continue
if (!ignoreError) {
_assert(expr, file, line);
}
}
# else // ! INTERNAL_DEBUG
// This form of CallDebugger would get built for java_g.exe to be
shipped to customers
void CallDebugger(char* expr, char* file, unsigned line) {
DWORD lastError = GetLastError();
printf("Internal error: %d\n", lastError);
printf("%s %s %d\n", expr, file, line);
return;
}
}
# endif // INTERNAL_DEBUG
# endif // DEBUG
The Problem
There are currently two versions of the java VM shipped with the JDK: An
optimized, production VM (java.exe) and a debug VM (java_g.exe). It is
only possible to run an application under a Java debugger with the debug
VM.
The debug VM attempts to serve two purposes:
1.Provide a debuggable version of the VM.
2.Provide an environment for Java programs to run under the control of a
debugger.
These two uses are designed for completely different audiences: The
first use is aimed at JavaSoft internal developers and testers and to
partners who are porting the JDK to new platforms. The second use is
aimed at end users who wish to debug their own Java applications.
It is not effective to use the same VM for both purposes. For testing
and diagnosing bugs in the VM itself, it is desirable to provide
instrumentation that allow assertion failures to either invoke a native
debugger or to cause the application to immediately bail out with an
appropriate error message. It is not important for the VM to remain up,
it is important that problems are detected. Typically debuggable
applications that contain assertion code are not shipped to customers.
When debugging an end user's Java application with a professional
quality IDE, we should expect that the VM be as robust and reliable as
the production VM, although we must be willing to accept certain
performance limitations that are necessary when debugging an
application. The end user shouldn't see assertions in the java VM that
are quietly overlooked in the production VM.
Currently, there are some assertions in AWT code that have been found
while running java_g while debugging user applications. These assertions
make it impossible for our end users to debug their applications. See
bug 4042898 for an example of such a bug.
Obviously, it is highly desirable to fix the underlying problems that
cause these assertions. Removing the assertion completely would just
hide the problem.
Realistically, there are over 400 assertions just in AWT code alone. I
recently counted:
- 189 uses of ASSERT.
- 189 uses of VERIFY (which calls ASSERT).
- 23 uses of CHECK_OBJ (which also calls ASSERT)
Our Proposal
>From our conversation with several JavaSoft sources, it is my
understanding that the VM is being restructured to phase out java_g with
the 1.2 JDK release. We agree with this strategy for all of the above
reasons. Unfortunately, for those of us trying to ship tools that must
work with the 1.1.* set of releases, something should be done sooner.
I propose that for the 1.1.5 release, the version of java_g that is
built and shipped to customers have changes made to the CallDebugger()
function (found in ..\src\win32\sun\windows\awt_Toolkit.cpp) so that the
assertion code will not abort the VM. Test versions of the toolkit could
still be built with the usual assertion behavior for diagnostic
purposes.
Even with this proposed change, there is still a difficulty debugging
around some of the problems that lead to assertions. About 43 of these
assertions (including the one involved with bug 4042898) check for an
uncaught Java Exception. The debugger will have received notification of
these exceptions before the ASSERT code would check for it. The debugger
user (or possibly debugger writer) will have to deal with these uncaught
exceptions, however with the proposed solution, they can simply allow
the application to continue execution.
Current ASSERT and CallDebugger sources
>From ..\src\win32\sun\windows\awt.h:
#define ASSERT(exp) (void)( (exp) || (CallDebugger(#exp, __FILE__, __LINE__), 0) )
>From ..\src\win32\sun\windows\awt_Toolkit.cpp:
////////////////////////////////////////////////////////////////////////
////
// Diagnostic routines
#if defined(DEBUG)
void CallDebugger(char* expr, char* file, unsigned line) {
DWORD lastError = GetLastError();
if (AwtToolkit::GetInstance().BreakOnError() == FALSE) {
printf("Fatal error: %d\n", lastError);
_assert(expr, file, line);
return;
}
BOOL ignoreError = FALSE;
# if defined(_M_IX86)
_asm { int 3 };
# else
DebugBreak();
# endif
// Modify ignoreError in the debugger to continue
if (!ignoreError) {
_assert(expr, file, line);
}
}
#endif // DEBUG
Proposed CallDebugger() source
////////////////////////////////////////////////////////////////////////
////
// Diagnostic routines
#if defined(DEBUG)
#if defined(INTERNAL_DEBUG)
// This form of CallDebugger would get built if
void CallDebugger(char* expr, char* file, unsigned line) {
DWORD lastError = GetLastError();
if (AwtToolkit::GetInstance().BreakOnError() == FALSE) {
printf("Fatal error: %d\n", lastError);
_assert(expr, file, line);
return;
}
BOOL ignoreError = FALSE;
# if defined(_M_IX86)
_asm { int 3 };
# else
DebugBreak();
# endif
// Modify ignoreError in the debugger to continue
if (!ignoreError) {
_assert(expr, file, line);
}
}
# else // ! INTERNAL_DEBUG
// This form of CallDebugger would get built for java_g.exe to be
shipped to customers
void CallDebugger(char* expr, char* file, unsigned line) {
DWORD lastError = GetLastError();
printf("Internal error: %d\n", lastError);
printf("%s %s %d\n", expr, file, line);
return;
}
}
# endif // INTERNAL_DEBUG
# endif // DEBUG
- relates to
-
JDK-4042898 win32: Assertion failure awt_Component.cpp line 1358
-
- Closed
-