Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020 Project CHIP Authors
4 : * Copyright (c) 2013-2017 Nest Labs, Inc.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : /**
20 : * @file
21 : * This file defines and implements a number of miscellaneous
22 : * templates for finding object minima and maxima and interface
23 : * macros for assertion checking.
24 : *
25 : */
26 :
27 : #pragma once
28 :
29 : #include <lib/core/CHIPConfig.h>
30 : #include <lib/core/CHIPError.h>
31 : #include <lib/core/ErrorStr.h>
32 : #include <lib/support/ObjectDump.h>
33 : #include <lib/support/VerificationMacrosNoLogging.h>
34 : #include <lib/support/logging/TextOnlyLogging.h>
35 : #include <memory>
36 :
37 : /**
38 : * Base-level abnormal termination.
39 : *
40 : * Terminate the program immediately, without invoking destructors, atexit callbacks, etc.
41 : * Used to implement the default `chipDie()`.
42 : *
43 : * @note
44 : * This should never be invoked directly by code outside this file.
45 : */
46 : #if !defined(CHIP_CONFIG_ABORT)
47 : #define CHIP_CONFIG_ABORT() abort()
48 : #endif
49 :
50 : /**
51 : * @name chip-specific nlassert.h Overrides
52 : *
53 : * @{
54 : *
55 : */
56 :
57 : /**
58 : * @def NL_ASSERT_ABORT()
59 : *
60 : * @brief
61 : * This implements a chip-specific override for #NL_ASSERT_ABORT *
62 : * from nlassert.h.
63 : *
64 : */
65 : #if !defined(NL_ASSERT_ABORT)
66 : #define NL_ASSERT_ABORT() chipAbort()
67 : #endif
68 :
69 : /**
70 : * @def NL_ASSERT_LOG(aPrefix, aName, aCondition, aLabel, aFile, aLine, aMessage)
71 : *
72 : * @brief
73 : * This implements a chip-specific override for \c NL_ASSERT_LOG
74 : * from nlassert.h.
75 : *
76 : * @param[in] aPrefix A pointer to a NULL-terminated C string printed
77 : * at the beginning of the logged assertion
78 : * message. Typically this is and should be
79 : * \c NL_ASSERT_PREFIX_STRING.
80 : * @param[in] aName A pointer to a NULL-terminated C string printed
81 : * following @a aPrefix that indicates what
82 : * module, program, application or subsystem
83 : * the assertion occurred in Typically this
84 : * is and should be
85 : * \c NL_ASSERT_COMPONENT_STRING.
86 : * @param[in] aCondition A pointer to a NULL-terminated C string indicating
87 : * the expression that evaluated to false in
88 : * the assertion. Typically this is a
89 : * stringified version of the actual
90 : * assertion expression.
91 : * @param[in] aLabel An optional pointer to a NULL-terminated C string
92 : * indicating, for exception-style
93 : * assertions, the label that will be
94 : * branched to when the assertion expression
95 : * evaluates to false.
96 : * @param[in] aFile A pointer to a NULL-terminated C string indicating
97 : * the file in which the exception
98 : * occurred. Typically this is and should be
99 : * \_\_FILE\_\_ from the C preprocessor.
100 : * @param[in] aLine The line number in @a aFile on which the assertion
101 : * expression evaluated to false. Typically
102 : * this is and should be \_\_LINE\_\_ from the C
103 : * preprocessor.
104 : * @param[in] aMessage An optional pointer to a NULL-terminated C string
105 : * containing a caller-specified message
106 : * further describing the assertion failure.
107 : *
108 : */
109 : // clang-format off
110 : #if !defined(NL_ASSERT_LOG)
111 : #define NL_ASSERT_LOG(aPrefix, aName, aCondition, aLabel, aFile, aLine, aMessage) \
112 : do \
113 : { \
114 : ChipLogError(NotSpecified, \
115 : NL_ASSERT_LOG_FORMAT_DEFAULT, \
116 : aPrefix, \
117 : (((aName) == 0) || (*(aName) == '\0')) ? "" : aName, \
118 : (((aName) == 0) || (*(aName) == '\0')) ? "" : ": ", \
119 : aCondition, \
120 : (((aMessage) == 0) ? "" : aMessage), \
121 : (((aMessage) == 0) ? "" : ", "), \
122 : aFile, \
123 : aLine); \
124 : } while (0)
125 : #endif
126 : // clang-format on
127 :
128 : /**
129 : * @} chip-specific nlassert.h Overrides
130 : *
131 : */
132 :
133 : #include <nlassert.h>
134 :
135 : /**
136 : * @def ReturnErrorOnFailure(expr, ...)
137 : *
138 : * @brief
139 : * Returns the error code if the expression returns an error. For a CHIP_ERROR expression, this means any value other
140 : * than CHIP_NO_ERROR. For an integer expression, this means non-zero.
141 : *
142 : * Example usage:
143 : *
144 : * @code
145 : * ReturnErrorOnFailure(channel->SendMsg(msg), mState = Uninitialized);
146 : * @endcode
147 : *
148 : * @param[in] expr An expression to be tested.
149 : * @param[in] ... Statements to execute before returning. Optional.
150 : */
151 : #define ReturnErrorOnFailure(expr, ...) \
152 : do \
153 : { \
154 : auto __err = (expr); \
155 : if (!::chip::ChipError::IsSuccess(__err)) \
156 : { \
157 : __VA_ARGS__; \
158 : return __err; \
159 : } \
160 : } while (false)
161 :
162 : /**
163 : * @def ReturnErrorVariantOnFailure(expr)
164 : *
165 : * @brief
166 : * This is for use when the calling function returns a Variant type. It returns a CHIP_ERROR variant with the corresponding error
167 : * code if the expression returns an error.
168 : *
169 : * Example usage:
170 : *
171 : * @code
172 : * ReturnErrorVariantOnFailure(NextStep, ParseSigma1(tlvReader, parsedSigma1));
173 : * @endcode
174 : *
175 : * @param[in] variantType The Variant type that the calling function returns.
176 : * @param[in] expr An expression to be tested.
177 : * @param[in] ... Statements to execute before returning. Optional.
178 : */
179 : #define ReturnErrorVariantOnFailure(variantType, expr, ...) \
180 : do \
181 : { \
182 : auto __err = (expr); \
183 : if (!::chip::ChipError::IsSuccess(__err)) \
184 : { \
185 : __VA_ARGS__; \
186 : return variantType::Create<CHIP_ERROR>(__err); \
187 : } \
188 : } while (false)
189 :
190 : /**
191 : * @def ReturnLogErrorOnFailure(expr)
192 : *
193 : * @brief
194 : * Returns the error code if the expression returns something different
195 : * than CHIP_NO_ERROR.
196 : *
197 : * Example usage:
198 : *
199 : * @code
200 : * ReturnLogErrorOnFailure(channel->SendMsg(msg));
201 : * @endcode
202 : *
203 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
204 : */
205 : #define ReturnLogErrorOnFailure(expr) \
206 : do \
207 : { \
208 : CHIP_ERROR __err = (expr); \
209 : if (__err != CHIP_NO_ERROR) \
210 : { \
211 : ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(__err), __FILE__, __LINE__); \
212 : return __err; \
213 : } \
214 : } while (false)
215 :
216 : /**
217 : * @def SuccessOrLog(expr, MOD, MSG, ...)
218 : *
219 : * @brief
220 : * If expr returns something other than CHIP_NO_ERROR, log a message for the specified module
221 : * in the 'Error' category.
222 : *
223 : * Example usage:
224 : *
225 : * @code
226 : * SuccessOrLog(channel->SendMsg(msg), Module, "Failure message: %s", param);
227 : * @endcode
228 : *
229 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
230 : * @param[in] MOD The log module to use.
231 : * @param[in] MSG The log message format string.
232 : * @param[in] ... Optional arguments for the log message.
233 : */
234 : #define SuccessOrLog(expr, MOD, MSG, ...) \
235 : do \
236 : { \
237 : CHIP_ERROR __lerr = (expr); \
238 : if (!::chip::ChipError::IsSuccess(__lerr)) \
239 : { \
240 : ChipLogFailure(__lerr, MOD, MSG, ##__VA_ARGS__); \
241 : } \
242 : } while (false)
243 :
244 : /**
245 : * @def ReturnAndLogOnFailure(expr, MOD, MSG, ...)
246 : *
247 : * @brief
248 : * If expr returns something than CHIP_NO_ERROR, log a chip message for the specified module
249 : * in the 'Error' category and return.
250 : *
251 : * Example usage:
252 : *
253 : * @code
254 : * ReturnAndLogOnFailure(channel->SendMsg(msg), Module, "Failure message: %s", param);
255 : * @endcode
256 : *
257 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
258 : * @param[in] MOD The log module to use.
259 : * @param[in] MSG The log message format string.
260 : * @param[in] ... Optional arguments for the log message.
261 : */
262 : #define ReturnAndLogOnFailure(expr, MOD, MSG, ...) \
263 : do \
264 : { \
265 : CHIP_ERROR __err = (expr); \
266 : if (!::chip::ChipError::IsSuccess(__err)) \
267 : { \
268 : ChipLogFailure(__err, MOD, MSG, ##__VA_ARGS__); \
269 : return; \
270 : } \
271 : } while (false)
272 :
273 : /**
274 : * @def ReturnErrorAndLogOnFailure(expr, MOD, MSG, ...)
275 : *
276 : * @brief
277 : * If expr returns something than CHIP_NO_ERROR, log a chip message for the specified module
278 : * in the 'Error' category and return the error.
279 : *
280 : * Example usage:
281 : *
282 : * @code
283 : * ReturnErrorAndLogOnFailure(channel->SendMsg(msg), Module, "Failure message: %s", param);
284 : * @endcode
285 : *
286 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
287 : * @param[in] MOD The log module to use.
288 : * @param[in] MSG The log message format string.
289 : * @param[in] ... Optional arguments for the log message.
290 : */
291 : #define ReturnErrorAndLogOnFailure(expr, MOD, MSG, ...) \
292 : do \
293 : { \
294 : CHIP_ERROR __err = (expr); \
295 : if (!::chip::ChipError::IsSuccess(__err)) \
296 : { \
297 : ChipLogFailure(__err, MOD, MSG, ##__VA_ARGS__); \
298 : return __err; \
299 : } \
300 : } while (false)
301 :
302 : /**
303 : * @def ReturnValueAndLogOnFailure(expr, value, MOD, MSG, ...)
304 : *
305 : * @brief
306 : * If expr returns something other than CHIP_NO_ERROR, log a message for the specified module
307 : * in the 'Error' category and return the error.
308 : *
309 : * Example usage:
310 : *
311 : * @code
312 : * ReturnValueAndLogOnFailure(channel->SendMsg(msg), false, Module, "Failure message: %s", param);
313 : * @endcode
314 : *
315 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
316 : * @param[in] value A value to return if @a expr is an error.
317 : * @param[in] MOD The log module to use.
318 : * @param[in] MSG The log message format string.
319 : * @param[in] ... Optional arguments for the log message.
320 : */
321 : #define ReturnValueAndLogOnFailure(expr, value, MOD, MSG, ...) \
322 : do \
323 : { \
324 : CHIP_ERROR __err = (expr); \
325 : if (!::chip::ChipError::IsSuccess(__err)) \
326 : { \
327 : ChipLogFailure(__err, MOD, MSG, ##__VA_ARGS__); \
328 : return value; \
329 : } \
330 : } while (false)
331 :
332 : /**
333 : * @def ReturnOnFailure(expr, ...)
334 : *
335 : * @brief
336 : * Returns if the expression returns an error. For a CHIP_ERROR expression, this means any value other
337 : * than CHIP_NO_ERROR. For an integer expression, this means non-zero.
338 : *
339 : * Example usage:
340 : *
341 : * @code
342 : * ReturnOnFailure(channel->SendMsg(msg), mState = Uninitialized);
343 : * @endcode
344 : *
345 : * @param[in] expr An expression to be tested.
346 : * @param[in] ... Statements to execute before returning. Optional.
347 : */
348 : #define ReturnOnFailure(expr, ...) \
349 : do \
350 : { \
351 : auto __err = (expr); \
352 : if (!::chip::ChipError::IsSuccess(__err)) \
353 : { \
354 : __VA_ARGS__; \
355 : return; \
356 : } \
357 : } while (false)
358 :
359 : /**
360 : * @def ReturnValueOnFailure(expr, value, ...)
361 : *
362 : * @brief
363 : * Returns value if the expression returns an error. For a CHIP_ERROR expression, this means any value other
364 : * than CHIP_NO_ERROR. For an integer expression, this means non-zero.
365 : *
366 : * Example usage:
367 : *
368 : * @code
369 : * ReturnValueOnFailure(channel->SendMsg(msg), Status::Failure, mState = Uninitialized);
370 : * @endcode
371 : *
372 : * @param[in] expr An expression to be tested.
373 : * @param[in] value A value to return if @a expr is an error.
374 : * @param[in] ... Statements to execute before returning. Optional.
375 : */
376 : #define ReturnValueOnFailure(expr, value, ...) \
377 : do \
378 : { \
379 : auto __err = (expr); \
380 : if (!::chip::ChipError::IsSuccess(__err)) \
381 : { \
382 : __VA_ARGS__; \
383 : return value; \
384 : } \
385 : } while (false)
386 :
387 : /**
388 : * @def VerifyOrReturn(expr, ...)
389 : *
390 : * @brief
391 : * Returns from the void function if expression evaluates to false
392 : *
393 : * Example usage:
394 : *
395 : * @code
396 : * VerifyOrReturn(param != nullptr, LogError("param is nullptr"));
397 : * @endcode
398 : *
399 : * @param[in] expr A Boolean expression to be evaluated.
400 : * @param[in] ... Statements to execute before returning. Optional.
401 : */
402 : #define VerifyOrReturn(expr, ...) \
403 : do \
404 : { \
405 : if (!(expr)) \
406 : { \
407 : __VA_ARGS__; \
408 : return; \
409 : } \
410 : } while (false)
411 :
412 : /**
413 : * @def VerifyOrReturnError(expr, code, ...)
414 : *
415 : * @brief
416 : * Returns a specified error code if expression evaluates to false
417 : *
418 : * Example usage:
419 : *
420 : * @code
421 : * VerifyOrReturnError(param != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
422 : * @endcode
423 : *
424 : * @param[in] expr A Boolean expression to be evaluated.
425 : * @param[in] code A value to return if @a expr is false.
426 : * @param[in] ... Statements to execute before returning. Optional.
427 : */
428 : #define VerifyOrReturnError(expr, code, ...) VerifyOrReturnValue(expr, code, ##__VA_ARGS__)
429 :
430 : /**
431 : * @def VerifyOrReturnValue(expr, value, ...)
432 : *
433 : * @brief
434 : * Returns a specified value if expression evaluates to false
435 : *
436 : * Example usage:
437 : *
438 : * @code
439 : * VerifyOrReturnError(param != nullptr, Foo());
440 : * @endcode
441 : *
442 : * @param[in] expr A Boolean expression to be evaluated.
443 : * @param[in] value A value to return if @a expr is false.
444 : * @param[in] ... Statements to execute before returning. Optional.
445 : */
446 : #define VerifyOrReturnValue(expr, value, ...) \
447 : do \
448 : { \
449 : if (!(expr)) \
450 : { \
451 : __VA_ARGS__; \
452 : return (value); \
453 : } \
454 : } while (false)
455 :
456 : /**
457 : * @def VerifyOrReturnLogError(expr, code)
458 : *
459 : * @brief
460 : * Returns and print a specified error code if expression evaluates to false
461 : *
462 : * Example usage:
463 : *
464 : * @code
465 : * VerifyOrReturnLogError(param != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
466 : * @endcode
467 : *
468 : * @param[in] expr A Boolean expression to be evaluated.
469 : * @param[in] code A value to return if @a expr is false.
470 : */
471 : #if CHIP_CONFIG_ERROR_SOURCE
472 : #define VerifyOrReturnLogError(expr, code) \
473 : do \
474 : { \
475 : if (!(expr)) \
476 : { \
477 : auto __code = (code); \
478 : ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(__code), __FILE__, __LINE__); \
479 : return __code; \
480 : } \
481 : } while (false)
482 : #else // CHIP_CONFIG_ERROR_SOURCE
483 : #define VerifyOrReturnLogError(expr, code) \
484 : do \
485 : { \
486 : if (!(expr)) \
487 : { \
488 : auto __code = (code); \
489 : ChipLogError(NotSpecified, "%s:%d false: %" CHIP_ERROR_FORMAT, #expr, __LINE__, __code.Format()); \
490 : return __code; \
491 : } \
492 : } while (false)
493 : #endif // CHIP_CONFIG_ERROR_SOURCE
494 :
495 : /**
496 : * @def SuccessOrExit(error)
497 : *
498 : * @brief
499 : * This checks for the specified error, which is expected to
500 : * commonly be successful (CHIP_NO_ERROR), and branches to
501 : * the local label 'exit' if the status is unsuccessful.
502 : *
503 : * Example Usage:
504 : *
505 : * @code
506 : * CHIP_ERROR TryHard()
507 : * {
508 : * CHIP_ERROR err;
509 : *
510 : * err = TrySomething();
511 : * SuccessOrExit(err);
512 : *
513 : * err = TrySomethingElse();
514 : * SuccessOrExit(err);
515 : *
516 : * exit:
517 : * return err;
518 : * }
519 : * @endcode
520 : *
521 : * @param[in] error A ChipError object to be evaluated against success (CHIP_NO_ERROR).
522 : *
523 : */
524 : #define SuccessOrExit(error) nlEXPECT(::chip::ChipError::IsSuccess((error)), exit)
525 :
526 : /**
527 : * @def SuccessOrExitAction(error, anAction)
528 : *
529 : * @brief
530 : * This checks for the specified error, which is expected to
531 : * commonly be successful (CHIP_NO_ERROR), and both executes
532 : * @a anAction and branches to the local label 'exit' if the
533 : * status is unsuccessful.
534 : *
535 : * @param[in] error A ChipError object to be evaluated against success (CHIP_NO_ERROR).
536 : */
537 : #define SuccessOrExitAction(error, action) nlEXPECT_ACTION(::chip::ChipError::IsSuccess((error)), exit, action)
538 :
539 : /**
540 : * @def VerifyOrExit(aCondition, anAction)
541 : *
542 : * @brief
543 : * This checks for the specified condition, which is expected to
544 : * commonly be true, and both executes @a anAction and branches to
545 : * the local label 'exit' if the condition is false.
546 : *
547 : * Example Usage:
548 : *
549 : * @code
550 : * CHIP_ERROR MakeBuffer(const uint8_t *& buf)
551 : * {
552 : * CHIP_ERROR err = CHIP_NO_ERROR;
553 : *
554 : * buf = (uint8_t *)malloc(1024);
555 : * VerifyOrExit(buf != NULL, err = CHIP_ERROR_NO_MEMORY);
556 : *
557 : * memset(buf, 0, 1024);
558 : *
559 : * exit:
560 : * return err;
561 : * }
562 : * @endcode
563 : *
564 : * @param[in] aCondition A Boolean expression to be evaluated.
565 : * @param[in] anAction An expression or block to execute when the
566 : * assertion fails.
567 : *
568 : */
569 : #define VerifyOrExit(aCondition, anAction) nlEXPECT_ACTION(aCondition, exit, anAction)
570 :
571 : /**
572 : * @def ExitNow(...)
573 : *
574 : * @brief
575 : * This unconditionally executes @a ... and branches to the local
576 : * label 'exit'.
577 : *
578 : * @note The use of this interface implies neither success nor
579 : * failure for the overall exit status of the enclosing function
580 : * body.
581 : *
582 : * Example Usage:
583 : *
584 : * @code
585 : * CHIP_ERROR ReadAll(Reader& reader)
586 : * {
587 : * CHIP_ERROR err;
588 : *
589 : * while (true)
590 : * {
591 : * err = reader.ReadNext();
592 : * if (err == CHIP_ERROR_AT_END)
593 : * ExitNow(err = CHIP_NO_ERROR);
594 : * SuccessOrExit(err);
595 : * DoSomething();
596 : * }
597 : *
598 : * exit:
599 : * return err;
600 : * }
601 : * @endcode
602 : *
603 : * @param[in] ... Statements to execute. Optional.
604 : */
605 : // clang-format off
606 : #define ExitNow(...) \
607 : do { \
608 : __VA_ARGS__; \
609 : goto exit; \
610 : } while (0)
611 : // clang-format on
612 :
613 : /**
614 : * @brief
615 : * This is invoked when a #VerifyOrDie or #VerifyOrDieWithMsg
616 : * assertion expression evaluates to false.
617 : *
618 : * Developers may override and customize this by defining #chipDie
619 : * before CodeUtils.h is included by the preprocessor.
620 : *
621 : * Example Usage:
622 : *
623 : * @code
624 : * chipDie();
625 : * @endcode
626 : *
627 : */
628 : #ifndef chipAbort
629 : extern "C" void chipAbort(void) __attribute((noreturn));
630 :
631 0 : inline void chipAbort(void)
632 : {
633 : while (true)
634 : {
635 : // NL_ASSERT_ABORT is redefined to be chipAbort, so not useful here.
636 0 : CHIP_CONFIG_ABORT();
637 : }
638 : }
639 : #endif // chipAbort
640 : #ifndef chipDie
641 : extern "C" void chipDie(void) __attribute((noreturn));
642 :
643 0 : inline void chipDie(void)
644 : {
645 0 : ChipLogError(NotSpecified, "chipDie chipDie chipDie");
646 0 : chipAbort();
647 : }
648 : #endif // chipDie
649 :
650 : /**
651 : * @def VerifyOrDie(aCondition)
652 : *
653 : * @brief
654 : * This checks for the specified condition, which is expected to
655 : * commonly be true and forces an immediate abort if the condition
656 : * is false.
657 : *
658 : * Example Usage:
659 : *
660 : * @code
661 : * void FreeBuffer(const uint8_t *buf)
662 : * {
663 : * VerifyOrDie(buf != NULL);
664 : * free(buf);
665 : * }
666 : * @endcode
667 : *
668 : * @param[in] aCondition A Boolean expression to be evaluated.
669 : *
670 : * @sa #VerifyOrDieWithMsg
671 : * @sa #chipDie
672 : *
673 : */
674 : #if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE && CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE_NO_COND
675 : #define VerifyOrDie(aCondition) \
676 : nlABORT_ACTION(aCondition, ChipLogError(Support, "VerifyOrDie failure at %s:%d", __FILE__, __LINE__))
677 : #elif CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
678 : #define VerifyOrDie(aCondition) \
679 : nlABORT_ACTION(aCondition, ChipLogError(Support, "VerifyOrDie failure at %s:%d: %s", __FILE__, __LINE__, #aCondition))
680 : #else // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
681 : #define VerifyOrDie(aCondition) VerifyOrDieWithoutLogging(aCondition)
682 : #endif // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
683 :
684 : /**
685 : * @def SuccessOrDie(error)
686 : *
687 : * @brief
688 : * This checks for the specified error, which is expected to
689 : * commonly be successful (CHIP_NO_ERROR), forces an immediate abort if the status
690 : * is unsuccessful.
691 : *
692 : *
693 : * Example Usage:
694 : *
695 : * @code
696 : * uint8_t* AllocateBuffer()
697 : * {
698 : * uint8_t* buffer;
699 : * SuccessOrDie(ChipAllocateBuffer(buffer));
700 : * return buffer;
701 : * }
702 : * @endcode
703 : *
704 : * @param[in] error A ChipError object to be evaluated against success (CHIP_NO_ERROR).
705 : *
706 : */
707 : #if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE && CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE_NO_COND
708 : #define SuccessOrDie(error) \
709 : do \
710 : { \
711 : auto __err = (error); \
712 : nlABORT_ACTION(::chip::ChipError::IsSuccess(__err), \
713 : ChipLogError(Support, "SuccessOrDie failure %s at %s:%d", ErrorStr(__err), __FILE__, __LINE__)); \
714 : } while (false)
715 : #elif CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
716 : #define SuccessOrDie(error) \
717 : do \
718 : { \
719 : auto __err = (error); \
720 : nlABORT_ACTION( \
721 : ::chip::ChipError::IsSuccess(__err), \
722 : ChipLogError(Support, "SuccessOrDie failure %s at %s:%d: %s", ErrorStr(__err), __FILE__, __LINE__, #error)); \
723 : } while (false)
724 : #else // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
725 : #define SuccessOrDie(error) VerifyOrDieWithoutLogging(::chip::ChipError::IsSuccess((error)))
726 : #endif // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
727 :
728 : /**
729 : * @def VerifyOrDieWithObject(aCondition, aObject)
730 : *
731 : * Like VerifyOrDie(), but calls DumpObjectToLog()
732 : * on the provided object on failure before aborting
733 : * if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE is enabled.
734 : */
735 : #if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
736 : #define VerifyOrDieWithObject(aCondition, aObject) \
737 : nlABORT_ACTION(aCondition, ::chip::DumpObjectToLog(aObject); \
738 : ChipLogError(Support, "VerifyOrDie failure at %s:%d: %s", __FILE__, __LINE__, #aCondition))
739 : #else // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
740 : #define VerifyOrDieWithObject(aCondition, aObject) VerifyOrDieWithoutLogging(aCondition)
741 : #endif // CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
742 :
743 : /**
744 : * @def VerifyOrDieWithMsg(aCondition, aModule, aMessage, ...)
745 : *
746 : * @brief
747 : * This checks for the specified condition, which is expected to
748 : * commonly be true and both prints @a aMessage and forces an
749 : * immediate abort if the condition is false.
750 : *
751 : * Example Usage:
752 : *
753 : * @code
754 : * void FreeBuffer(const uint8_t *buf)
755 : * {
756 : * VerifyOrDieWithMsg(buf != NULL, MemoryManagement, "Invalid pointer passed to FreeBuffer");
757 : * free(buf);
758 : * }
759 : * @endcode
760 : *
761 : * @param[in] aCondition A Boolean expression to be evaluated.
762 : * @param[in] aModule A chip LogModule short-hand mnemonic identifing
763 : * the logical section of code that is a
764 : * source the logged message.
765 : * @param[in] aMessage A pointer to a NULL-terminated C string with
766 : * C Standard Library-style format specifiers
767 : * containing the log message to be formatted
768 : * and logged.
769 : * @param[in] ... A variadic argument list whose elements should
770 : * correspond to the format specifiers in @a
771 : * aMessage.
772 : *
773 : * @sa #VerifyOrDie
774 : * @sa #chipDie
775 : *
776 : */
777 : #define VerifyOrDieWithMsg(aCondition, aModule, aMessage, ...) \
778 : nlABORT_ACTION(aCondition, ChipLogError(aModule, aMessage, ##__VA_ARGS__))
779 :
780 : /**
781 : * @def LogErrorOnFailure(expr)
782 : *
783 : * @brief
784 : * Logs a message if the expression returns something different than CHIP_NO_ERROR.
785 : *
786 : * Example usage:
787 : *
788 : * @code
789 : * ReturnLogErrorOnFailure(channel->SendMsg(msg));
790 : * @endcode
791 : *
792 : * @param[in] expr A scalar expression to be evaluated against CHIP_NO_ERROR.
793 : */
794 : #define LogErrorOnFailure(expr) \
795 : do \
796 : { \
797 : CHIP_ERROR __err = (expr); \
798 : if (__err != CHIP_NO_ERROR) \
799 : { \
800 : ChipLogError(NotSpecified, "%s at %s:%d", ErrorStr(__err), __FILE__, __LINE__); \
801 : } \
802 : } while (false)
803 :
804 : /**
805 : * @def VerifyOrDo(expr, ...)
806 : *
807 : * @brief
808 : * do something if expression evaluates to false
809 : *
810 : * Example usage:
811 : *
812 : * @code
813 : * VerifyOrDo(param != nullptr, LogError("param is nullptr"));
814 : * @endcode
815 : *
816 : * @param[in] expr A Boolean expression to be evaluated.
817 : * @param[in] ... Statements to execute.
818 : */
819 : #define VerifyOrDo(expr, ...) \
820 : do \
821 : { \
822 : if (!(expr)) \
823 : { \
824 : __VA_ARGS__; \
825 : } \
826 : } while (false)
827 :
828 : #if (__cplusplus >= 201103L)
829 :
830 : #ifndef __FINAL
831 : #define __FINAL final
832 : #endif
833 :
834 : #ifndef __OVERRIDE
835 : #define __OVERRIDE override
836 : #endif
837 :
838 : #ifndef __CONSTEXPR
839 : #define __CONSTEXPR constexpr
840 : #endif
841 :
842 : #else
843 :
844 : #ifndef __FINAL
845 : #define __FINAL
846 : #endif
847 :
848 : #ifndef __OVERRIDE
849 : #define __OVERRIDE
850 : #endif
851 :
852 : #ifndef __CONSTEXPR
853 : #define __CONSTEXPR constexpr
854 : #endif
855 :
856 : #endif // (__cplusplus >= 201103L)
857 :
858 : #if ((__cplusplus >= 201703L) || (defined(__GNUC__) && (__GNUC__ >= 7)) || (defined(__clang__)) && (__clang_major__ >= 4))
859 : #define CHECK_RETURN_VALUE [[nodiscard]]
860 : #elif defined(__GNUC__) && (__GNUC__ >= 4)
861 : #define CHECK_RETURN_VALUE __attribute__((warn_unused_result))
862 : #elif defined(_MSC_VER) && (_MSC_VER >= 1700)
863 : #define CHECK_RETURN_VALUE _Check_return_
864 : #else
865 : #define CHECK_RETURN_VALUE
866 : #endif
867 :
868 : #if defined(__clang__)
869 : #define FALLTHROUGH [[clang::fallthrough]]
870 : #elif defined(__GNUC__)
871 : #define FALLTHROUGH __attribute__((fallthrough))
872 : #else
873 : #define FALLTHROUGH (void) 0
874 : #endif
875 :
876 : /**
877 : * @def MATTER_ARRAY_SIZE(aArray)
878 : *
879 : * @brief
880 : * Returns the size of an array in number of elements.
881 : *
882 : * Example Usage:
883 : *
884 : * @code
885 : * int numbers[10];
886 : * SortNumbers(numbers, MATTER_ARRAY_SIZE(numbers));
887 : * @endcode
888 : *
889 : * @return The size of an array in number of elements.
890 : *
891 : * @note Clever template-based solutions seem to fail when MATTER_ARRAY_SIZE is used
892 : * with a variable-length array argument, so we just do the C-compatible
893 : * thing in C++ as well.
894 : */
895 : #ifndef MATTER_ARRAY_SIZE
896 : #define MATTER_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
897 : #endif
898 :
899 : /**
900 : * @brief Ensures that if `str` is NULL, a non-null `default_str_value` is provided
901 : *
902 : * @param str - null-terminated string pointer or nullptr
903 : * @param default_str_value - replacement value if `str` is nullptr
904 : * @return `str` if not null, otherwise `default_str_value`
905 : */
906 5024 : inline const char * DefaultStringWhenNull(const char * str, const char * default_str_value)
907 : {
908 5024 : return (str != nullptr) ? str : default_str_value;
909 : }
910 :
911 : /**
912 : * @brief Ensure that a string for a %s specifier is shown as "(null)" if null
913 : *
914 : * @param str - null-terminated string pointer or nullptr
915 : * @return `str` if not null, otherwise literal "(null)"
916 : */
917 5024 : inline const char * StringOrNullMarker(const char * str)
918 : {
919 5024 : return DefaultStringWhenNull(str, "(null)");
920 : }
921 :
922 : namespace chip {
923 :
924 : /**
925 : * Utility for checking, at compile time if the array is constexpr, whether an
926 : * array is sorted. Can be used for static_asserts.
927 : */
928 : template <typename T>
929 : constexpr bool ArrayIsSorted(const T * aArray, size_t aLength)
930 : {
931 : if (aLength == 0 || aLength == 1)
932 : {
933 : return true;
934 : }
935 :
936 : if (aArray[0] > aArray[1])
937 : {
938 : return false;
939 : }
940 :
941 : return ArrayIsSorted(aArray + 1, aLength - 1);
942 : }
943 :
944 : template <typename T, size_t N>
945 : constexpr bool ArrayIsSorted(const T (&aArray)[N])
946 : {
947 : return ArrayIsSorted(aArray, N);
948 : }
949 :
950 : /**
951 : * @def ScopeExit(fn)
952 : *
953 : * @brief
954 : * RAII to automatically release resources on scope exit (instead of depending on goto exit)
955 : * See https://en.cppreference.com/w/cpp/experimental/scope_exit.html
956 : * Use with ReturnOnFailure, ReturnLogErrorOnFailure, ReturnAndLogOnFailure and other such methods
957 : * to return an error code result from a method call without needing to store in a local var
958 : *
959 : * Example usage:
960 : *
961 : * @code
962 : * Resource * resource = GetResource();
963 : * auto resourceHolder = ScopeExit([&] { resource->Release() });
964 : * // If the call below fails, logs, returns the error code, and calls resourceHolder
965 : * ReturnAndLogOnFailure(ProcessAndSaveResource(resource), Module, "Failure message: %s", param);
966 : * resourceHolder->release(); // Cancel clean-up at end of successful method
967 : * @endcode
968 : */
969 : template <class F>
970 : __attribute__((always_inline)) inline auto ScopeExit(F && fn)
971 : {
972 112 : auto deleter = [f = std::forward<F>(fn)](void *) mutable { f(); };
973 110 : return std::unique_ptr<void, decltype(deleter)>(reinterpret_cast<void *>(1), std::move(deleter));
974 : }
975 :
976 : } // namespace chip
|