Coverage Report

Created: 2024-02-29 06:05

/src/strongswan/src/libstrongswan/utils/utils/strerror.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2012-2014 Tobias Brunner
3
 *
4
 * Copyright (C) secunet Security Networks AG
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License as published by the
8
 * Free Software Foundation; either version 2 of the License, or (at your
9
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
10
 *
11
 * This program is distributed in the hope that it will be useful, but
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14
 * for more details.
15
 */
16
17
#include <stdlib.h>
18
#include <string.h>
19
20
#include <library.h>
21
#include <threading/thread_value.h>
22
#include <threading/spinlock.h>
23
24
#include "strerror.h"
25
26
/**
27
 * The size of the thread-specific error buffer
28
 */
29
0
#define STRERROR_BUF_LEN 256
30
31
/**
32
 * Thread specific strerror buffer, as char*
33
 */
34
static thread_value_t *strerror_buf;
35
36
#ifndef HAVE_STRERROR_R
37
/**
38
 * Lock to access strerror() safely
39
 */
40
static spinlock_t *strerror_lock;
41
#endif /* HAVE_STRERROR_R */
42
43
/**
44
 * Retrieve the error buffer assigned to the current thread (or create it)
45
 */
46
static inline char *get_strerror_buf()
47
0
{
48
0
  char *buf;
49
0
  bool old = FALSE;
50
51
0
  if (!strerror_buf)
52
0
  {
53
0
    return NULL;
54
0
  }
55
56
0
  buf = strerror_buf->get(strerror_buf);
57
0
  if (!buf)
58
0
  {
59
0
    if (lib->leak_detective)
60
0
    {
61
0
      old = lib->leak_detective->set_state(lib->leak_detective, FALSE);
62
0
    }
63
0
    buf = malloc(STRERROR_BUF_LEN);
64
0
    strerror_buf->set(strerror_buf, buf);
65
0
    if (lib->leak_detective)
66
0
    {
67
0
      lib->leak_detective->set_state(lib->leak_detective, old);
68
0
    }
69
0
  }
70
0
  return buf;
71
0
}
72
73
/**
74
 * Use real strerror() below
75
 */
76
#undef strerror
77
78
/*
79
 * Described in header.
80
 */
81
const char *strerror_safe(int errnum)
82
0
{
83
0
  char *buf, *msg;
84
85
0
  buf = get_strerror_buf();
86
0
  if (!buf)
87
0
  {
88
    /* library not initialized? fallback */
89
0
    return strerror(errnum);
90
0
  }
91
0
#ifdef HAVE_STRERROR_R
92
# ifdef STRERROR_R_CHAR_P
93
  /* char* version which may or may not return the original buffer */
94
  msg = strerror_r(errnum, buf, STRERROR_BUF_LEN);
95
# else
96
  /* int version returns 0 on success */
97
0
  msg = strerror_r(errnum, buf, STRERROR_BUF_LEN) ? "Unknown error" : buf;
98
0
# endif
99
#else /* HAVE_STRERROR_R */
100
  /* use a lock to ensure calling strerror(3) is thread-safe */
101
  strerror_lock->lock(strerror_lock);
102
  msg = strncpy(buf, strerror(errnum), STRERROR_BUF_LEN);
103
  strerror_lock->unlock(strerror_lock);
104
  buf[STRERROR_BUF_LEN - 1] = '\0';
105
#endif /* HAVE_STRERROR_R */
106
0
  return msg;
107
0
}
108
109
/**
110
 * free() with disabled leak detective
111
 */
112
static void free_no_ld(void *buf)
113
0
{
114
0
  bool old = FALSE;
115
116
0
  if (lib->leak_detective)
117
0
  {
118
0
    old = lib->leak_detective->set_state(lib->leak_detective, FALSE);
119
0
  }
120
0
  free(buf);
121
0
  if (lib->leak_detective)
122
0
  {
123
0
    lib->leak_detective->set_state(lib->leak_detective, old);
124
0
  }
125
0
}
126
127
/**
128
 * See header
129
 */
130
void strerror_init()
131
3.92k
{
132
3.92k
  strerror_buf = thread_value_create(free_no_ld);
133
#ifndef HAVE_STRERROR_R
134
  strerror_lock = spinlock_create();
135
#endif
136
3.92k
}
137
138
/**
139
 * See header
140
 */
141
void strerror_deinit()
142
3.92k
{
143
3.92k
  strerror_buf->destroy(strerror_buf);
144
3.92k
  strerror_buf = NULL;
145
#ifndef HAVE_STRERROR_R
146
  strerror_lock->destroy(strerror_lock);
147
#endif
148
3.92k
}