{"action":"created","issue":{"url":"https://api.github.com/repos/google/flatbuffers/issues/136","labels_url":"https://api.github.com/repos/google/flatbuffers/issues/136/labels{/name}","comments_url":"https://api.github.com/repos/google/flatbuffers/issues/136/comments","events_url":"https://api.github.com/repos/google/flatbuffers/issues/136/events","html_url":"https://github.com/google/flatbuffers/issues/136","id":55625099,"number":136,"title":"Not Safe for Multiple Readers","user":{"login":"pjulien","id":673277,"avatar_url":"https://avatars.githubusercontent.com/u/673277?v=3","gravatar_id":"","url":"https://api.github.com/users/pjulien","html_url":"https://github.com/pjulien","followers_url":"https://api.github.com/users/pjulien/followers","following_url":"https://api.github.com/users/pjulien/following{/other_user}","gists_url":"https://api.github.com/users/pjulien/gists{/gist_id}","starred_url":"https://api.github.com/users/pjulien/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pjulien/subscriptions","organizations_url":"https://api.github.com/users/pjulien/orgs","repos_url":"https://api.github.com/users/pjulien/repos","events_url":"https://api.github.com/users/pjulien/events{/privacy}","received_events_url":"https://api.github.com/users/pjulien/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":4,"created_at":"2015-01-27T14:37:20Z","updated_at":"2015-01-27T20:52:29Z","closed_at":null,"body":"It seems flat buffers are not safe to read from multiple reader threads at the same time.  This is because of methods line this one:\r\n\r\n```\r\n  protected String __string(int offset) {\r\n    offset += bb.getInt(offset);\r\n    if (bb.hasArray()) {\r\n      return new String(bb.array(), offset + SIZEOF_INT, bb.getInt(offset), FlatBufferBuilder.utf8charset);\r\n    } else {\r\n      // We can't access .array(), since the ByteBuffer is read-only.\r\n      // We're forced to make an extra copy:\r\n      byte[] copy = new byte[bb.getInt(offset)];\r\n      int old_pos = bb.position();\r\n      bb.position(offset + SIZEOF_INT);\r\n      bb.get(copy);\r\n      bb.position(old_pos);\r\n      return new String(copy, 0, copy.length, FlatBufferBuilder.utf8charset);\r\n    }\r\n  }\r\n```\r\n\r\nThe problem is that in-between \r\n\r\n```\r\n      int old_pos = bb.position();\r\n```\r\n\r\nand\r\n\r\n```\r\n      bb.position(old_pos);\r\n```\r\n\r\nThe reader has modified the buffer that is globally visible to all other threads.  There are several ways to solve this:\r\n\r\n- Could use ``Unsafe``\r\n- Could use the get with a positional index to reach every byte one by one.\r\n- Could call ``ByteBuffer#duplicate``\r\n\r\nI'm working around the issue using duplicate for the moment.  @gwvo Let me know what you prefer and I'll make a PR.\r\n"},"comment":{"url":"https://api.github.com/repos/google/flatbuffers/issues/comments/71725461","html_url":"https://github.com/google/flatbuffers/issues/136#issuecomment-71725461","issue_url":"https://api.github.com/repos/google/flatbuffers/issues/136","id":71725461,"user":{"login":"gwvo","id":6145400,"avatar_url":"https://avatars.githubusercontent.com/u/6145400?v=3","gravatar_id":"","url":"https://api.github.com/users/gwvo","html_url":"https://github.com/gwvo","followers_url":"https://api.github.com/users/gwvo/followers","following_url":"https://api.github.com/users/gwvo/following{/other_user}","gists_url":"https://api.github.com/users/gwvo/gists{/gist_id}","starred_url":"https://api.github.com/users/gwvo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gwvo/subscriptions","organizations_url":"https://api.github.com/users/gwvo/orgs","repos_url":"https://api.github.com/users/gwvo/repos","events_url":"https://api.github.com/users/gwvo/events{/privacy}","received_events_url":"https://api.github.com/users/gwvo/received_events","type":"User","site_admin":false},"created_at":"2015-01-27T20:52:28Z","updated_at":"2015-01-27T20:52:28Z","body":"I was hoping that for most users, `bb.hasArray()` is true, so this wouldn't be an issue..\r\n\r\nI'd be glad to see an improvement to this code, however. My primary concern is speed (the loop based version sounds like it could be slow). My secondary concern is simplicity (the vast majority of callers will want a string, so we should give them that). The third concern is code size / method count (adding additional methods isn't great unless the payoff is great).\r\n\r\nUsing a StringBuilder or CharSequence could be good, problem is, what do you do with one of these once you get it? If you need to convert it to String anyway to look at it, there's no point."}}