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

bdwgc / bdwgc / 2053

22 Feb 2026 05:48AM UTC coverage: 77.233% (+3.3%) from 73.894%
2053

push

travis-ci

ivmai
Fix missing GC_ATTR_NONNULL for API functions
(fix of commit d012f92c)

* include/gc/gc.h (GC_exclude_static_roots, GC_add_roots): Add
`GC_ATTR_NONNULL` attribute for the appropriate arguments.
* include/gc/gc.h [GC_WIN32_THREADS && (!GC_PTHREADS || GC_BUILD
|| GC_WINDOWS_H_INCLUDED) && (!GC_NO_THREAD_DECLS || GC_BUILD)
&& !GC_DONT_INCL_WINDOWS_H] (GC_CreateThread, GC_beginthreadex):
Likewise.
* include/gc/gc_inline.h (GC_generic_malloc_many): Likewise.
* include/gc/gc_mark.h (GC_mark_and_push, GC_new_proc,
GC_new_proc_inner): Likewise.
* include/gc/gc_pthread_redirects.h [GC_PTHREADS
&& !GC_PTHREAD_REDIRECTS_ONLY] (GC_pthread_create): Likewise.
* include/private/gc_priv.h (NONNULL_PROC_NOT_ZERO): New macro.
* mallocx.c (GC_generic_malloc_many): Add assertion that `result` is
non-null.
* mark_rts.c (GC_add_roots_inner): Add assertion that `b` is non-null.
* mark_rts.c (GC_exclude_static_roots_inner): Add assertion that
`start` is non-null.
* misc.c (GC_new_proc_inner): Add assertion that `proc` is non-zero.
* pthread_support.c (GC_wrap_pthread_create): Add assertion that
`start_routine` is non-zero.

3 of 3 new or added lines in 2 files covered. (100.0%)

128 existing lines in 9 files now uncovered.

6873 of 8899 relevant lines covered (77.23%)

17354920.53 hits per line

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

37.82
/ptr_chck.c
1
/*
2
 * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
3
 *
4
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
5
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
6
 *
7
 * Permission is hereby granted to use or copy this program
8
 * for any purpose, provided the above notices are retained on all copies.
9
 * Permission to modify the code and to distribute modified code is granted,
10
 * provided the above notices are retained, and a notice that the code was
11
 * modified is included with the above copyright notice.
12
 */
13

14
#include "private/gc_pmark.h"
15

16
/*
17
 * These are checking routines calls to which could be inserted by
18
 * a preprocessor to validate C pointer arithmetic.
19
 */
20

21
STATIC void GC_CALLBACK
22
GC_default_same_obj_print_proc(void *p, void *q)
×
23
{
24
  ABORT_ARG2("GC_same_obj test failed",
×
25
             ": %p and %p are not in the same object", p, q);
26
}
27

28
GC_same_obj_print_proc_t GC_same_obj_print_proc
29
    = GC_default_same_obj_print_proc;
30

31
GC_API void *GC_CALL
32
GC_same_obj(void *p, void *q)
63✔
33
{
34
  hdr *hhdr;
35
  ptr_t base, limit;
36
  size_t sz;
37

38
  if (UNLIKELY(!GC_is_initialized))
63✔
39
    GC_init();
×
40
  hhdr = HDR(p);
63✔
41
  if (NULL == hhdr) {
63✔
42
    if (divHBLKSZ(ADDR(p)) != divHBLKSZ(ADDR(q)) && HDR(q) != NULL) {
×
43
      GC_same_obj_print_proc((ptr_t)p, (ptr_t)q);
×
44
    }
45
    return p;
63✔
46
  }
47
  /*
48
   * If it is a pointer to the middle of a large object, move it to
49
   * the beginning.
50
   */
51
  if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
63✔
52
    struct hblk *h = GC_find_starting_hblk(HBLKPTR(p), &hhdr);
×
53

54
    limit = (ptr_t)h + hhdr->hb_sz;
×
55
    if (ADDR_GE((ptr_t)p, limit) || ADDR_GE((ptr_t)q, limit)
×
56
        || ADDR_LT((ptr_t)q, (ptr_t)h)) {
×
57
      GC_same_obj_print_proc((ptr_t)p, (ptr_t)q);
×
58
    }
59
    return p;
×
60
  }
