• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

aremmell / libsir / 903

26 Sep 2023 08:37AM UTC coverage: 95.11% (+0.07%) from 95.039%
903

Pull #301

gitlab-ci

aremmell
test actually verifies platform errors
Pull Request #301: Add sir_geterrorinfo to obtain extended information about an error

148 of 148 new or added lines in 5 files covered. (100.0%)

3715 of 3906 relevant lines covered (95.11%)

525783.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.05
/src/sirerrors.c
1
/*
2
 * sirerrors.c
3
 *
4
 * Author:    Ryan M. Lederman <lederman@gmail.com>
5
 * Copyright: Copyright (c) 2018-2023
6
 * Version:   2.2.4
7
 * License:   The MIT License (MIT)
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
10
 * this software and associated documentation files (the "Software"), to deal in
11
 * the Software without restriction, including without limitation the rights to
12
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
13
 * the Software, and to permit persons to whom the Software is furnished to do so,
14
 * subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included in all
17
 * copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
21
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
22
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
23
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 */
26
#include "sir/errors.h"
27
#include "sir/helpers.h"
28

29
#if defined(__WIN__)
30
# if defined(__EMBARCADEROC__) && defined(_WIN64)
31
#  pragma comment(lib, "shlwapi.a")
32
# else
33
#  pragma comment(lib, "shlwapi.lib")
34
# endif
35
#endif
36

37
#if defined(__MACOS__) || defined(__BSD__) || \
38
    (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L && !defined(_GNU_SOURCE)))
39
# define __HAVE_XSI_STRERROR_R__
40
# if defined(__GLIBC__) && GLIBC_VERSION < 21300
41
#  define __HAVE_XSI_STRERROR_R_ERRNO__
42
# endif
43
#elif defined(_GNU_SOURCE) && defined(__GLIBC__)
44
# define __HAVE_GNU_STRERROR_R__
45
#elif defined(__HAVE_STDC_SECURE_OR_EXT1__)
46
# define __HAVE_STRERROR_S__
47
#endif
48

49
/** Per-thread error data */
50
static _sir_thread_local sir_thread_err _sir_te = {
51
    _SIR_E_NOERROR, 0, {0}, {SIR_UNKNOWN, SIR_UNKNOWN, 0}
52
};
53

54
#define _SIR_E_PLATFORM_ERRORMSG "Platform error"
55
#define _SIR_E_PLATFORM_ERRORFORMAT _SIR_E_PLATFORM_ERRORMSG " code %d: %s"
56

57
static const struct {
58
    uint32_t e;
59
    const char* msg;
60
} sir_errors[] = {
61
    {_SIR_E_NOERROR,   "The operation completed successfully"},
62
    {_SIR_E_NOTREADY,  "libsir has not been initialized"},
63
    {_SIR_E_ALREADY,   "libsir is already initialized"},
64
    {_SIR_E_DUPITEM,   "Item already managed by libsir"},
65
    {_SIR_E_NOITEM,    "Item not managed by libsir"},
66
    {_SIR_E_NOROOM,    "Maximum number of items already stored"},
67
    {_SIR_E_OPTIONS,   "Option flags are invalid"},
68
    {_SIR_E_LEVELS,    "Level flags are invalid"},
69
    {_SIR_E_TEXTSTYLE, "Text style is invalid"},
70
    {_SIR_E_STRING,    "Invalid string argument"},
71
    {_SIR_E_NULLPTR,   "NULL pointer argument"},
72
    {_SIR_E_INVALID,   "Invalid argument"},
73
    {_SIR_E_NODEST,    "No destinations registered for level"},
74
    {_SIR_E_UNAVAIL,   "Feature is disabled or unavailable"},
75
    {_SIR_E_INTERNAL,  "An internal error has occurred"},
76
    {_SIR_E_COLORMODE, "Color mode is invalid"},
77
    {_SIR_E_TEXTATTR,  "Text attributes are invalid"},
78
    {_SIR_E_TEXTCOLOR, "Text color is invalid for mode"},
79
    {_SIR_E_PLUGINBAD, "Plugin module is malformed"},
80
    {_SIR_E_PLUGINDAT, "Data produced by plugin is invalid"},
81
    {_SIR_E_PLUGINVER, "Plugin interface version unsupported"},
82
    {_SIR_E_PLUGINERR, "Plugin reported failure"},
83
    {_SIR_E_PLATFORM,  _SIR_E_PLATFORM_ERRORFORMAT},
84
    {_SIR_E_UNKNOWN,   "Unknown error"},
85
};
86

