8220394: bufferedStream does not honor size limit

Thomas Stüfe thomas.stuefe at gmail.com
Tue May 21 09:12:29 UTC 2019


Hi David,

On Tue, May 21, 2019 at 10:01 AM David Holmes <david.holmes at oracle.com>
wrote:

> Hi Thomas,
>
> On 21/05/2019 5:26 pm, Thomas Stüfe wrote:
> > Hi David,
> >
> > thank you for taking a look at this! Remarks inline:
> >
> > On Tue, May 21, 2019 at 8:45 AM David Holmes <david.holmes at oracle.com
> > <mailto:david.holmes at oracle.com>> wrote:
> >
> >     Hi Thomas,
> >
> >     Sorry but I don't grok this stop-gap fix. I get that bufferedStream
> >     is a
> >     strange entity - and to me it doesn't look or act like a buffered
> >     stream! - but other code seems to recognise this e.g. see:
> >
> >     ./share/code/codeHeapState.cpp
> >
> >     and look what it does to effect actual buffering between a
> >     bufferedStream and a real outputStream!
> >
> >     If there is code that misuses bufferedStream (and it seems the only
> >     other direct uses are in the attach listener and JFR) then I'd rather
> >     see those fixed.
> >
> >
> > Definitely.
> >
> >     But looking at the attach listener code it also seems
> >     to recognise that bufferedStream is just a "buffer" which it copies
> to
> >     the final destination ie. writing the content to the socket.
> >
> >
> > Yes, but the problem is that until it finally sends the output of an
> > attach op back it completely buffers the whole output in the stream
> > internal buffer. That is a problem especially if you have faulty
> > printing code.
> >
> > I encountered the problem when I was working on a diagnostic command and
> > had an error resulting in infinite printing. The process was growing
> > until the OOM killer killed it.
>
> That seems like a good debugging tool to me. If the output had simply
> been truncated then you may not have known where the problem was ;-)
>

I agree. That is why I assert in debug case.

But since bugs like these are likely to happen in situations which are not
critical to VM life (e.g. someone calls jcmd on a running server VM at a
customer site, and triggers an error in a diagnostic command) I rather not
crash the VM. I rather have truncated output in this case or an error
message. Therefore, for release, I truncate.

I know its not perfect. But I prefer that to killing the VM outright or
making the machine swap.


> > The intention of my patch is not to fix those usages - that should be
> > done separately, e.g. we should teach the attach listener to send output
> > piecemeal, or temporarily buffer to a local file. But that would be a
> > much larger fix, and only fixes this one occurrence.
>
> Hmmm. To me this is working as intended, with an assumption that the
> amount of data buffered will be finite and reasonable. It's not clear
> that you can change the way things work to send the data back piecemeal.
>

Lets hope its fixable. It is already today a problem if you have a command
which produces lots of output - you may hit timeouts on the receiving side.
But that is an issue for another day.


>
> > What I wanted was just an assert at a size which reasonably could be
> > called an error. Would make analyzing these issues much easier. And
> > since this is an error which very likely depends on runtime conditions
> > (e.g. you may hit an error in a jcmd at a customer site you never saw in
> > lab) it makes sense to have a solution for release builds too, hence the
> > silent truncation.
> >
> > Do you have a better proposal?
>
> No. I see what you are trying to do now. I think the commentary is a bit
> excessive and don't necessarily agree there is a fundamental problem
> with the users that needs to be fixed but ...
>

Okay, I may have gotten a bit overexcited with the comment, I will slim it
down :)


>
> One concern:
>
> 969     if (buffer_pos + len > MAX2(buffer_max, 100 * M)) {
>
> As this is already within a guard that "buffer_pos + len > buffer_max"
> you only need to check against 100*M - if flush() is a no-op. If flush()
> is not a no-op then this will be incorrect if buffer_max > 100MB and len
>  > 100M. Maybe save the original buffer_pos and only do your check if it
> has not changed - ie flush() was a no-op?


Good point. I'll fix it.

..Thomas


>
> Thanks,
> David
> -----
>
> >
> >     So where is the code that misuses bufferedStream?
> >
> >
> > It was jcmd.
> >
> >     Thanks,
> >     David
> >     -----
> >
> >
> > Cheers, Thomas
> >
> >
> >     On 21/05/2019 4:11 pm, Thomas Stüfe wrote:
> >      > Ping?
> >      >
> >      > Thanks, Thomas
> >      >
> >      > On Tue, May 14, 2019 at 12:25 PM Thomas Stüfe
> >     <thomas.stuefe at gmail.com <mailto:thomas.stuefe at gmail.com>>
> >      > wrote:
> >      >
> >      >>
> >      >>     Hi all,
> >      >>
> >      >>
> >      >> Bug: https://bugs.openjdk.java.net/browse/JDK-8220394
> >      >> cr:
> >      >>
> >
> http://cr.openjdk.java.net/~stuefe/webrevs/8220394-bufferedstream-does-not-honor-size-limit/webrev.00/webrev/
> >      >>
> >      >> I redid the patch for this in a minimal form. The first version
> >     I posted
> >      >> in March but after consideration I found it too invasive.
> >      >>
> >      >> Short story: bufferedStream is misused as a
> >      >> outputStream-with-dynamic-buffer in a number of places - misused
> >     since we
> >      >> have stringStream for that.
> >      >>
> >      >> It has something looking like a maximum buffer size cap but that
> is
> >      >> actually a flush-trigger for child classes of bufferesStream.
> >      >> bufferedStream::flush itself is a noop.
> >      >>
> >      >> That means that printing to this stream may cause high memory
> >     footprint or
> >      >> native OOM since the upper limit is not honored. In runaway
> >     printing coding
> >      >> this can tear down the process.
> >      >>
> >      >> This patch is a stopgap - when we reach the buffer limit - but
> >     not below
> >      >> 100M - we will assert(debug) or truncate (release).
> >      >>
> >      >> I am careful here since I do not know if there are situations
> >     where more
> >      >> than buffer-limit bytes are written today and suddenly enforcing
> >     this limit
> >      >> now would cause errors. I think 100M is safe to be considered
> >     "too much".
> >      >>
> >      >> The real correct solution should be that all callers use
> >     stringStream and
> >      >> handle truncation. This patch is small and could be, if
> >     necessary, ported
> >      >> down to older releases easily.
> >      >>
> >      >> Thanks, Thomas
> >      >>
> >      >>
> >      >>
> >
>


More information about the hotspot-runtime-dev mailing list