61
  sz = hhdr->hb_sz;
63✔
62
  if (sz > MAXOBJBYTES) {
63✔
63
    base = (ptr_t)HBLKPTR(p);
×
64
    limit = base + sz;
×
65
    if (ADDR_GE((ptr_t)p, limit)) {
×
66
      GC_same_obj_print_proc((ptr_t)p, (ptr_t)q);
×
67
      return p;
×
68
    }
69
  } else {
70
    size_t offset;
71

72
    if (HBLKPTR(p) != HBLKPTR(q)) {
63✔
73
      /*
74
       * Without this check, we might miss an error if `q` points to
75
       * the first object on a page, and points just before the page.
76
       */
77
      GC_same_obj_print_proc((ptr_t)p, (ptr_t)q);
×
78
      return p;
×
79
    }
80
    offset = HBLKDISPL(p) % sz;
63✔
81
    base = (ptr_t)p - offset;
63✔
82
    limit = base + sz;
63✔
83
  }
84
  /*
85
   * [`base`,`limit`) delimits the object containing `p`, if any.
86
   * If `p` is not inside a valid object, then either `q` is also
87
   * outside any valid object, or it is outside [`base`,`limit`).
88
   */
89
  if (!ADDR_INSIDE((ptr_t)q, base, limit)) {
63✔
90
    GC_same_obj_print_proc((ptr_t)p, (ptr_t)q);
×
91
  }
92
  return p;
63✔
93
}
94

95
STATIC void GC_CALLBACK
96
GC_default_is_valid_displacement_print_proc(void *p)
×
97
{
98
  ABORT_ARG1("GC_is_valid_displacement test failed", ": %p not valid", p);
×
99
}
100

101
GC_valid_ptr_print_proc_t GC_is_valid_displacement_print_proc
102
    = GC_default_is_valid_displacement_print_proc;
103

104
GC_API void *GC_CALL
105
GC_is_valid_displacement(void *p)
189✔
106
{
107
  hdr *hhdr;
108
  size_t offset;
109
  struct hblk *h;
110
  size_t sz;
111

112
  if (UNLIKELY(!GC_is_initialized))
189✔
113
    GC_init();
×
114
  if (NULL == p)
189✔
115
    return NULL;
189✔
116
  hhdr = HDR(p);
189✔
117
  if (NULL == hhdr)
189✔
118
    return p;
63✔
119
  h = HBLKPTR(p);
126✔
120
#ifndef NO_ALL_INTERIOR_POINTERS
121
  if (GC_all_interior_pointers) {
126✔
122
    h = GC_find_starting_hblk(h, &hhdr);
126✔
123
  } else
124
#endif
125
    /* else */ if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
×
126
      GC_is_valid_displacement_print_proc((ptr_t)p);
×
127
      return p;
×
128
    }
129
  sz = hhdr->hb_sz;
126✔
130
  offset = HBLKDISPL(p) % sz;
126✔
131
  if ((sz > MAXOBJBYTES && ADDR_GE((ptr_t)p, (ptr_t)h + sz))
126✔
132
      || !GC_valid_offsets[offset]
126✔
133
      || (ADDR_LT((ptr_t)(h + 1), (ptr_t)p + sz - offset)
126✔
134
          && !IS_FORWARDING_ADDR_OR_NIL(HDR(h + 1)))) {
×
135
    GC_is_valid_displacement_print_proc((ptr_t)p);
×
136
  }
137
  return p;
126✔
138
}
139

140
STATIC void GC_CALLBACK
141
GC_default_is_visible_print_proc(void *p)
×
142
{
143
  ABORT_ARG1("GC_is_visible test failed", ": %p not GC-visible", p);
×
144
}
145