87
bool __sir_seterror(uint32_t err, const char* func, const char* file, uint32_t line) {
2,676,040✔
88
    if (_sir_validerror(err)) {
2,676,040✔
89
        _sir_te.lasterror = err;
2,676,042✔
90
        _sir_te.loc.func  = func;
2,676,042✔
91
        _sir_te.loc.file  = file;
2,676,042✔
92
        _sir_te.loc.line  = line;
2,676,042✔
93

94
        if (_SIR_E_PLATFORM != err) {
2,676,042✔
95
            _sir_te.os_code = 0;
2,667,831✔
96
            _sir_resetstr(_sir_te.os_msg);
2,667,831✔
97
        }
98
    }
99
#if defined(DEBUG) && defined(SIR_SELFLOG)
100
    if (_SIR_E_NOERROR != err) {
2,595,389✔
101
        char errmsg[SIR_MAXERROR] = {0};
175,657✔
102
        _sir_geterror(errmsg);
175,657✔
103
        __sir_selflog(func, file, line, "%s", errmsg);
175,661✔
104
    }
105
#endif
106
    return false;
2,676,221✔
107
}
108

109
void __sir_setoserror(int code, const char* msg, const char* func, const char* file, uint32_t line) {
8,224✔
110
    _sir_te.os_code = code;
8,224✔
111
    _sir_resetstr(_sir_te.os_msg);
8,224✔
112

113
    if (_sir_validstrnofail(msg))
8,224✔
114
        _sir_strncpy(_sir_te.os_msg, SIR_MAXERROR, msg, SIR_MAXERROR);
8,224✔
115

116
    (void)__sir_seterror(_SIR_E_PLATFORM, func, file, line);
8,224✔
117
}
8,224✔
118

119
bool __sir_handleerr(int code, const char* func, const char* file, uint32_t line) {
40,800✔
120
    if (SIR_E_NOERROR != code) {
40,800✔
121
        char message[SIR_MAXERROR] = {0};
8,224✔
122
        int finderr                = 0;
8,200✔
123
        errno                      = SIR_E_NOERROR;
8,224✔
124

125
#if defined(__HAVE_XSI_STRERROR_R__)
126
        _sir_selflog("using XSI strerror_r");
127
        finderr = strerror_r(code, message, SIR_MAXERROR);
128
# if defined(__HAVE_XSI_STRERROR_R_ERRNO__)
129
        _sir_selflog("using XSI strerror_r for glibc < 2.13");
130
        if (finderr == -1)
131
            finderr = errno;
132
# endif
133
#elif defined(__HAVE_GNU_STRERROR_R__)
134
        _sir_selflog("using GNU strerror_r");
8,216✔
135
        const char* tmp = strerror_r(code, message, SIR_MAXERROR);
8,224✔
136
        if (tmp != message)
8,224✔
137
            _sir_strncpy(message, SIR_MAXERROR, tmp, SIR_MAXERROR);
8,222✔
138
#elif defined(__HAVE_STRERROR_S__)
139
        _sir_selflog("using strerror_s");
140
        finderr = (int)strerror_s(message, SIR_MAXERROR, code);
141
#else
142
        _sir_selflog("using strerror");
143
        const char* tmp = strerror(code);
144
        _sir_strncpy(message, SIR_MAXERROR, tmp, strnlen(tmp, SIR_MAXERROR));
145
#endif
146
        if (0 == finderr) { //-V547
8,200✔
147
            __sir_setoserror(code, message, func, file, line);
8,224✔
148
#if defined(__HAVE_XSI_STRERROR_R__) || defined(__HAVE_STRERROR_S__)
149
        } else {
150
            /* Per my reading of the man pages, GNU strerror_r and normal strerror "can't fail";
151
             * they simply return a string such as "Unknown nnn error" if unable to look up an
152
             * error code.
153
             */
154
# if defined(__HAVE_XSI_STRERROR_R__)
155
            _sir_selflog("strerror_r failed! error: %d", finderr);
156
# elif defined(__HAVE_STRERROR_S__)
157
            _sir_selflog("strerror_s failed! error: %d", finderr);
158
# endif
159
#endif
160
        }
161
    }
162
    return false;
40,800✔
163
}
164

