A software engineer and a passionate java programmer
Method parameters and TOCTOU
I have always been fascinated by the Design by Contract approach:
Software always had bugs and always will”. Tired of this defeatist attitude? With Design by Contract, invented by Eiffel Software and one of the most widely recognized breakthroughs in the history of software engineering, you can write complex software and not wake up at night fearing that something, somewhere will go wrong. Design by Contract brings science to the construction of correct and robust software.
From this point of view, unfortunately, Java is not Eiffel. Therefore, even if I would have follow this Bertrand Meyer valuable concept, I had to cope with the language itself. I know in the past years some Java frameworks which implement Design by Contract have been proposed, but I have never had the chance to try them seriously. So what I do is simply checking input method parameters.
Usually I don’t check at all if a method object might be null, because I hope the method code will cause a NullPointerException after few lines far from the method beginning.
I think that «few lines far» from where the problem has originated is a reasonable trade off between a pure fail-fast (fail-early) approach, and a very impractical null check, repeated for each method parameters, which weighs the code readability down:
1234567891011121314151617181920212223242526
publicStringgetPromotionalCode(DatecurrentDate,DatebirthDate,Orderorder){if(currentDate==null){thrownewNullPointerException("Design by Contract violation: currentDate MUST NOT be null");}if(birthDate==null){thrownewNullPointerException("Design by Contract violation: birthDate MUST NOT be null");}if(order==null){thrownewNullPointerException("Design by Contract violation: order MUST NOT be null");}if(birthDate.after(currentDate)){thrownewIllegalArgumentException("Design by Contract violation: birthDate MUST NOT be after currentDate");}if(isTimeToOfferPromotion(currentDate.getTime(),birthDate.getTime())){returncomputePromotionalCode(currentDate.getTime(),order);}returnSORRY_ITS_NO_SPECIAL_OFFERS_TIME;}
You can surely improve readability, in fact Jim Shore suggest to encapsulate checks inside static methods of a class designed to convey the fail-fast meaning, but still you have to write code to perform the checks:
123456789101112131415
publicStringgetPromotionalCode(DatecurrentDate,DatebirthDate,Orderorder){DesignByContract.assertNotNull(currentDate,"currentDate");DesignByContract.assertNotNull(birthDate,"birthDate");DesignByContract.assertNotNull(order,"order");DesignByContract.assertFalse(birthDate.after(currentDate),"birthDate MUST NOT be after currentDate");if(isTimeToOfferPromotion(currentDate.getTime(),birthDate.getTime())){returncomputePromotionalCode(currentDate.getTime(),order);}returnSORRY_ITS_NO_SPECIAL_OFFERS_TIME;}
I prefer, instead, communicate the Design by Contract violation by javadocs, letting NullPointerException happen not to far from where a null check should have been. The only case when I explicitly check for null is when the code let propagate the method input parameter inside other object’s methods, without ever generating a NullPointerException like occurs for the order parameter:
/** * @param currentDate MUST NOT be null (Design by Contract). * @param birthDate MUST NOT be null (Design by Contract). MUST be less * then, or equal to, the currentDate (Design by Contract). * @param order MUST NOT be null (Design by Contract). * * @return the promotional code, or the * {@link #SORRY_ITS_NO_SPECIAL_OFFERS_TIME} message. * * @throws NullPointerException if a Design by Contract violation occurs. * @throws IllegalArgumentException if a Design by Contract violation occurs. */publicStringgetPromotionalCode(DatecurrentDate,DatebirthDate,Orderorder){if(order==null){thrownewNullPointerException("Design by Contract violation: order MUST NOT be null");}if(birthDate.after(currentDate)){thrownewIllegalArgumentException("Design by Contract violation: birthDate MUST NOT be after currentDate");}if(isTimeToOfferPromotion(currentDate.getTime(),birthDate.getTime())){returncomputePromotionalCode(currentDate.getTime(),order);}returnSORRY_ITS_NO_SPECIAL_OFFERS_TIME;}
The second step I do is to check which method input parameter is not an immutable object. When I found a mutable object I make a defensive copy, because even if the client changed the parameter value my local method defensive copy would remain unchanged:
/** * @param currentDate MUST NOT be null (Design by Contract). * @param birthDate MUST NOT be null (Design by Contract). MUST be less * then, or equal to, the currentDate (Design by Contract). * @param order MUST NOT be null (Design by Contract). * * @return the promotional code, or the * {@link #SORRY_ITS_NO_SPECIAL_OFFERS_TIME} message. * * @throws NullPointerException if a Design by Contract violation occurs. * @throws IllegalArgumentException if a Design by Contract violation occurs. */publicStringgetPromotionalCode(DatecurrentDate,DatebirthDate,Orderorder){if(order==null){thrownewNullPointerException("Design by Contract violation: order MUST NOT be null");}if(birthDate.after(currentDate)){thrownewIllegalArgumentException("Design by Contract violation: birthDate MUST NOT be after currentDate");}OrderorderDefensiveCopy=newOrder(order);DatecurrentDateDefensiveCopy=newDate(currentDate.getTime());DatebirthDateDefensiveCopy=newDate(birthDate.getTime());if(isTimeToOfferPromotion(currentDateDefensiveCopy.getTime(),birthDateDefensiveCopy.getTime())){returncomputePromotionalCode(currentDateDefensiveCopy.getTime(),orderDefensiveCopy);}returnSORRY_ITS_NO_SPECIAL_OFFERS_TIME;}
Finally I check for TOCTOU race condition, which stands for «Time Of Check Time Of Use». As explained in Building Secure Software by John Viega, Gary R. McGraw this precaution makes our method more secure when multi-threading comes into play.
In fact it might happen that just after our thread has checked that birthDate isn’t after currentDate, but before it has created the birthDateDefensiveCopy, another thread might change the birthDate value setting it after the currentDate, making totally worthless the initial Design by Contract check; the other thread might also set birthDate to another totally unexpected value making the method isTimeToOfferPromotion return false when it shouldn’t. A similar thing can be said for order. The core concept of TOCTOU is the existence of a temporal vulnerability window during which another running thread can change the used value after the value itself has been checked.
In order to avoid TOCTOU vulnerability window Joshua Bloch, in his book Effective Java, suggest the following two steps approach:
/** * @param currentDate MUST NOT be null (Design by Contract). * @param birthDate MUST NOT be null (Design by Contract). MUST be less * then, or equal to, the currentDate (Design by Contract). * @param order MUST NOT be null (Design by Contract). * * @return the promotional code, or the * {@link #SORRY_ITS_NO_SPECIAL_OFFERS_TIME} message. * * @throws NullPointerException if a Design by Contract violation occurs. * @throws IllegalArgumentException if a Design by Contract violation occurs. */publicStringgetPromotionalCode(DatecurrentDate,DatebirthDate,Orderorder){OrderorderDefensiveCopy=newOrder(order);DatecurrentDateDefensiveCopy=newDate(currentDate.getTime());DatebirthDateDefensiveCopy=newDate(birthDate.getTime());if(orderDefensiveCopy==null){thrownewNullPointerException("Design by Contract violation: order MUST NOT be null");}if(birthDateDefensiveCopy.after(currentDateDefensiveCopy)){thrownewIllegalArgumentException"Design by Contract violation: birthDate MUST NOT be after currentDate");}if(isTimeToOfferPromotion(currentDateDefensiveCopy.getTime(),birthDateDefensiveCopy.getTime())){returncomputePromotionalCode(currentDateDefensiveCopy.getTime(),orderDefensiveCopy);}returnSORRY_ITS_NO_SPECIAL_OFFERS_TIME;}
Let me know how you cope with the validation of method input parameters in order to avoid that bugs bubble up very far from where they have been originated. Do you validate method input parameters? Yes? No? Sometimes?
2 Comments to “Method parameters and TOCTOU”
Posted by Enrico #
Great article Tarin!
However, rather than using
java.util.Date
, I suggest you to use the immutablejava.time.LocalDate
.Posted by Tarin Gamberini #
Thanks Enrico,
You are perfectly right! Preferring immutable objects is a great hints.
It was an old Java 6 example, and Java 8 Date Time API has been a very welcome one to the core Java API.
Cheers,
Tarin
Post a comment
A comment is submitted by an ordinary e-mail. Your e-mail address will not be published or broadcast.
This blog is moderated, therefore some comments might not be published. Comments are usually approved by the moderator in one/three days.