{"action":"created","issue":{"url":"https://api.github.com/repos/fusepy/fusepy/issues/116","repository_url":"https://api.github.com/repos/fusepy/fusepy","labels_url":"https://api.github.com/repos/fusepy/fusepy/issues/116/labels{/name}","comments_url":"https://api.github.com/repos/fusepy/fusepy/issues/116/comments","events_url":"https://api.github.com/repos/fusepy/fusepy/issues/116/events","html_url":"https://github.com/fusepy/fusepy/issues/116","id":316222495,"number":116,"title":"Segfault when calling fuse_exit","user":{"login":"frossigneux","id":739143,"avatar_url":"https://avatars2.githubusercontent.com/u/739143?v=4","gravatar_id":"","url":"https://api.github.com/users/frossigneux","html_url":"https://github.com/frossigneux","followers_url":"https://api.github.com/users/frossigneux/followers","following_url":"https://api.github.com/users/frossigneux/following{/other_user}","gists_url":"https://api.github.com/users/frossigneux/gists{/gist_id}","starred_url":"https://api.github.com/users/frossigneux/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/frossigneux/subscriptions","organizations_url":"https://api.github.com/users/frossigneux/orgs","repos_url":"https://api.github.com/users/frossigneux/repos","events_url":"https://api.github.com/users/frossigneux/events{/privacy}","received_events_url":"https://api.github.com/users/frossigneux/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":7,"created_at":"2018-04-20T10:57:23Z","updated_at":"2018-05-22T18:18:38Z","closed_at":null,"author_association":"NONE","body":"When I do a fuse_exit from a side thread, I get a segfault.\r\n\r\nSo I looked at the problem, and I see that `fuse_get_context().contents` seems to be only zero filled (all attributes set to 0 or None from Python point of view). This obviously cause the segfault when calling `_libfuse.fuse_exit` whith a null pointer.\r\n\r\nLooking into libfuse implementation, it seems `fuse_context` is valid for the duration of a single filesystem operation, which would explain why trying to get such object from outside of the fuse thread end up with an empty object (see https://github.com/libfuse/libfuse/blob/1a4afa80292534e92ecb4b9f6665d1910d573ca3/include/fuse.h#L979-L987).\r\n\r\nHowever I don't see how I could use `fuse_exit` from the main fuse thread (given it runs python code only when filesystem operations are processed...)\r\n\r\nIs there a workaround?"},"comment":{"url":"https://api.github.com/repos/fusepy/fusepy/issues/comments/391090718","html_url":"https://github.com/fusepy/fusepy/issues/116#issuecomment-391090718","issue_url":"https://api.github.com/repos/fusepy/fusepy/issues/116","id":391090718,"user":{"login":"N-Coder","id":1306276,"avatar_url":"https://avatars2.githubusercontent.com/u/1306276?v=4","gravatar_id":"","url":"https://api.github.com/users/N-Coder","html_url":"https://github.com/N-Coder","followers_url":"https://api.github.com/users/N-Coder/followers","following_url":"https://api.github.com/users/N-Coder/following{/other_user}","gists_url":"https://api.github.com/users/N-Coder/gists{/gist_id}","starred_url":"https://api.github.com/users/N-Coder/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/N-Coder/subscriptions","organizations_url":"https://api.github.com/users/N-Coder/orgs","repos_url":"https://api.github.com/users/N-Coder/repos","events_url":"https://api.github.com/users/N-Coder/events{/privacy}","received_events_url":"https://api.github.com/users/N-Coder/received_events","type":"User","site_admin":false},"created_at":"2018-05-22T18:18:38Z","updated_at":"2018-05-22T18:18:38Z","author_association":"CONTRIBUTOR","body":"It seems that the `The service python has failed to start` message (which is windows-specific) sometimes also shows up when the FUSE driver stops shortly after being started. So if you use the following code in your example and open the directory manually a few seconds after starting the driver everything should work (minus Windows Explorer having a problem with the mount going away while trying to access it):\r\n```python\r\ndef getattr(self, path, fh=None):\r\n    if path == \"/FUSE_EXIT\":\r\n        fuse_exit()\r\n    return super().getattr(path, fh)\r\n```\r\nThe `The service python has been stopped` message means what it says - that the FUSE driver was actually stopped, which is exactly what you want. That the main process is also affected might have to do with which process ID you are sending the signal to or how the main process handles termination of a child.\r\n\r\n------------\r\n\r\nIt seems that the fuse implementation on Linux is not as strict as WinFSP with regard to the \"The context is only valid for the duration of a filesystem operation, and thus must not be stored and used later.\" restriction mentioned in your first comment. So on Linux, the context luckily still contains valid data when called from another thread than the main thread, while on Windows it is 0-filled. \r\nThis behaviour can be reproduced with the following code, which will give the `OSError: exception: access violation reading 0x00000334` on Windows while working flawlessly on Linux.\r\n```python\r\ndef fuse_exit():\r\n    print(\"fuse_exit called\")\r\n    time.sleep(10)\r\n    fuse_ptr = ctypes.c_void_p(_libfuse.fuse_get_context().contents.fuse)\r\n    print(fuse_ptr)\r\n    _libfuse.fuse_exit(fuse_ptr)\r\n\r\n\r\nclass FuseOperations(LoggingMixIn, Operations):\r\n    def getattr(self, path, fh=None):\r\n        Thread(target=fuse_exit).start()\r\n        return super().getattr(path, fh)\r\n```\r\n\r\nTo fix this problem, you can simply save the address of the fuse pointer for later use:\r\n```python\r\ndef fuse_exit(fuse_ptr=None):\r\n    from fuse import _libfuse\r\n    import ctypes\r\n\r\n    print(\"fuse_exit called\")\r\n    time.sleep(10)\r\n    if not fuse_ptr:\r\n        fuse_ptr = ctypes.c_void_p(_libfuse.fuse_get_context().contents.fuse)\r\n    print(fuse_ptr)\r\n    _libfuse.fuse_exit(fuse_ptr)\r\n\r\n\r\nclass FuseOperations(LoggingMixIn, Operations):\r\n    def getattr(self, path, fh=None):\r\n        fuse_ptr = ctypes.c_void_p(_libfuse.fuse_get_context().contents.fuse)\r\n        Thread(target=fuse_exit, args=(fuse_ptr,)).start()\r\n        return super().getattr(path, fh)\r\n```\r\nThis is a little bit hacky, but so is calling a function from another thread that only wants to be called from the main thread. This might also be the solution for #105 until somebody finds out why `release` is different from the other methods. I don't think we should include this in the library though, as it's not the cleanest solution and according to the FUSE docs, the context `must not be stored and used later`."}}
{"actor":{"display_login":"N-Coder"}}