xref: /linux/lib/zstd/common/error_private.h (revision e61f33273ca755b3e2ebee4520a76097199dc7a8)
1 /* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
2 /*
3  * Copyright (c) Meta Platforms, Inc. and affiliates.
4  * All rights reserved.
5  *
6  * This source code is licensed under both the BSD-style license (found in the
7  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
8  * in the COPYING file in the root directory of this source tree).
9  * You may select, at your option, one of the above-listed licenses.
10  */
11 
12 /* Note : this module is expected to remain private, do not expose it */
13 
14 #ifndef ERROR_H_MODULE
15 #define ERROR_H_MODULE
16 
17 /* ****************************************
18 *  Dependencies
19 ******************************************/
20 #include <linux/zstd_errors.h>  /* enum list */
21 #include "compiler.h"
22 #include "debug.h"
23 #include "zstd_deps.h"       /* size_t */
24 
25 /* ****************************************
26 *  Compiler-specific
27 ******************************************/
28 #define ERR_STATIC static __attribute__((unused))
29 
30 
31 /*-****************************************
32 *  Customization (error_public.h)
33 ******************************************/
34 typedef ZSTD_ErrorCode ERR_enum;
35 #define PREFIX(name) ZSTD_error_##name
36 
37 
38 /*-****************************************
39 *  Error codes handling
40 ******************************************/
41 #undef ERROR   /* already defined on Visual Studio */
42 #define ERROR(name) ZSTD_ERROR(name)
43 #define ZSTD_ERROR(name) ((size_t)-PREFIX(name))
44 
ERR_isError(size_t code)45 ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); }
46 
ERR_getErrorCode(size_t code)47 ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); }
48 
49 /* check and forward error code */
50 #define CHECK_V_F(e, f)     \
51     size_t const e = f;     \
52     do {                    \
53         if (ERR_isError(e)) \
54             return e;       \
55     } while (0)
56 #define CHECK_F(f)   do { CHECK_V_F(_var_err__, f); } while (0)
57 
58 
59 /*-****************************************
60 *  Error Strings
61 ******************************************/
62 
63 const char* ERR_getErrorString(ERR_enum code);   /* error_private.c */
64 
ERR_getErrorName(size_t code)65 ERR_STATIC const char* ERR_getErrorName(size_t code)
66 {
67     return ERR_getErrorString(ERR_getErrorCode(code));
68 }
69 
70 /*
71  * Ignore: this is an internal helper.
72  *
73  * This is a helper function to help force C99-correctness during compilation.
74  * Under strict compilation modes, variadic macro arguments can't be empty.
75  * However, variadic function arguments can be. Using a function therefore lets
76  * us statically check that at least one (string) argument was passed,
77  * independent of the compilation flags.
78  */
79 static INLINE_KEYWORD UNUSED_ATTR
_force_has_format_string(const char * format,...)80 void _force_has_format_string(const char *format, ...) {
81   (void)format;
82 }
83 
84 /*
85  * Ignore: this is an internal helper.
86  *
87  * We want to force this function invocation to be syntactically correct, but
88  * we don't want to force runtime evaluation of its arguments.
89  */
90 #define _FORCE_HAS_FORMAT_STRING(...)              \
91     do {                                           \
92         if (0) {                                   \
93             _force_has_format_string(__VA_ARGS__); \
94         }                                          \
95     } while (0)
96 
97 #define ERR_QUOTE(str) #str
98 
99 /*
100  * Return the specified error if the condition evaluates to true.
101  *
102  * In debug modes, prints additional information.
103  * In order to do that (particularly, printing the conditional that failed),
104  * this can't just wrap RETURN_ERROR().
105  */
106 #define RETURN_ERROR_IF(cond, err, ...)                                        \
107     do {                                                                       \
108         if (cond) {                                                            \
109             RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s",          \
110                   __FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \
111             _FORCE_HAS_FORMAT_STRING(__VA_ARGS__);                             \
112             RAWLOG(3, ": " __VA_ARGS__);                                       \
113             RAWLOG(3, "\n");                                                   \
114             return ERROR(err);                                                 \
115         }                                                                      \
116     } while (0)
117 
118 /*
119  * Unconditionally return the specified error.
120  *
121  * In debug modes, prints additional information.
122  */
123 #define RETURN_ERROR(err, ...)                                               \
124     do {                                                                     \
125         RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \
126               __FILE__, __LINE__, ERR_QUOTE(ERROR(err)));                    \
127         _FORCE_HAS_FORMAT_STRING(__VA_ARGS__);                               \
128         RAWLOG(3, ": " __VA_ARGS__);                                         \
129         RAWLOG(3, "\n");                                                     \
130         return ERROR(err);                                                   \
131     } while(0)
132 
133 /*
134  * If the provided expression evaluates to an error code, returns that error code.
135  *
136  * In debug modes, prints additional information.
137  */
138 #define FORWARD_IF_ERROR(err, ...)                                                 \
139     do {                                                                           \
140         size_t const err_code = (err);                                             \
141         if (ERR_isError(err_code)) {                                               \
142             RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s",                 \
143                   __FILE__, __LINE__, ERR_QUOTE(err), ERR_getErrorName(err_code)); \
144             _FORCE_HAS_FORMAT_STRING(__VA_ARGS__);                                 \
145             RAWLOG(3, ": " __VA_ARGS__);                                           \
146             RAWLOG(3, "\n");                                                       \
147             return err_code;                                                       \
148         }                                                                          \
149     } while(0)
150 
151 #endif /* ERROR_H_MODULE */
152