{"action":"created","issue":{"url":"https://api.github.com/repos/zeromq/libzmq/issues/2942","repository_url":"https://api.github.com/repos/zeromq/libzmq","labels_url":"https://api.github.com/repos/zeromq/libzmq/issues/2942/labels{/name}","comments_url":"https://api.github.com/repos/zeromq/libzmq/issues/2942/comments","events_url":"https://api.github.com/repos/zeromq/libzmq/issues/2942/events","html_url":"https://github.com/zeromq/libzmq/issues/2942","id":296362447,"number":2942,"title":"PUB crash when SUB exceeded SNDHWM","user":{"login":"sublee","id":19982,"avatar_url":"https://avatars0.githubusercontent.com/u/19982?v=4","gravatar_id":"","url":"https://api.github.com/users/sublee","html_url":"https://github.com/sublee","followers_url":"https://api.github.com/users/sublee/followers","following_url":"https://api.github.com/users/sublee/following{/other_user}","gists_url":"https://api.github.com/users/sublee/gists{/gist_id}","starred_url":"https://api.github.com/users/sublee/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sublee/subscriptions","organizations_url":"https://api.github.com/users/sublee/orgs","repos_url":"https://api.github.com/users/sublee/repos","events_url":"https://api.github.com/users/sublee/events{/privacy}","received_events_url":"https://api.github.com/users/sublee/received_events","type":"User","site_admin":false},"labels":[{"id":361105095,"url":"https://api.github.com/repos/zeromq/libzmq/labels/Platform%20(linux/generic)","name":"Platform (linux/generic)","color":"bfd4f2","default":false},{"id":675552804,"url":"https://api.github.com/repos/zeromq/libzmq/labels/Symptom%20(Assertion%20failure)","name":"Symptom (Assertion failure)","color":"bfd4f2","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":57,"created_at":"2018-02-12T12:43:22Z","updated_at":"2018-03-02T17:46:08Z","closed_at":null,"author_association":"NONE","body":"*Please use this template for reporting suspected bugs or requests for help.*\r\n\r\n# Issue description\r\n\r\nWhen all of these conditions are satisfied, the assertion failure from `mtrie.cpp` occurs:\r\n\r\n- A connection between a `PUB` socket and many `SUB` sockets.\r\n- A `SUB` socket subscribe/unsubscribe many prefixes.\r\n- Call `zmq_getsockopt()` with `ZMQ_EVENTS` for `SUB` sockets.\r\n\r\n```\r\nAssertion failed: erased == 1 (src/mtrie.cpp:297)\r\n[1]    30266 abort (core dumped)  ./a.out\r\n```\r\n\r\n# Environment\r\n\r\n* libzmq version (commit hash if unreleased): 4.2.0 and 4.2.3\r\n* OS: Ubuntu 16.04 LTS\r\n\r\n# Minimal test code / Steps to reproduce the issue\r\n\r\nTo reproduce this crash, we should prepare a `PUB` socket and many `SUB` sockets.\r\n\r\nWe will call this sequence (pseudo-code): `pub.connect(sub) or sub.connect(pub); pub.getsockopt(ZMQ_EVENTS); sub.subscribe(prefix); sub.getsockopt(ZMQ_EVENTS); sub.unsubscribe(prefix); sub.getsockopt(ZMQ_EVENTS)`.  There will be many prefixes to subscribe/unsubscribe.\r\n\r\nCalling `getsockopt(ZMQ_EVENTS)` after `SUB`'s `SUBSCRIBE`/`UNSUBSCRIBE`, or `PUB`'s `zmq_connect()` will produce a crash due to the assertion failure in `mtrie_t::rm_helper`.\r\n\r\nYou can switch `PUB<->SUB` connection topology by the `pub_to_sub` variable.\r\n\r\n```c\r\n#include \"zmq.h\"\r\n#include <stdio.h>\r\n\r\n// Set 1 or 0 to switch the PUB<->SUB connection topology.\r\nstatic int pub_to_sub = 1;\r\n\r\nvoid gen_topic(int n, char* topic)\r\n{\r\n    // Simple hash function to generate a subscription prefix from a number.\r\n    n = (n * 2654435761);\r\n    sprintf(topic, \"%08x\", n);\r\n}\r\n\r\nvoid getsockopt_events_within_many_subscriptions(void* sub)\r\n{\r\n    char topic[8];\r\n    char opt[256];\r\n    size_t opt_len = 256;\r\n\r\n    for (int j = 0; j < 10000; ++j)\r\n    {\r\n        gen_topic(j, topic);\r\n        zmq_setsockopt(sub, ZMQ_SUBSCRIBE, &topic, 8);\r\n        // CRASH: Get ZMQ_EVENTS from a SUB socket.\r\n        zmq_getsockopt(sub, ZMQ_EVENTS, opt, &opt_len);\r\n    }\r\n    for (int j = 0; j < 10000; ++j)\r\n    {\r\n        gen_topic(j, topic);\r\n        zmq_setsockopt(sub, ZMQ_UNSUBSCRIBE, &topic, 8);\r\n        // CRASH: Get ZMQ_EVENTS from a SUB socket.\r\n        zmq_getsockopt(sub, ZMQ_EVENTS, opt, &opt_len);\r\n    }\r\n}\r\n\r\nint main()\r\n{\r\n    printf(\"%d.%d.%d\\n\", ZMQ_VERSION_MAJOR, ZMQ_VERSION_MINOR, ZMQ_VERSION_PATCH);\r\n\r\n    void *context = zmq_ctx_new();\r\n    void *pub = zmq_socket(context, ZMQ_PUB);\r\n    void *sub;\r\n\r\n    char addr[256]; size_t addr_len = 256;\r\n    char opt[256];  size_t opt_len  = 256;\r\n\r\n    if (pub_to_sub)\r\n    {\r\n        // PUB->SUB\r\n        for (int i = 0; i < 100; ++i)\r\n        {\r\n            sub = zmq_socket(context, ZMQ_SUB);\r\n\r\n            zmq_bind(sub, \"tcp://127.0.0.1:*\");\r\n            zmq_getsockopt(sub, ZMQ_LAST_ENDPOINT, addr, &addr_len);\r\n            zmq_connect(pub, addr);\r\n\r\n            getsockopt_events_within_many_subscriptions(sub);\r\n        }\r\n    }\r\n    else\r\n    {\r\n        // SUB->PUB\r\n        zmq_bind(pub, \"tcp://127.0.0.1:*\");\r\n        zmq_getsockopt(pub, ZMQ_LAST_ENDPOINT, addr, &addr_len);\r\n        for (int i = 0; i < 100; ++i)\r\n        {\r\n            sub = zmq_socket(context, ZMQ_SUB);\r\n\r\n            zmq_connect(sub, addr);\r\n\r\n            getsockopt_events_within_many_subscriptions(sub);\r\n\r\n            // CRASH: Get ZMQ_EVENTS from the PUB socket.\r\n            zmq_getsockopt(pub, ZMQ_EVENTS, opt, &opt_len);\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n# What's the actual result? (include assertion message & call stack if applicable)\r\n\r\n```console\r\n$ gcc zmq_events_crash.c -L ~/usr/local/lib -lzmq && ./a.out\r\n4.2.3\r\nAssertion failed: erased == 1 (src/mtrie.cpp:297)\r\n[1]    30266 abort (core dumped)  ./a.out\r\n```\r\n\r\n# What's the expected result?\r\n\r\n```console\r\n$ gcc zmq_events_crash.c -L ~/usr/local/lib -lzmq && ./a.out\r\n4.2.3\r\n$ echo $?\r\n0\r\n```\r\n\r\nWhen `SUB` sockets connect to the `PUB` socket, this crash doesn't happen."},"comment":{"url":"https://api.github.com/repos/zeromq/libzmq/issues/comments/369996756","html_url":"https://github.com/zeromq/libzmq/issues/2942#issuecomment-369996756","issue_url":"https://api.github.com/repos/zeromq/libzmq/issues/2942","id":369996756,"user":{"login":"bluca","id":782193,"avatar_url":"https://avatars3.githubusercontent.com/u/782193?v=4","gravatar_id":"","url":"https://api.github.com/users/bluca","html_url":"https://github.com/bluca","followers_url":"https://api.github.com/users/bluca/followers","following_url":"https://api.github.com/users/bluca/following{/other_user}","gists_url":"https://api.github.com/users/bluca/gists{/gist_id}","starred_url":"https://api.github.com/users/bluca/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bluca/subscriptions","organizations_url":"https://api.github.com/users/bluca/orgs","repos_url":"https://api.github.com/users/bluca/repos","events_url":"https://api.github.com/users/bluca/events{/privacy}","received_events_url":"https://api.github.com/users/bluca/received_events","type":"User","site_admin":false},"created_at":"2018-03-02T17:46:08Z","updated_at":"2018-03-02T17:46:08Z","author_association":"OWNER","body":"@sublee please try again from latest master"}}
{"actor":{"display_login":"bluca"}}