165
#if defined(__WIN__)
166
void _sir_invalidparameter(const wchar_t* expr, const wchar_t* func, const wchar_t* file,
167
    unsigned int line, uintptr_t reserved) {
168
    _sir_selflog("invalid parameter handler: expression: '%S' in %S (%S:%u)",
169
        expr, func, file, line);
170
    SIR_UNUSED(reserved);
171
}
172

173
bool __sir_handlewin32err(DWORD code, const char* func, const char* file, uint32_t line) {
174
    char* errbuf = NULL;
175
    DWORD flags  = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
176
                   FORMAT_MESSAGE_IGNORE_INSERTS  | FORMAT_MESSAGE_MAX_WIDTH_MASK;
177

178
    DWORD fmtmsg = FormatMessageA(flags, NULL, code, 0, (LPSTR)&errbuf, SIR_MAXERROR, NULL);
179
    if (0 < fmtmsg && _sir_validstrnofail(errbuf)) {
180
        if (errbuf[fmtmsg - 1] == '\n' || errbuf[fmtmsg - 1] == ' ')
181
            errbuf[fmtmsg - 1] = '\0';
182
        __sir_setoserror((int)code, errbuf, func, file, line);
183
    } else {
184
        _sir_selflog("FormatMessage failed! error: %lu", GetLastError());
185
        SIR_ASSERT(false);
186
    }
187

188
    if (errbuf) {
189
        HLOCAL local_free = LocalFree((HLOCAL)errbuf);
190
        SIR_ASSERT_UNUSED(NULL == local_free, local_free);
191
        errbuf = NULL;
192
    }
193
    return false;
194
}
195
#endif /* !__WIN__ */
196

197
uint32_t _sir_geterror(char message[SIR_MAXERROR]) {
430,364✔
198
    _sir_resetstr(message);
430,364✔
199

200
    static const size_t low  = 0;
201
    static const size_t high = _sir_countof(sir_errors) - 1;
202

203
    uint32_t retval = _SIR_E_UNKNOWN;
387,904✔
204

205
    _SIR_DECLARE_BIN_SEARCH(low, high);
387,904✔
206
    _SIR_BEGIN_BIN_SEARCH()
207

208
    if (sir_errors[_mid].e == _sir_te.lasterror) {
1,721,671✔
209
        char* heap_msg = NULL;
430,303✔
210

211
        if (_SIR_E_PLATFORM == sir_errors[_mid].e) {
430,303✔
212
            heap_msg = calloc(SIR_MAXERROR, sizeof(char));
10,280✔
213
            if (_sir_validptrnofail(heap_msg)) {
10,280✔
214
                _sir_snprintf_trunc(heap_msg, SIR_MAXERROR, _SIR_E_PLATFORM_ERRORFORMAT, _sir_te.os_code,
10,246✔
215
                    (_sir_validstrnofail(_sir_te.os_msg) ? _sir_te.os_msg : SIR_UNKNOWN));
216
            }
217
        }
218

219
        _sir_snprintf_trunc(message, SIR_MAXERROR, SIR_ERRORFORMAT, _sir_te.loc.func, //-V576
472,752✔
220
            _sir_te.loc.file, _sir_te.loc.line, (_sir_validstrnofail(heap_msg)
221
                ? heap_msg : (_sir_validstrnofail(sir_errors[_mid].msg)
222
                ? sir_errors[_mid].msg : SIR_UNKNOWN)));
223

224
        _sir_safefree(&heap_msg);
430,323✔
225

226
        retval = sir_errors[_mid].e;
387,966✔
227
        break;
387,966✔
228
    }
229

230
    _SIR_ITERATE_BIN_SEARCH((sir_errors[_mid].e < _sir_te.lasterror ? 1 : -1));
1,291,368✔
231
    _SIR_END_BIN_SEARCH();
232

233
    return retval;
430,495✔
234
}
235

