JDK-8224193 : stringStream should not use Resource Area
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 11,13
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2019-05-20
  • Updated: 2021-01-25
  • Resolved: 2019-05-22
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 11 JDK 13
11.0.6-oracleFixed 13 b22Fixed
Related Reports
Blocks :  
Blocks :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
stringStream is often used as a temp buffer to assemble messages before posting them somewhere else. For example (compilerBroker.cpp):

  void log_compile(JavaThread* thread, CompileTask* task) {
    StringLogMessage lm;
    stringStream sstr = lm.stream();
    // msg.time_stamp().update_to(tty->time_stamp().ticks());
    task->print(&sstr, NULL, true, false);
    log(thread, "%s", (const char*)lm);
  }

This is a valid scenario; the problem however is that stringStream uses ResourceArea as backing memory for its temporary buffer which is a very poor choice for two reasons:

1) When implementing sub functions which print to the stream and also need Resource Area, the polite thing to do is to span open a ResourceMark in the sub function (e.g. inside CompileTask::print() in above example). 

However, if the printing the sub function does happens to trigger a reallocation of the stream-internal backing memory, it will do so under the then current ResourceMark in the child frame. That will either crash in release builds or assert in debug builds (see [1] for an example). The bad thing is that this is difficult to test since it is dependent on how much logging happens.

2) Even if we did not have the problem of ResourceMarks, this is very inefficient way to use resource area, since resource area resizing is often not a resizing but just a reallocation of the buffer while the old buffer is not released (if the character array is not at the top of the resource area anymore). That is by design and cannot be changed.


Because of both reasons, the reasonable thing to do would be to not use resource area for any kind of buffer which gets handed up and down the stack and potentially resized inside every frame. Like it is typical for stream objects.

Note that we did a similar cleanup already in UL, with the same reasoning: JDK-8181917

----------------------------------

[1] Example assert stack:

Stack: [0x00003fff511b0000,0x00003fff515b0000],  sp=0x00003fff515ad380,  free space=4084k
Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x1824afc]  stringStream::write(char const*, unsigned long)+0x22c
V  [libjvm.so+0x182528c]  outputStream::do_vsnprintf_and_write_with_automatic_buffer(char const*, char*, bool)+0x10c
V  [libjvm.so+0x1825b2c]  outputStream::print(char const*, ...)+0x13c
V  [libjvm.so+0x16d5514]  Method::print_short_name(outputStream*)+0xe4
V  [libjvm.so+0xcee158]  CompileTask::print(outputStream*, char const*, bool, bool)+0x188
V  [libjvm.so+0xce6ca0]  CompileBroker::invoke_compiler_on_method(CompileTask*)+0xf30
V  [libjvm.so+0xce7f48]  CompileBroker::compiler_thread_loop()+0xb58
V  [libjvm.so+0x1b56b7c]  compiler_thread_entry(JavaThread*, Thread*)+0x7c
V  [libjvm.so+0x1b62304]  JavaThread::thread_main_inner()+0x234
V  [libjvm.so+0x1b6a138]  Thread::call_run()+0x158
V  [libjvm.so+0x180e08c]  thread_native_entry(Thread*)+0x18c
C  [libpthread.so.0+0xc460]  start_thread+0x100


Comments
Fix Request: Important to fix because: This prevents hard-to-predict crashes: - stringStream gets created - gets handed down to "print_xyz(outputStream*)" function - in that function a new ResourceMark is spanned - and in that function (or below) we print to that stream and that printing leads to a resizing of the stringStream backing buffer, which would be reallocated under the new ResourceMark This bug is highly dependent on the content printed, so it may never happen during testing. Nature of fix: Do not use ResourceArea for stringStream backing. Use C heap. Note: to work correctly, "8224487 outputStream should not be copyable" must be backported first. Low risk because: The fix is small and simple. Testing done: SAP nightlies (jck gtests jtreg etc as well as new gtests written for stringStream)
27-06-2019