146
GC_valid_ptr_print_proc_t GC_is_visible_print_proc
147
    = GC_default_is_visible_print_proc;
148

149
/* Could `p` be a stack address? */
150
STATIC GC_bool
151
GC_on_stack(ptr_t p)
×
152
{
153
  return HOTTER_THAN(p, GC_stackbottom) && !HOTTER_THAN(p, GC_approx_sp());
×
154
}
155

156
/* Is the address `p` in one of the registered static root sections? */
157
STATIC GC_bool
158
GC_is_static_root(ptr_t p)
×
159
{
160
  static size_t last_static_root_set = MAX_ROOT_SETS;
161
  size_t i;
162

163
#ifdef CPPCHECK
164
  if (n_root_sets > MAX_ROOT_SETS)
165
    ABORT("Bad n_root_sets");
166
#endif
167
  if (last_static_root_set < n_root_sets
×
168
      && ADDR_INSIDE(p, GC_static_roots[last_static_root_set].r_start,
×
169
                     GC_static_roots[last_static_root_set].r_end))
170
    return TRUE;
×
171
  for (i = 0; i < n_root_sets; i++) {
×
172
    if (ADDR_INSIDE(p, GC_static_roots[i].r_start, GC_static_roots[i].r_end)) {
×
173
      last_static_root_set = i;
×
174
      return TRUE;
×
175
    }
176
  }
177
  return FALSE;
×
178
}
179

180
GC_API void *GC_CALL
181
GC_is_visible(void *p)
126✔
182
{
183
  const hdr *hhdr;
184

185
  if (UNLIKELY(!GC_is_initialized))
126✔
UNCOV
186
    GC_init();
×
187
  if ((ADDR(p) & (ALIGNMENT - 1)) != 0)
126✔
188
    goto fail;
63✔
189
  hhdr = HDR(p);
63✔
190
#ifdef THREADS
191
  if (GC_has_running_threads()) {
63✔
192
    if (hhdr != NULL && NULL == GC_base(p))
63✔
193
      goto fail;
×
194
    /* May be inside a thread's stack.  We cannot do much. */
195
    return p;
63✔
196
  }
197
#endif
198
  if (NULL == hhdr) {
×
199
    /* Check stack first. */
200
    if (GC_on_stack((ptr_t)p))
×
201
      return p;
×
202

203
    if (GC_is_static_root((ptr_t)p)) {
×
204
      return p;
×
205
    }
206
    /* Else do it again correctly. */
207
#if defined(ANY_MSWIN) || defined(DYNAMIC_LOADING)
208
    if (!GC_no_dls) {
×
209
#  ifdef GC_ASSERTIONS
210
      /* Just to set `GC_lock_holder`. */
211
      LOCK();
×
212
#  endif
213
      GC_register_dynamic_libraries();
×
214
#  ifdef GC_ASSERTIONS
215
      UNLOCK();
×
216
#  endif
217
      if (GC_is_static_root((ptr_t)p))
×
218
        return p;
×
219
    }
220
#endif
221
  } else {
222
    /* `p` points to the heap. */
223
    word descr;
224
    /* TODO: Should `GC_base` be manually inlined? */
225
    ptr_t base = (ptr_t)GC_base(p);
×
226

227
    if (NULL == base)
×
228
      goto fail;
×
229
    if (HBLKPTR(base) != HBLKPTR(p))
×
230
      hhdr = HDR(base);
×
231
    descr = hhdr->hb_descr;
×
232
  retry:
×
233
    switch (descr & GC_DS_TAGS) {
×
234
    case GC_DS_LENGTH:
×
235
      if ((word)((ptr_t)p - base) >= descr)
×
236
        goto fail;
×
237
      break;
×
238
    case GC_DS_BITMAP:
×
239
      if ((word)p - (word)base >= PTRS_TO_BYTES(BITMAP_BITS))
×
240
        goto fail;
×
241
#if ALIGNMENT != CPP_PTRSZ / 8
242
      if ((ADDR(p) & (sizeof(ptr_t) - 1)) != 0)
243
        goto fail;
244
#endif
245
      if (!(((word)1 << (CPP_WORDSZ - 1 - (word)((ptr_t)p - base))) & descr))
×
246
        goto fail;
×
247
      break;
×
248
    case GC_DS_PROC:
×
249
      /* We could try to decipher this partially.  For now we just punt. */
250
      break;
×
251
    case GC_DS_PER_OBJECT:
×
252
      if (!(descr & SIGNB)) {
×
253
        descr = *(word *)((ptr_t)base + (descr & ~(word)GC_DS_TAGS));
×
254
      } else {
255
        ptr_t type_descr = *(ptr_t *)base;
×
256

257
        if (UNLIKELY(NULL == type_descr)) {
×
258
          /* See the comment in `GC_mark_from`. */
259
          goto fail;
×
260
        }
261
        descr = *(word *)(type_descr
×
262
                          - ((GC_signed_word)descr
×
263
                             + (GC_INDIR_PER_OBJ_BIAS - GC_DS_PER_OBJECT)));
264
      }
265
      goto retry;
×
266
    }
267
    return p;
×
268
  }
269
fail:
63✔
270
  GC_is_visible_print_proc((ptr_t)p);
63✔
271
  return p;
63✔
272
}
273

