Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible inconsistency with xrep_t::current_in, xrep_t::more_in after pipe is terminated #69

Closed
nirs opened this issue Sep 10, 2010 · 12 comments

Comments

@nirs
Copy link
Contributor

nirs commented Sep 10, 2010

It seems that after a reader invoke xrep_t::terminated() and the pipe is removed from the inpipes vector, current_in is not updated.

If the terminated pipe was the last in the list, the current_in was last index, it will be invalid at this point. The next time xrecv is called, inpipes[current_in] may be out of the vector bounds.

If the terminated pipe was before current_in, and more_in is true, current_in points now to the next pipe, and more_in is invalid.

I did not check that this situation is reproducible.

@sustrik
Copy link
Member

sustrik commented Sep 29, 2010

Hi, can you point me to the version of 0MQ you are using, the file and the line? I'll have a look.

@nirs
Copy link
Contributor Author

nirs commented Sep 29, 2010

It was master branch at the time I started this issue.

More specific:
When a reader invokes xrep_t::terminated:
http://github.com/zeromq/zeromq2/blob/master/src/xrep.cpp#L90

The reader pipe is removed form the inpipes, without updating the current_in member.

current_in is initialized here:
http://github.com/zeromq/zeromq2/blob/master/src/xrep.cpp#L28

It is updated when iterating over readers here: http://github.com/zeromq/zeromq2/blob/master/src/xrep.cpp#L211

and here:
http://github.com/zeromq/zeromq2/blob/master/src/xrep.cpp#L225

Now if it is possible that a reader is terminated in the middle of this loop, for example, some other code is called, and the other code cause the reader to close, current_in wil be wrong, as described above.

Even if this is not possible now, it may be possible in the future. current_in should be update when a reader is terminated, just like current_out is when a writer is terminated, here:
http://github.com/zeromq/zeromq2/blob/master/src/xrep.cpp#L104

@sustrik
Copy link
Member

sustrik commented Sep 29, 2010

I've checked the code and AFAICS the reader cannot be terminated in the middle of the loop. The list of pipes is local to this thread and cannot be modified in the background.

@sustrik
Copy link
Member

sustrik commented Sep 29, 2010

Ah, but a different thing can happen: Termination of reader can leave current_in pointing past the end of the array and subsequent attempt to recv may thus segfault!

@sustrik
Copy link
Member

sustrik commented Sep 30, 2010

Fixed in r98fa2fa. Thanks for spotting this!

@nirs
Copy link
Contributor Author

nirs commented Sep 30, 2010

This does not fix the inconsistency with more_in, prefetched and prefetched_msg members.

Possible issues:

  1. Reader terminates when after you prefetched the single message and returned the "identity" message to the caller. current_in points now the next reader. When xrecv is called again, you will return the prefetched message from the terminated reader.
  2. Reader terminates after you fetched the first message out of multipart message. and more_in is set to true. current_in points now to the next reader. When xrecv is called again, you will try to return the next message part from the next reader, which may be passive, and then you segfault here:
    http://github.com/zeromq/zeromq2/blob/master/src/xrep.cpp#L215

A better fix is to update all members related to reading a message from a reader: prefetched, prefetched_msg and more_in.

Something like:

void xrep_t::reset_reader()
{
    if (prefetched) {
        zmq_msg_close (&prefetched_msg);
        prefetched = false;
    }
    more_in = false;
}

The you invoke this when current reader is changed.

@sustrik
Copy link
Member

sustrik commented Sep 30, 2010

The point is that reader cannot terminate in the middle of multipart message. Message is delivered either whole or not at all.

@nirs
Copy link
Contributor Author

nirs commented Sep 30, 2010

So the reader is responsible for checking xrep state before calling terminated? Where is this enforced?

@sustrik
Copy link
Member

sustrik commented Oct 1, 2010

Nope. terminate only happens when reader reads the last message (the "delimiter") from the pipe. Pipe writer is responsible for sending only whole messages, so the delimiter may not occur in the middle of the message. If there's half written message and sender wants to send delimiter, it rollbacks the unfinished message from the pipe.

@nirs
Copy link
Contributor Author

nirs commented Oct 1, 2010

Ok, maybe some asserts are missing, blowing up if the reader breaks the contract you described.

Add above http://github.com/zeromq/zeromq2/blob/master/src/xrep.cpp#L104:

if (pipe_ == inpipes [current_in].reader) {
    // Reader is not allowed to terminate in the middle of multipart message
    assert (!prefetched);
    assert (!more_in);
}

@sustrik
Copy link
Member

sustrik commented Oct 1, 2010

Sure. Feel free to send it as a patch to the mailing list.

@nirs
Copy link
Contributor Author

nirs commented Oct 2, 2010

I guess we can close this issue.

csrl pushed a commit to exosite-archive/zeromq2 that referenced this issue Dec 22, 2012
Fixes to LIBZMQ-411 ZMQ 2.x compilation problems when building with disabled asserts.
drahosp pushed a commit to LuaDist/libzmq that referenced this issue Feb 13, 2014
Close pipes for inproc sockets on zmq_disconnect
benjdero pushed a commit to benjdero/libzmq that referenced this issue Feb 20, 2023
missing static specifier for file local function
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants