00001 #ifndef guard_range_checking_hpp 00002 #define guard_range_checking_hpp 00003 /** 00004 * @file 00005 * 00006 * @brief Details can be found in the documentation for 00007 * TAO::details::generic_sequence 00008 * 00009 * $Id: Range_Checking_T.h 86955 2009-10-06 11:02:41Z vzykov $ 00010 * 00011 * @author Carlos O'Ryan 00012 */ 00013 00014 #include "tao/Basic_Types.h" 00015 #include "tao/SystemException.h" 00016 00017 #if !defined (TAO_CHECKED_SEQUENCE_INDEXING) && !defined (ACE_NDEBUG) 00018 # define TAO_CHECKED_SEQUENCE_INDEXING 1 00019 #endif 00020 00021 TAO_BEGIN_VERSIONED_NAMESPACE_DECL 00022 00023 namespace TAO 00024 { 00025 namespace details 00026 { 00027 00028 /** 00029 * @struct range_checking 00030 * 00031 * @brief Configurable traits to tradeoff safety vs. performance in 00032 * the implementation of TAO sequences. 00033 * 00034 * The CORBA specification grants certain latitude to implementors by 00035 * not defining the behavior of sequences under certain conditions. 00036 * Probably the most clear example is the operator[] access, where the 00037 * application <b>must</b> set the length to a high enough value 00038 * before using the operator[]. 00039 * 00040 * Implementors that cater to high-performance applications tend to 00041 * exploit this latitude to the extreme, basically reasoning that 00042 * correct applications will behave normally, while incorrect 00043 * applications will crash, but those crashes will be detected during 00044 * development/testing. 00045 * 00046 * Realizing that this may be a bad tradeoff some implementors offer 00047 * compile-time hooks to control the behavior of sequences when used 00048 * improperly, some implementors may go as far as using run-time 00049 * hooks. 00050 * 00051 * The implementation of sequences calls the following template class 00052 * in points where the application may trigger undefined behavior. 00053 * The application developer can use partial (or full) template 00054 * specialization to introduce her own code at these critical points. 00055 * 00056 * Some examples may help, suppose you want to change your application 00057 * so for all sequence types the operator[] raises an exception if the 00058 * index is out of range. Then you would provide the following 00059 * (partial) template specialization: 00060 * 00061 * <PRE> 00062 * template<typename T> 00063 * struct range_checking<T,true> { 00064 * void check(CORBA::ULong index, CORBA::ULong length) { 00065 * if (index < length) 00066 * return; 00067 * throw std::range_error("CORBA sequence range error"); 00068 * }; 00069 * ... 00070 * .. 00071 * }; 00072 * </PRE> 00073 * 00074 * This specialization must be introduced before any sequence code is 00075 * seen, therefore, the application would also need to define the 00076 * following macro in their $ACE_ROOT/ace/config.h file: 00077 * 00078 * - #define TAO_USER_DEFINED_SEQUENCE_SAFETY_TRAITS_INCLUDE "<filename here>" 00079 * 00080 * Likewise, if the application only wanted to check the range for a 00081 * special type, say some structure MyStruct, then they would provide 00082 * a full specialization. Just for giggles, we will also introduce 00083 * run-time controls to this example: 00084 * 00085 * <PRE> 00086 * template<> 00087 * struct safety_traits<tao::details::value_traits<MyStruct>,true> { 00088 * bool enable_range_checking; 00089 * void check_range(CORBA::ULong index, CORBA::ULong length) { 00090 * if (!enable_range_checking || index < length) 00091 * return; 00092 * throw std::range_error("CORBA sequence range error"); 00093 * }; 00094 * ... 00095 * .. 00096 * }; 00097 * </PRE> 00098 * 00099 * 00100 * 00101 * @todo There is no control on a per-sequence type basis, only on a 00102 * per-underlying type basis, for example, the following two IDL 00103 * sequences would get the same behavior: 00104 * // IDL 00105 * typedef sequence<MyStruct> MyStructSequence; 00106 * typedef sequence<MyStruct> MyStructList; 00107 * 00108 * @todo There is no way to control behavior on a per-sequence basis, 00109 * i.e. to have some sequences of longs checked while others are 00110 * not. This is easy to fix, simply: 00111 * - make all members of safety_traits non-static 00112 * - have each sequence contain their own instance of 00113 * safety_traits 00114 * - grant users read/write access to the safety_traits of each 00115 * sequence 00116 * but there are footprint consequences to that approach. Until 00117 * there is more demand to justify the cost, I will not 00118 * implement such a change. 00119 */ 00120 template<typename T, bool dummy> 00121 struct range_checking 00122 { 00123 typedef T value_type; 00124 00125 inline static void check( 00126 CORBA::ULong index, 00127 CORBA::ULong length, 00128 CORBA::ULong /* maximum */, 00129 char const * /* function_name */) 00130 { 00131 // Applications and tests can specialize this function to define 00132 // their own behavior 00133 #if defined (TAO_CHECKED_SEQUENCE_INDEXING) && (TAO_CHECKED_SEQUENCE_INDEXING == 1) 00134 if (length <= index) 00135 throw ::CORBA::BAD_PARAM (); 00136 #else 00137 ACE_UNUSED_ARG (index); 00138 ACE_UNUSED_ARG (length); 00139 #endif // TAO_CHECKED_SEQUENCE_INDEXING 00140 } 00141 00142 inline static void check_length( 00143 CORBA::ULong &new_length, 00144 CORBA::ULong maximum) 00145 { 00146 if (maximum < new_length) 00147 throw ::CORBA::BAD_PARAM (); 00148 } 00149 }; 00150 00151 } // namespace details 00152 } // namespace TAO 00153 00154 TAO_END_VERSIONED_NAMESPACE_DECL 00155 00156 #if defined(TAO_USER_DEFINED_SEQUENCE_RANGE_CHECKING_INCLUDE) 00157 # include TAO_USER_DEFINED_SEQUENCE_RANGE_CHECKING_INCLUDE 00158 #endif // TAO_USER_DEFINED_SEQUENCE_RANGE_CHECKING_INCLUDE 00159 00160 #endif // guard_range_checking_hpp