274
GC_API void *GC_CALL
275
GC_pre_incr(void **p, ptrdiff_t how_much)
×
276
{
277
  void *initial = *p;
×
278
  void *result = GC_same_obj((ptr_t)initial + how_much, initial);
×
279

280
  if (!GC_all_interior_pointers) {
×
281
    (void)GC_is_valid_displacement(result);
×
282
  }
283
  *p = result;
×
284
  return result; /*< updated pointer */
×
285
}
286

287
GC_API void *GC_CALL
288
GC_post_incr(void **p, ptrdiff_t how_much)
×
289
{
290
  void *initial = *p;
×
291
  void *result = GC_same_obj((ptr_t)initial + how_much, initial);
×
292

293
  if (!GC_all_interior_pointers) {
×
294
    (void)GC_is_valid_displacement(result);
×
295
  }
296
  *p = result;
×
297
  return initial; /*< original `*p` */
×
298
}
299

300
GC_API void GC_CALL
301
GC_set_same_obj_print_proc(GC_same_obj_print_proc_t fn)
3✔
302
{
303
  GC_ASSERT(NONNULL_ARG_NOT_NULL(fn));
3✔
304
  GC_same_obj_print_proc = fn;
3✔
305
}
3✔
306

307
GC_API GC_same_obj_print_proc_t GC_CALL
308
GC_get_same_obj_print_proc(void)
3✔
309
{
310
  return GC_same_obj_print_proc;
3✔
311
}
312

313
GC_API void GC_CALL
314
GC_set_is_valid_displacement_print_proc(GC_valid_ptr_print_proc_t fn)
3✔
315
{
316
  GC_ASSERT(NONNULL_ARG_NOT_NULL(fn));
3✔
317
  GC_is_valid_displacement_print_proc = fn;
3✔
318
}
3✔
319

320
GC_API GC_valid_ptr_print_proc_t GC_CALL
321
GC_get_is_valid_displacement_print_proc(void)
3✔
322
{
323
  return GC_is_valid_displacement_print_proc;
3✔
324
}
325

326
GC_API void GC_CALL
327
GC_set_is_visible_print_proc(GC_valid_ptr_print_proc_t fn)
3✔
328
{
329
  GC_ASSERT(NONNULL_ARG_NOT_NULL(fn));
3✔
330
  GC_is_visible_print_proc = fn;
3✔
331
}
3✔
332

333
GC_API GC_valid_ptr_print_proc_t GC_CALL
334
GC_get_is_visible_print_proc(void)
3✔
335
{
336
  return GC_is_visible_print_proc;
3✔
337
}
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

© 2026 Coveralls, Inc