TestMustReturnFromCaller.cpp (5573B)
1 #include <cstddef> 2 #include <utility> 3 4 #define MOZ_MUST_RETURN_FROM_CALLER_IF_THIS_IS_ARG __attribute__((annotate("moz_must_return_from_caller_if_this_is_arg"))) 5 #define MOZ_MAY_CALL_AFTER_MUST_RETURN __attribute__((annotate("moz_may_call_after_must_return"))) 6 7 struct Thrower { 8 void MOZ_MUST_RETURN_FROM_CALLER_IF_THIS_IS_ARG Throw() {} 9 }; 10 11 void DoAnythingElse(); 12 int MakeAnInt(); 13 int MOZ_MAY_CALL_AFTER_MUST_RETURN SafeMakeInt(); 14 bool Condition(); 15 16 // It might be nicer to #include "mozilla/ScopeExit.h" and use that here -- but 17 // doing so also will #define the two attribute-macros defined above, running a 18 // risk of redefinition errors. Just stick to the normal clang-plugin test 19 // style and use as little external code as possible. 20 21 template<typename Func> 22 class ScopeExit { 23 Func exitFunction; 24 bool callOnDestruction; 25 public: 26 explicit ScopeExit(Func&& func) 27 : exitFunction(std::move(func)) 28 , callOnDestruction(true) 29 {} 30 31 ~ScopeExit() { 32 if (callOnDestruction) { 33 exitFunction(); 34 } 35 } 36 37 void release() { callOnDestruction = false; } 38 }; 39 40 template<typename ExitFunction> 41 ScopeExit<ExitFunction> 42 MakeScopeExit(ExitFunction&& func) 43 { 44 return ScopeExit<ExitFunction>(std::move(func)); 45 } 46 47 class Foo { 48 public: 49 __attribute__((annotate("moz_implicit"))) Foo(std::nullptr_t); 50 Foo(); 51 }; 52 53 void a1(Thrower& thrower) { 54 thrower.Throw(); 55 } 56 57 int a2(Thrower& thrower) { 58 thrower.Throw(); // expected-error {{You must immediately return after calling this function}} 59 return MakeAnInt(); 60 } 61 62 int a3(Thrower& thrower) { 63 // RAII operations happening after a must-immediately-return are fine. 64 auto atExit = MakeScopeExit([] { DoAnythingElse(); }); 65 thrower.Throw(); 66 return 5; 67 } 68 69 int a4(Thrower& thrower) { 70 thrower.Throw(); // expected-error {{You must immediately return after calling this function}} 71 return Condition() ? MakeAnInt() : MakeAnInt(); 72 } 73 74 void a5(Thrower& thrower) { 75 thrower.Throw(); // expected-error {{You must immediately return after calling this function}} 76 DoAnythingElse(); 77 } 78 79 int a6(Thrower& thrower) { 80 thrower.Throw(); // expected-error {{You must immediately return after calling this function}} 81 DoAnythingElse(); 82 return MakeAnInt(); 83 } 84 85 int a7(Thrower& thrower) { 86 thrower.Throw(); // expected-error {{You must immediately return after calling this function}} 87 DoAnythingElse(); 88 return Condition() ? MakeAnInt() : MakeAnInt(); 89 } 90 91 int a8(Thrower& thrower) { 92 thrower.Throw(); 93 return SafeMakeInt(); 94 } 95 96 int a9(Thrower& thrower) { 97 if (Condition()) { 98 thrower.Throw(); 99 } 100 return SafeMakeInt(); 101 } 102 103 int a10(Thrower& thrower) { 104 auto atExit = MakeScopeExit([] { DoAnythingElse(); }); 105 106 if (Condition()) { 107 thrower.Throw(); 108 return SafeMakeInt(); 109 } 110 111 atExit.release(); 112 DoAnythingElse(); 113 return 5; 114 } 115 116 void b1(Thrower& thrower) { 117 if (Condition()) { 118 thrower.Throw(); 119 } 120 } 121 122 int b2(Thrower& thrower) { 123 if (Condition()) { 124 thrower.Throw(); // expected-error {{You must immediately return after calling this function}} 125 } 126 return MakeAnInt(); 127 } 128 129 int b3(Thrower& thrower) { 130 if (Condition()) { 131 thrower.Throw(); 132 } 133 return 5; 134 } 135 136 // Explicit test in orer to also verify the `UnaryOperator` node in the `CFG` 137 int b3a(Thrower& thrower) { 138 if (Condition()) { 139 thrower.Throw(); 140 } 141 return -1; 142 } 143 144 float b3b(Thrower& thrower) { 145 if (Condition()) { 146 thrower.Throw(); 147 } 148 return 1.0f; 149 } 150 151 bool b3c(Thrower& thrower) { 152 if (Condition()) { 153 thrower.Throw(); 154 } 155 return false; 156 } 157 158 int b4(Thrower& thrower) { 159 if (Condition()) { 160 thrower.Throw(); // expected-error {{You must immediately return after calling this function}} 161 } 162 return Condition() ? MakeAnInt() : MakeAnInt(); 163 } 164 165 void b5(Thrower& thrower) { 166 if (Condition()) { 167 thrower.Throw(); // expected-error {{You must immediately return after calling this function}} 168 } 169 DoAnythingElse(); 170 } 171 172 void b6(Thrower& thrower) { 173 if (Condition()) { 174 thrower.Throw(); // expected-error {{You must immediately return after calling this function}} 175 DoAnythingElse(); 176 } 177 } 178 179 void b7(Thrower& thrower) { 180 if (Condition()) { 181 thrower.Throw(); 182 return; 183 } 184 DoAnythingElse(); 185 } 186 187 void b8(Thrower& thrower) { 188 if (Condition()) { 189 thrower.Throw(); // expected-error {{You must immediately return after calling this function}} 190 DoAnythingElse(); 191 return; 192 } 193 DoAnythingElse(); 194 } 195 196 void b9(Thrower& thrower) { 197 while (Condition()) { 198 thrower.Throw(); // expected-error {{You must immediately return after calling this function}} 199 } 200 } 201 202 void b10(Thrower& thrower) { 203 while (Condition()) { 204 thrower.Throw(); 205 return; 206 } 207 } 208 209 void b11(Thrower& thrower) { 210 thrower.Throw(); // expected-error {{You must immediately return after calling this function}} 211 if (Condition()) { 212 return; 213 } else { 214 return; 215 } 216 } 217 218 void b12(Thrower& thrower) { 219 switch (MakeAnInt()) { 220 case 1: 221 break; 222 default: 223 thrower.Throw(); 224 return; 225 } 226 } 227 228 void b13(Thrower& thrower) { 229 if (Condition()) { 230 thrower.Throw(); 231 } 232 return; 233 } 234 235 Foo b14(Thrower& thrower) { 236 if (Condition()) { 237 thrower.Throw(); 238 return nullptr; 239 } 240 return nullptr; 241 } 242 243 Foo b15(Thrower& thrower) { 244 if (Condition()) { 245 thrower.Throw(); 246 } 247 return nullptr; 248 } 249 250 Foo b16(Thrower& thrower) { 251 if (Condition()) { 252 thrower.Throw(); 253 } 254 return Foo(); 255 } 256 257 void c1() { 258 Thrower thrower; 259 thrower.Throw(); 260 DoAnythingElse(); // Should be allowed, since our thrower is not an arg 261 } 262 263 class TestRet { 264 TestRet *b13(Thrower &thrower) { 265 if (Condition()) { 266 thrower.Throw(); 267 } 268 return this; 269 } 270 };