cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Sylvain Lebresne (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (CASSANDRA-9863) NIODataInputStream can loop forever
Date Wed, 22 Jul 2015 12:04:05 GMT

    [ https://issues.apache.org/jira/browse/CASSANDRA-9863?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14636778#comment-14636778
] 

Sylvain Lebresne commented on CASSANDRA-9863:
---------------------------------------------

bq. That looks like actually a very simple bug

Might be. But I still find {{readNext()}} fairly dodgy for the case where we don't have a
{{ReadableByteChannel}}. First because in that case we don't refill anything, but also because
it's a costly no-op in that case but that's far from evident from the code (the {{buf.limit(buf.capacity())}}
line is particularly weird at first glance since in that case (where the buffer you use has
been externally provided), you should absolutely not read/write after the initial limit (not
saying that's what we do, the {{flip()}} makes it ok, but it makes understanding harder than
it should)). As a minor aside, I would have renamed that method {{refill()}} or something
since readNext() make it sounds like it's returning what it reads which it isn't. 

So it would make me happy if we could use that ticket to also fix that (maybe by having readNext()
first check if we're in the "no {{ReadableByteChannel}}" case upfront and directly exit with
-1 in that case).

bq. This is a different problem to the one in CASSANDRA-9708.

True, but I'd still prefer fix all {{NIODataInputStream}} problems we have here since that's
a more targeted issue (I'll rename the issue even to make that more clear).

> NIODataInputStream can loop forever
> -----------------------------------
>
>                 Key: CASSANDRA-9863
>                 URL: https://issues.apache.org/jira/browse/CASSANDRA-9863
>             Project: Cassandra
>          Issue Type: Bug
>            Reporter: Sylvain Lebresne
>            Assignee: Ariel Weisberg
>            Priority: Blocker
>             Fix For: 3.0 beta 1
>
>
> As the title says, there is cases where method calls to NIODataInputStream, at least
{{readVInt}} calls can loop forever. This is possibly only a problem for vints where the code
tries to read 8 bytes minimum but there is less than that available, and in that sense is
related to [~benedict]'s observation in CASSANDRA-9708, but it is more serious than said observation
because:
> # this can happen even if the buffer passed to NIODataInputStream ctor has more than
8 bytes available, and hence I'm relatively confident [~benedict]'s fix in CASSANDRA-9708
is not enough.
> # this doesn't necessarily fail cleanly by raising assertions, this can loop forever
(which is much harder to debug).
> Due of that, and because that is at least one of the cause of CASSANDRA-9764, I think
the problem warrants a specific ticket (from CASSANDRA-9708 that is).
> Now, the exact reason of this is looping is if {{readVInt}} is called but the buffer
has less than 8 byte remaining (again, the buffer had more initially). In that case, {{readMinimum(8,
1)}} is called and it calls {{readNext()}} in a loop. Within {{readNext()}}, the buffer (which
has {{buf.position() == 0 && buf.hasRemaining()}}) is actually unchanged (through
a very weird dance of setting the position to the limit, then the limit to the capacity, and
then flipping the buffer which resets everything to what it was), and because {{rbc}} is the
{{emptyReadableByteChannel}}, {{rbc.read(buf)}} does nothing and always return {{-1}}. Back
in {{readMinimum}}, {{read == -1}} but {{remaining >= require}} (and {{remaining}} never
changes), and hence the forever looping.
> Now, not sure what the best fix is because I'm not fully familiar with that code, but
that does leads me to a 2nd point: {{NIODataInputSttream}} can IMHO use a bit of additional/better
comments. I won't pretend having tried very hard to understand the whole class, so there is
probably some lack of effort, but at least a few things felt like they should clarified:
> * Provided I understand {{readNext()}} correctly, it only make sense when we do have
a {{ReadableByteChannel}} (and the fact that it's not the case sounds like the bug). If that's
the case, this should be explicitly documented and probably asserted. As as an aside, I wonder
if using {{rbc == null}} when we don't have wouldn't be better: if we don't have one, we shouldn't
try to use it, and having a {{null}} would make things fail loudly if we do.
> * I'm not exactly sure what {{readMinimum}} arguments do. I'd have expected at least
one to be called "minimum", and an explanation of the meaning of the other one.
> * {{prepareReadPaddedPrimitive}} says that it "Add padding if requested" but there is
seemingly no argument that trigger the "if requested part". Also unclear what that padding
is about in the first place.
> As a final point, it looks like the case where {{NIODataInputStream}} is constructed
with a {{ByteBuffer}} (rather than a {{ReadableByteChannel}}) seems to be completely untested
by the unit tests.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Mime
View raw message