{"action":"created","issue":{"url":"https://api.github.com/repos/robotology/yarp/issues/435","labels_url":"https://api.github.com/repos/robotology/yarp/issues/435/labels{/name}","comments_url":"https://api.github.com/repos/robotology/yarp/issues/435/comments","events_url":"https://api.github.com/repos/robotology/yarp/issues/435/events","html_url":"https://github.com/robotology/yarp/issues/435","id":60329003,"number":435,"title":"[Plugins] Unexpected behaviour when DeviceDriver/Carrier is not the first inherited class","user":{"login":"drdanz","id":1100056,"avatar_url":"https://avatars.githubusercontent.com/u/1100056?v=3","gravatar_id":"","url":"https://api.github.com/users/drdanz","html_url":"https://github.com/drdanz","followers_url":"https://api.github.com/users/drdanz/followers","following_url":"https://api.github.com/users/drdanz/following{/other_user}","gists_url":"https://api.github.com/users/drdanz/gists{/gist_id}","starred_url":"https://api.github.com/users/drdanz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/drdanz/subscriptions","organizations_url":"https://api.github.com/users/drdanz/orgs","repos_url":"https://api.github.com/users/drdanz/repos","events_url":"https://api.github.com/users/drdanz/events{/privacy}","received_events_url":"https://api.github.com/users/drdanz/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/robotology/yarp/labels/Component:%20YARP_OS","name":"Component: YARP_OS","color":"207de5"},{"url":"https://api.github.com/repos/robotology/yarp/labels/Severity:%20Major","name":"Severity: Major","color":"e11d21"},{"url":"https://api.github.com/repos/robotology/yarp/labels/Type:%20Bug","name":"Type: Bug","color":"fc2929"}],"state":"open","locked":false,"assignee":{"login":"drdanz","id":1100056,"avatar_url":"https://avatars.githubusercontent.com/u/1100056?v=3","gravatar_id":"","url":"https://api.github.com/users/drdanz","html_url":"https://github.com/drdanz","followers_url":"https://api.github.com/users/drdanz/followers","following_url":"https://api.github.com/users/drdanz/following{/other_user}","gists_url":"https://api.github.com/users/drdanz/gists{/gist_id}","starred_url":"https://api.github.com/users/drdanz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/drdanz/subscriptions","organizations_url":"https://api.github.com/users/drdanz/orgs","repos_url":"https://api.github.com/users/drdanz/repos","events_url":"https://api.github.com/users/drdanz/events{/privacy}","received_events_url":"https://api.github.com/users/drdanz/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/robotology/yarp/milestones/2","html_url":"https://github.com/robotology/yarp/milestones/YARP%202.4.0","labels_url":"https://api.github.com/repos/robotology/yarp/milestones/2/labels","id":326863,"number":2,"title":"YARP 2.4.0","description":"Next major release","creator":{"login":"drdanz","id":1100056,"avatar_url":"https://avatars.githubusercontent.com/u/1100056?v=3","gravatar_id":"","url":"https://api.github.com/users/drdanz","html_url":"https://github.com/drdanz","followers_url":"https://api.github.com/users/drdanz/followers","following_url":"https://api.github.com/users/drdanz/following{/other_user}","gists_url":"https://api.github.com/users/drdanz/gists{/gist_id}","starred_url":"https://api.github.com/users/drdanz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/drdanz/subscriptions","organizations_url":"https://api.github.com/users/drdanz/orgs","repos_url":"https://api.github.com/users/drdanz/repos","events_url":"https://api.github.com/users/drdanz/events{/privacy}","received_events_url":"https://api.github.com/users/drdanz/received_events","type":"User","site_admin":false},"open_issues":6,"closed_issues":6,"state":"open","created_at":"2013-05-04T15:25:14Z","updated_at":"2015-03-09T11:18:12Z","due_on":null,"closed_at":null},"comments":1,"created_at":"2015-03-09T11:18:11Z","updated_at":"2015-03-09T15:14:04Z","closed_at":null,"body":"When deleting a device/carrier from a plugin, if the `yarp::dev::DeviceDriver`/`yarp::os::Carrier` class is not the first inherited class, something completely unexpected can happen (I noticed this because instead of the destructor of the class a complete different function was called by `delete`.\r\nFrom the `YARP_DEFINE_SHARED_SUBCLASS` definition:\r\n\r\n```c++\r\n#define YARP_DEFINE_SHARED_SUBCLASS(factoryname,classname,basename) \\\r\n    YARP_SHARED_CLASS_FN void *factoryname ## _create () { return (basename *)new classname; } \\\r\n    YARP_SHARED_CLASS_FN void factoryname ## _destroy (void *obj) { delete (classname *)obj; } \\\r\n// [...]\r\n```\r\n\r\nIf the class is not the first, then ``return (basename *)new classname;`` will return a different address from the one returned by `new` (i.e. \"`classname *` + `offset`\") .\r\nThen the object is used, but when it is destroyed it is casted to `classname *` from a `void *`, therefore not using any knowledge about the base class. Therefore the pointer to \"`classname *` + `offset`\" is interpreted as if it was just \"`classname *`\", and instead of the destructor (that should be at \"`classname *` + `delete-offset`\") some random call is executed (the one found at \"`classname *` + `offset` + `delete-offset`\".\r\n\r\nDepending on what is called, this can break horribly everything and debugging can be very painful.\r\n\r\nIn order to fix this, it is possible to double-cast the pointer to `basename *` first and to `classname *` after:\r\n\r\n```c++\r\n    YARP_SHARED_CLASS_FN void factoryname ## _destroy (void *obj) { delete (classname *)(basename *)obj; } \\\r\n```\r\n\r\ncasting ``void *`` to ``basename *`` and then to ``classname *`` will automatically take into account the `offset` and everything should work.\r\n\r\n@paulfitz I could just change that line, but I have a couple of issues about this:\r\n\r\n* Which kind of casts should we use? `static_cast`/c-style cast is probably the right thing to do from `void *` to `basename *`. For the cast from `basename *` to `classname *` both `dynamic_cast` and `static_cast` will work, but I'm not sure if conceptually `static_cast` is correct.\r\n* Even though we just bumped the plugin systemVersion number, I'd like to bump it again, to ensure that we don't have broken plugins around, is it ok for you?\r\n\r\n```c++\r\n    YARP_SHARED_CLASS_FN void factoryname ## _destroy (void *obj) { delete (classname *)(basename *)obj; } \\\r\n```"},"comment":{"url":"https://api.github.com/repos/robotology/yarp/issues/comments/77872241","html_url":"https://github.com/robotology/yarp/issues/435#issuecomment-77872241","issue_url":"https://api.github.com/repos/robotology/yarp/issues/435","id":77872241,"user":{"login":"paulfitz","id":118367,"avatar_url":"https://avatars.githubusercontent.com/u/118367?v=3","gravatar_id":"","url":"https://api.github.com/users/paulfitz","html_url":"https://github.com/paulfitz","followers_url":"https://api.github.com/users/paulfitz/followers","following_url":"https://api.github.com/users/paulfitz/following{/other_user}","gists_url":"https://api.github.com/users/paulfitz/gists{/gist_id}","starred_url":"https://api.github.com/users/paulfitz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paulfitz/subscriptions","organizations_url":"https://api.github.com/users/paulfitz/orgs","repos_url":"https://api.github.com/users/paulfitz/repos","events_url":"https://api.github.com/users/paulfitz/events{/privacy}","received_events_url":"https://api.github.com/users/paulfitz/received_events","type":"User","site_admin":false},"created_at":"2015-03-09T15:14:04Z","updated_at":"2015-03-09T15:14:04Z","body":"@drdanz yikes, good catch. Yes, please do bump the plugin version number. I defer to your judgement on the casts. "}}