236
void _sir_geterrorinfo(sir_errorinfo* err) {
530✔
237
    if (!_sir_validptr(err))
530✔
238
        return;
×
239

240
    memset(err, 0, sizeof(sir_errorinfo));
458✔
241

242
    err->func = _sir_te.loc.func;
530✔
243
    err->file = _sir_te.loc.file;
530✔
244
    err->line = _sir_te.loc.line;
530✔
245

246
    err->os_code = _sir_te.os_code;
530✔
247
    (void)_sir_strncpy(err->os_msg, SIR_MAXERROR, (_sir_validstrnofail(_sir_te.os_msg)
599✔
248
        ? _sir_te.os_msg : SIR_UNKNOWN), SIR_MAXERROR);
249

250
    err->code = _sir_geterrcode(SIR_E_UNKNOWN);
530✔
251

252
    static const size_t low  = 0;
253
    static const size_t high = _sir_countof(sir_errors) - 1;
254

255
    _SIR_DECLARE_BIN_SEARCH(low, high);
458✔
256
    _SIR_BEGIN_BIN_SEARCH()
257

258
    if (sir_errors[_mid].e == _sir_te.lasterror) {
2,077✔
259
        err->code = _sir_geterrcode(sir_errors[_mid].e);
530✔
260
        if (_SIR_E_PLATFORM == sir_errors[_mid].e)
530✔
261
            (void)_sir_strncpy(err->msg, SIR_MAXERROR, _SIR_E_PLATFORM_ERRORMSG, SIR_MAXERROR);
21✔
262
        else
263
            (void)_sir_strncpy(err->msg, SIR_MAXERROR, sir_errors[_mid].msg, SIR_MAXERROR);
509✔
264
        break;
458✔
265
    }
266

267
    _SIR_ITERATE_BIN_SEARCH((sir_errors[_mid].e < _sir_te.lasterror ? 1 : -1));
1,547✔
268
    _SIR_END_BIN_SEARCH();
269
}
270

271
void _sir_reset_tls_error(void) {
1,576✔
272
    _sir_te.lasterror = _SIR_E_NOERROR;
1,576✔
273
    _sir_te.os_code  = 0;
1,576✔
274
    _sir_resetstr(_sir_te.os_msg);
1,576✔
275
    _sir_te.loc.func = SIR_UNKNOWN;
1,576✔
276
    _sir_te.loc.file = SIR_UNKNOWN;
1,576✔
277
    _sir_te.loc.line = 0U;
1,576✔
278
}
1,576✔
279

280
#if defined(SIR_SELFLOG)
281
PRINTF_FORMAT_ATTR(4, 5)
282
void __sir_selflog(const char* func, const char* file, uint32_t line,
857,064✔
283
    PRINTF_FORMAT const char* format, ...) {
284
    bool success = true;
812,865✔
285
    char prefix[256];
286

287
    int write1 = snprintf(prefix, 256, "%s (%s:%"PRIu32"): ", func, file, line);
812,865✔
288
    _sir_eqland(success, write1 > 0);
812,865✔
289

290
    if (write1 > 0) {
857,064✔
291
        va_list args;
292
        va_list args2;
293
        va_start(args, format);
857,381✔
294
        va_copy(args2, args);
857,381✔
295

296
        int write2 = vsnprintf(NULL, 0, format, args);
813,148✔
297
        va_end(args);
857,381✔
298
        _sir_eqland(success, write2 > 0);
857,381✔
299

300
        if (write2 > 0) {
857,381✔
301
            char* buf = (char*)malloc(write2 + 1);
857,331✔
302
            _sir_eqland(success, NULL != buf);
857,331✔
303

304
            if (buf) {
857,331✔
305
                write2 = vsnprintf(buf, write2 + 1, format, args2);
813,070✔
306
                va_end(args2);
857,294✔
307
                _sir_eqland(success, write2 > 0);
857,294✔
308

309
                bool error = false;
813,070✔
310
                bool warn  = false;
813,070✔
311
                if (write2 > 0) {
857,294✔
312
# if !defined(__WIN__)
313
                    if (NULL != strcasestr(buf, "error") ||
857,346✔
314
                        NULL != strcasestr(buf, "assert")) {
585,239✔
315
# else /* __WIN__ */
316
                    if (NULL != StrStrIA(buf, "error") ||
317
                        NULL != StrStrIA(buf, "assert")) {
318
# endif
319
                        error = true;
391,242✔
320
# if !defined(__WIN__)
321
                    } else if (NULL != strcasestr(buf, "warn")) {
465,962✔
322
# else /* __WIN__ */
323
                    } else if (NULL != StrStrIA(buf, "warn")) {
324
# endif
325
                        warn = true;
51✔
326
                    }
327

328
                    write2 = fprintf(stderr, (error ? BRED("%s%s") "\n" :
901,423✔
329
                        (warn ? YELLOW("%s%s") "\n" : "%s%s\n")), prefix, buf);
330
                    _sir_eqland(success, write2 > 0);
857,726✔
331
                }
332

333
                _sir_safefree(&buf);
857,674✔
334
            }
335
        }
336
    }
337

338
    SIR_ASSERT_UNUSED(success, success);
857,458✔
339
}
857,458✔
340
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc