?

Log in

No account? Create an account
   Journal    Friends    Archive    Profile    Memories
 

Nice bug - morfizm


Apr. 4th, 2011 04:32 pm Nice bug

Just found a bug of this kind:

There are two group of objects: A and B. Each A has one or more Bs. The old code was written with the assumptions that B objects can be reused across As, by just moving pointers. New code broke this assumption by tieing it to the parent A and introducing a shared field with A (again, shared by pointer). So, the bug was in old code, which was correct under old assumptions, but incorrect under new ones.

I am not sure what's the right way to avoid this class of bugs as a whole. I'd just be extremely careful with reusing/sharing objects by pointers, and add a comment in class definition for every field where it's a case.

11 comments - Leave a commentPrevious Entry Share Next Entry

Comments:

From:archaicos
Date:April 5th, 2011 02:29 am (UTC)
(Link)
Some constructor/destructor magic might help, maybe more is needed. And it depends on what you're doing. You may want to do some temporary refactoring to validate assumptions/find problems before changing the design/implementation. Or you may do this all the way to avoid issues in the future. Or both. Also, if this is something very perf sensitive you may want to fork into release/free and debug/checked versions with minimum overhead in the former.
From:morfizm
Date:April 5th, 2011 02:36 am (UTC)
(Link)
Now (in the aftermath) I am looking for architectural hint: what's the best practice to write code in a way to avoid this kind of bugs? How to make it the most clear, obvious, readable, apparent to a future developer that you may or may not reuse the same copy of B object for use with different A objects?
From:archaicos
Date:April 5th, 2011 02:46 am (UTC)
(Link)
Comments may not help. People don't like reading nowadays, not to mention writing elaborate explanations or reading such poems afterwards. :) You may add checks and restrictions in the code around the lifetime of A and B (e.g. who can create/destroy/access what, when and in what order).
From:archaicos
Date:April 5th, 2011 02:35 am (UTC)
(Link)
Btw, there's another classic bug of this type, which is in the sample code for the red-black tree implementation in this book: http://www.amazon.com/Introduction-Algorithms-CD-Rom-Thomas-Cormen/dp/0072970545/. The code shuffles node payload in one place instead of doing proper pointer exchange. You don't want your data to go somewhere else. :)
From:morfizm
Date:April 5th, 2011 02:38 am (UTC)
(Link)
Oh, sweet, I meant, stupid. How did they miss that bug? :)
From:archaicos
Date:April 5th, 2011 02:42 am (UTC)
(Link)
Well, their code didn't care where the data was, in which node, because it was, AFAIR, just a number and there was nothing else in the node. Now if you try to reuse the code for a real-life problem, where your node contains multiple entities and some may be indices, pointers or sizes, you're in a trouble. :)
From:dennyrolling
Date:April 5th, 2011 06:10 am (UTC)
(Link)
afair r-b tree code in the indexer was right off the book (template, and without the bug, of course, they did their own memory managment).
(no subject) - (Anonymous)
From:dennyrolling
Date:April 5th, 2011 06:41 am (UTC)
(Link)
казалось бы, при чем тут дот-нет?
From:sasha_gil
Date:April 5th, 2011 06:56 am (UTC)
(Link)
Купиться на дот-нет -- это для моего большого подразделения слишком рисковано (big bet! :) ). Хотя есть довольно большие и важные продукты, которые постепенно таки-переписываются на дот-нет (ну, я думаю, ты понимаешь, какой серверный софт я имею в виду)
From:morfizm
Date:April 5th, 2011 07:02 am (UTC)
(Link)
Идея очень интересная сама по себе. Я об этом когда-то думал, но руки не дошли до написания.

Описанная мной проблемы - это другое. Это Питон, и challenge в том, чтобы глянуть на код (на описание структур данных) и понять, эти поля - это скопированные объекты, или shared pointers. Брать за правило над всеми shared pointers делать wrapper-ы - это как-то не по-питоновски.
From:sasha_gil
Date:April 5th, 2011 07:18 am (UTC)
(Link)
А я, увы, с Пайтоном знаком довольно слабо. Вот есть ещё такой момент: что знавит, что "объект A владеет объектом B"? Во-первых, объект B - mutable (если данные immutable, о владении говорить нечего). Во-вторых, изменения B должны быть под полным контролем A. Но A хочет показать B наружу! По-моему, несколько поковырявшись, можно сделать прокси-обёртку для выставления наружу только immutable доступа для B - перенаправив все внешние mutating воздействия на B через A. Это может работать, если mutating-операций значительно меньше, чем immutable операций. Такой трюк можно провести через наследование "расширенного" B (доступного только A) от "базового" (immutable) B, который A выставляет наружу. Получится в Пайтоне?