Coverage Report

Created: 2025-10-13 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/jq/src/jv_alloc.c
Line
Count
Source
1
#include <assert.h>
2
#include <stdio.h>
3
#include <stdlib.h>
4
#include <string.h>
5
#include "jv.h"
6
7
struct nomem_handler {
8
    jv_nomem_handler_f handler;
9
    void *data;
10
};
11
12
#if !defined(HAVE_PTHREAD_KEY_CREATE) || \
13
    !defined(HAVE_PTHREAD_ONCE) || \
14
    !defined(HAVE_ATEXIT)
15
16
/* Try thread-local storage? */
17
18
#ifdef _MSC_VER
19
/* Visual C++: yes */
20
static __declspec(thread) struct nomem_handler nomem_handler;
21
#define USE_TLS
22
#else
23
#ifdef HAVE___THREAD
24
/* GCC and friends: yes */
25
static __thread struct nomem_handler nomem_handler;
26
#define USE_TLS
27
#endif /* HAVE___THREAD */
28
#endif /* _MSC_VER */
29
30
#endif /* !HAVE_PTHREAD_KEY_CREATE */
31
32
#ifdef USE_TLS
33
void jv_nomem_handler(jv_nomem_handler_f handler, void *data) {
34
  nomem_handler.handler = handler;
35
}
36
37
static void memory_exhausted(void) {
38
  if (nomem_handler.handler)
39
    nomem_handler.handler(nomem_handler.data); // Maybe handler() will longjmp() to safety
40
  // Or not
41
  fprintf(stderr, "jq: error: cannot allocate memory\n");
42
  abort();
43
}
44
#else /* USE_TLS */
45
46
#ifdef HAVE_PTHREAD_KEY_CREATE
47
#include <pthread.h>
48
49
static pthread_key_t nomem_handler_key;
50
static pthread_once_t mem_once = PTHREAD_ONCE_INIT;
51
52
/* tsd_fini is called on application exit */
53
/* it clears the nomem_handler allocated in the main thread */
54
0
static void tsd_fini(void) {
55
0
  struct nomem_handler *nomem_handler;
56
0
  nomem_handler = pthread_getspecific(nomem_handler_key);
57
0
  if (nomem_handler) {
58
0
    (void) pthread_setspecific(nomem_handler_key, NULL);
59
0
    free(nomem_handler);
60
0
  }
61
0
}
62
63
/* The tsd_fini_thread is a destructor set by calling */
64
/* pthread_key_create(&nomem_handler_key, tsd_fini_thread) */
65
/* It is called when thread ends */
66
0
static void tsd_fini_thread(void *nomem_handler) {
67
0
  free(nomem_handler);
68
0
}
69
70
0
static void tsd_init(void) {
71
0
  if (pthread_key_create(&nomem_handler_key, tsd_fini_thread) != 0) {
72
0
    fprintf(stderr, "jq: error: cannot create thread specific key");
73
0
    abort();
74
0
  }
75
0
  if (atexit(tsd_fini) != 0) {
76
0
    fprintf(stderr, "jq: error: cannot set an exit handler");
77
0
    abort();
78
0
  }
79
0
}
80
81
static void tsd_init_nomem_handler(void)
82
0
{
83
0
  if (pthread_getspecific(nomem_handler_key) == NULL) {
84
0
    struct nomem_handler *nomem_handler = calloc(1, sizeof(struct nomem_handler));
85
0
    if (pthread_setspecific(nomem_handler_key, nomem_handler) != 0) {
86
0
      fprintf(stderr, "jq: error: cannot set thread specific data");
87
0
      abort();
88
0
    }
89
0
  }
90
0
}
91
92
0
void jv_nomem_handler(jv_nomem_handler_f handler, void *data) {
93
0
  pthread_once(&mem_once, tsd_init); // cannot fail
94
0
  tsd_init_nomem_handler();
95
96
0
  struct nomem_handler *nomem_handler;
97
98
0
  nomem_handler = pthread_getspecific(nomem_handler_key);
99
0
  if (nomem_handler == NULL) {
100
0
    handler(data);
101
0
    fprintf(stderr, "jq: error: cannot allocate memory\n");
102
0
    abort();
103
0
  }
104
0
  nomem_handler->handler = handler;
105
0
  nomem_handler->data = data;
106
0
}
107
108
0
static void memory_exhausted(void) {
109
0
  struct nomem_handler *nomem_handler;
110
111
0
  pthread_once(&mem_once, tsd_init);
112
0
  tsd_init_nomem_handler();
113
114
0
  nomem_handler = pthread_getspecific(nomem_handler_key);
115
0
  if (nomem_handler && nomem_handler->handler)
116
0
    nomem_handler->handler(nomem_handler->data); // Maybe handler() will longjmp() to safety
117
  // Or not
118
0
  fprintf(stderr, "jq: error: cannot allocate memory\n");
119
0
  abort();
120
0
}
121
122
#else
123
124
/* No thread-local storage of any kind that we know how to handle */
125
126
static struct nomem_handler nomem_handler;
127
void jv_nomem_handler(jv_nomem_handler_f handler, void *data) {
128
  nomem_handler.handler = handler;
129
  nomem_handler.data = data;
130
}
131
132
static void memory_exhausted(void) {
133
  fprintf(stderr, "jq: error: cannot allocate memory\n");
134
  abort();
135
}
136
137
#endif /* HAVE_PTHREAD_KEY_CREATE */
138
#endif /* USE_TLS */
139
140
141
5.36M
void* jv_mem_alloc(size_t sz) {
142
5.36M
  void* p = malloc(sz);
143
5.36M
  if (!p) {
144
0
    memory_exhausted();
145
0
  }
146
5.36M
  return p;
147
5.36M
}
148
149
0
void* jv_mem_alloc_unguarded(size_t sz) {
150
0
  return malloc(sz);
151
0
}
152
153
0
void* jv_mem_calloc(size_t nemb, size_t sz) {
154
0
  assert(nemb > 0 && sz > 0);
155
0
  void* p = calloc(nemb, sz);
156
0
  if (!p) {
157
0
    memory_exhausted();
158
0
  }
159
0
  return p;
160
0
}
161
162
0
void* jv_mem_calloc_unguarded(size_t nemb, size_t sz) {
163
0
  assert(nemb > 0 && sz > 0);
164
0
  return calloc(nemb, sz);
165
0
}
166
167
0
char* jv_mem_strdup(const char *s) {
168
0
  char *p = strdup(s);
169
0
  if (!p) {
170
0
    memory_exhausted();
171
0
  }
172
0
  return p;
173
0
}
174
175
0
char* jv_mem_strdup_unguarded(const char *s) {
176
0
  return strdup(s);
177
0
}
178
179
5.36M
void jv_mem_free(void* p) {
180
5.36M
  free(p);
181
5.36M
}
182
183
7.27k
void* jv_mem_realloc(void* p, size_t sz) {
184
7.27k
  p = realloc(p, sz);
185
7.27k
  if (!p) {
186
0
    memory_exhausted();
187
0
  }
188
7.27k
  return p;
189
7.27k
}