| /* Adapted from malloc-1.c, but wrapping the pointers in a struct. */ |
| |
| /* { dg-require-effective-target alloca } */ |
| |
| #include <stdlib.h> |
| |
| extern int foo (void); |
| extern int bar (void); |
| extern void could_free (void *); |
| extern void cant_free (const void *); /* since it's a const void *. */ |
| |
| typedef struct boxed_ptr { void *value; } boxed_ptr; |
| |
| boxed_ptr |
| boxed_malloc (size_t sz) |
| { |
| boxed_ptr result; |
| result.value = malloc (sz); |
| return result; |
| } |
| |
| boxed_ptr |
| boxed_free (boxed_ptr ptr) |
| { |
| free (ptr.value); |
| } |
| |
| const boxed_ptr boxed_null = {NULL}; |
| |
| void test_1 (void) |
| { |
| boxed_ptr ptr; |
| ptr.value = malloc (1024); |
| free (ptr.value); |
| free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */ |
| } |
| |
| void test_2 (boxed_ptr ptr) |
| { |
| free (ptr.value); |
| free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */ |
| } |
| |
| boxed_ptr |
| test_3 (void) |
| { |
| boxed_ptr ptr; |
| ptr.value = malloc (sizeof (int)); |
| *(int *)ptr.value = 42; /* { dg-warning "dereference of possibly-NULL 'ptr.value' \\\[CWE-690\\\]" } */ |
| return ptr; |
| } |
| |
| boxed_ptr |
| test_4 (void) |
| { |
| boxed_ptr ptr; |
| ptr.value = malloc (sizeof (int)); |
| int *iptr = (int *)ptr.value; |
| if (iptr) |
| *iptr = 42; |
| else |
| *iptr = 43; /* { dg-warning "dereference of NULL 'iptr' \\\[CWE-476\\\]" } */ |
| return ptr; |
| } |
| |
| int test_5 (boxed_ptr ptr) |
| { |
| free (ptr.value); |
| return *(int *)ptr.value; /* { dg-warning "use after 'free' of 'ptr.value'" } */ |
| } |
| |
| void test_6 (void *ptr) |
| { |
| boxed_ptr q; |
| q.value = ptr; |
| free (ptr); |
| free (q.value); /* { dg-warning "double-'free' of 'ptr'" } */ |
| } |
| |
| void test_6a (boxed_ptr ptr) |
| { |
| boxed_ptr q; |
| q = ptr; |
| boxed_free (ptr); |
| free (q.value); /* { dg-warning "double-'free' of 'ptr.value'" } */ |
| } |
| |
| void test_7 (void) |
| { |
| boxed_ptr ptr = boxed_malloc(4096); |
| if (!ptr.value) |
| return; |
| __builtin_memset(ptr.value, 0, 4096); |
| boxed_free(ptr); |
| } |
| |
| boxed_ptr test_8 (void) |
| { |
| boxed_ptr ptr = boxed_malloc(4096); |
| if (!ptr.value) |
| return boxed_null; |
| __builtin_memset(ptr.value, 0, 4096); |
| return ptr; |
| } |
| |
| void test_9 (void) |
| { |
| boxed_ptr ptr = boxed_malloc (1024); |
| |
| int i; |
| for (i = 0; i < 1024; i++) |
| free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */ |
| } |
| |
| void test_10 (void) |
| { |
| boxed_ptr ptr = boxed_malloc (1024); |
| |
| int i; |
| for (i = 0; i < 1024; i++) |
| foo (); |
| |
| free (ptr.value); |
| free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */ |
| } |
| |
| void test_11 (void) |
| { |
| boxed_ptr ptr = boxed_malloc (1024); |
| |
| while (foo ()) |
| bar (); |
| |
| free (ptr.value); |
| free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */ |
| } |
| |
| void test_12 (void) |
| { |
| boxed_ptr ptr = boxed_malloc (1024); |
| |
| while (1) |
| { |
| free (ptr.value); |
| free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */ |
| } |
| } |
| |
| void test_13 (void) |
| { |
| boxed_ptr p = boxed_malloc (1024); |
| boxed_ptr q = boxed_malloc (1024); |
| |
| foo (); |
| if (!q.value) |
| { |
| boxed_free (q); |
| return; /* { dg-warning "leak of 'p.value'" } */ |
| } |
| bar (); |
| boxed_free (q); |
| boxed_free (p); |
| } |
| |
| void test_14 (void) |
| { |
| boxed_ptr p, q; |
| p = boxed_malloc (1024); |
| if (!p.value) |
| return; |
| |
| q = boxed_malloc (1024); |
| if (!q.value) |
| { |
| boxed_free (p); |
| boxed_free (q); |
| /* oops: missing "return". */ |
| } |
| bar (); |
| boxed_free (q); /* Although this looks like a double-'free' of q, |
| it's known to be NULL for the case where free is |
| called twice on it. */ |
| free (p.value); /* { dg-warning "double-'free' of 'p.value'" } */ |
| } |
| |
| void test_15 (void) |
| { |
| boxed_ptr p, q; |
| p.value = NULL; |
| q.value = NULL; |
| |
| p = boxed_malloc (1024); |
| if (!p.value) |
| goto fail; |
| |
| foo (); |
| |
| q = boxed_malloc (1024); |
| if (!q.value) |
| goto fail; |
| |
| bar (); |
| |
| fail: |
| boxed_free (q); |
| boxed_free (p); |
| } |
| |
| void test_16 (void) |
| { |
| boxed_ptr p, q; /* { dg-message "region created on stack here" } */ |
| |
| p = boxed_malloc (1024); |
| if (!p.value) |
| goto fail; |
| |
| foo (); |
| |
| q = boxed_malloc (1024); |
| if (!q.value) |
| goto fail; |
| |
| bar (); |
| |
| fail: |
| boxed_free (q); /* { dg-warning "use of uninitialized value 'q'" } */ |
| boxed_free (p); |
| } |
| |
| void test_17 (void) |
| { |
| boxed_ptr ptr = boxed_malloc (1024); |
| } /* { dg-warning "leak of 'ptr.value'" } */ |
| |
| void test_18 (void) |
| { |
| boxed_ptr ptr = boxed_malloc (64); |
| ptr = boxed_null; /* { dg-warning "leak of 'ptr.value'" } */ |
| } |
| |
| void test_18a (void) |
| { |
| boxed_ptr ptr = boxed_malloc (64); |
| ptr.value = NULL; /* { dg-warning "leak of 'ptr.value'" } */ |
| } |
| |
| void test_19 (void) |
| { |
| boxed_ptr ptr = boxed_malloc (64); |
| free (ptr.value); |
| ptr.value = NULL; |
| free (ptr.value); |
| } |
| |
| boxed_ptr global_ptr_20; |
| |
| void test_20 (void) |
| { |
| global_ptr_20 = boxed_malloc (1024); |
| } |
| |
| int *test_21 (int i) |
| { |
| boxed_ptr ptr = boxed_malloc (sizeof (int)); |
| if (!ptr.value) |
| abort (); |
| *(int *)ptr.value = i; |
| return ptr.value; |
| } |
| |
| boxed_ptr test_21a (int i) |
| { |
| boxed_ptr ptr = boxed_malloc (sizeof (int)); |
| if (!ptr.value) |
| abort (); |
| *(int *)ptr.value = i; |
| return ptr; |
| } |
| |
| void test_22 (void) |
| { |
| boxed_ptr ptr = boxed_malloc (1024); |
| |
| int i; |
| for (i = 5; i < 10; i++) |
| foo (); |
| |
| free (ptr.value); |
| free (ptr.value); /* { dg-warning "double-'free' of 'ptr.value'" } */ |
| } |
| |
| int test_24 (void) |
| { |
| boxed_ptr ptr; |
| ptr.value = __builtin_alloca (sizeof (int)); /* { dg-message "region created on stack here" } */ |
| free (ptr.value); /* { dg-warning "'free' of 'ptr.value' which points to memory on the stack \\\[CWE-590\\\]" } */ |
| } |
| |
| int test_25 (void) |
| { |
| char tmp[100]; /* { dg-message "region created on stack here" } */ |
| boxed_ptr p; |
| p.value = tmp; |
| free (p.value); /* { dg-warning "'free' of '&tmp' which points to memory on the stack \\\[CWE-590\\\]" } */ |
| } |
| |
| char global_buffer[100]; /* { dg-message "region created here" } */ |
| |
| int test_26 (void) |
| { |
| boxed_ptr p; |
| p.value = global_buffer; |
| free (p.value); /* { dg-warning "'free' of '&global_buffer' which points to memory not on the heap \\\[CWE-590\\\]" } */ |
| } |
| |
| struct coord { |
| float x; |
| float y; |
| }; |
| |
| boxed_ptr test_27 (void) |
| { |
| boxed_ptr p = boxed_malloc (sizeof (struct coord)); |
| ((struct coord *)p.value)->x = 0.f; /* { dg-warning "dereference of possibly-NULL 'p.value' \\\[CWE-690\\\]" } */ |
| |
| /* Only the first such usage should be reported: */ |
| ((struct coord *)p.value)->y = 0.f; |
| |
| return p; |
| } |
| |
| struct link |
| { |
| boxed_ptr m_ptr; |
| }; |
| |
| boxed_ptr test_29 (void) |
| { |
| boxed_ptr res = boxed_malloc (sizeof (struct link)); |
| if (!res.value) |
| return boxed_null; |
| ((struct link *)res.value)->m_ptr = boxed_malloc (sizeof (struct link)); |
| return res; |
| } |
| |
| void test_31 (void) |
| { |
| struct link tmp; |
| boxed_ptr ptr = boxed_malloc (sizeof (struct link)); |
| tmp.m_ptr = ptr; |
| } /* { dg-warning "leak" } */ |
| |
| void test_32 (void) |
| { |
| boxed_ptr ptr = boxed_malloc (1024); |
| could_free (ptr.value); |
| } /* { dg-bogus "leak" } */ |
| |
| void test_33 (void) |
| { |
| boxed_ptr ptr = boxed_malloc (1024); |
| cant_free (ptr.value); |
| } /* { dg-warning "leak of 'ptr.value'" } */ |
| |
| void test_34 (void) |
| { |
| float *q; |
| boxed_ptr p = boxed_malloc (sizeof (struct coord)); |
| if (!p.value) |
| return; |
| ((struct coord *)p.value)->x = 0.0f; |
| q = &((struct coord *)p.value)->x; |
| boxed_free (p); |
| *q = 1.0f; /* { dg-warning "use after 'free' of 'q'" } */ |
| }; |
| |
| int test_35 (void) |
| { |
| boxed_ptr ptr = boxed_malloc(4096); |
| if (!ptr.value) |
| return -1; |
| __builtin_memset(ptr.value, 0, 4096); |
| boxed_free(ptr); |
| return 0; |
| } |
| |
| void test_36 (void) |
| { |
| boxed_ptr ptr = boxed_malloc(4096); |
| if (!ptr.value) |
| return; |
| __builtin_memset(ptr.value, 0, 4096); |
| boxed_free(ptr); |
| } |
| |
| boxed_ptr test_37a (void) |
| { |
| boxed_ptr ptr = boxed_malloc(4096); |
| __builtin_memset(ptr.value, 0, 4096); /* { dg-warning "use of possibly-NULL 'ptr.value' where non-null expected \\\[CWE-690\\\]" } */ |
| return ptr; |
| } |
| |
| int test_37b (void) |
| { |
| boxed_ptr p = boxed_malloc(4096); |
| boxed_ptr q = boxed_malloc(4096); |
| if (p.value) { |
| __builtin_memset(p.value, 0, 4096); /* Not a bug: checked */ |
| } else { |
| __builtin_memset(q.value, 0, 4096); /* { dg-warning "use of possibly-NULL 'q.value' where non-null expected \\\[CWE-690\\\]" } */ |
| } |
| boxed_free(p); |
| boxed_free(q); |
| return 0; |
| } |
| |
| extern void might_use_ptr (void *ptr); |
| |
| void test_38(int i) |
| { |
| boxed_ptr p; |
| |
| p = boxed_malloc(1024); |
| if (p.value) { |
| boxed_free(p); |
| might_use_ptr(p.value); /* { dg-warning "use after 'free' of 'p.value'" "" { xfail *-*-* } } */ |
| // TODO: xfail |
| } |
| } |
| |
| boxed_ptr |
| test_39 (int i) |
| { |
| boxed_ptr p = boxed_malloc(sizeof(int*)); |
| *(int *)p.value = i; /* { dg-warning "dereference of possibly-NULL 'p.value' \\\[CWE-690\\\]" } */ |
| return p; |
| } |
| |
| boxed_ptr |
| test_41 (int flag) |
| { |
| boxed_ptr buffer; |
| |
| if (flag) { |
| buffer = boxed_malloc(4096); |
| } else { |
| buffer = boxed_null; |
| } |
| |
| ((char *)buffer.value)[0] = 'a'; /* { dg-warning "dereference of possibly-NULL 'buffer.value' \\\[CWE-690\\\]" "possibly-NULL" } */ |
| /* { dg-warning "dereference of NULL" "NULL" { target *-*-* } .-1 } */ |
| |
| return buffer; |
| } |
| |
| extern void might_take_ownership (boxed_ptr ptr); |
| |
| void test_45 (void) |
| { |
| boxed_ptr p = boxed_malloc (1024); |
| might_take_ownership (p); |
| } |
| |
| /* Free of function, and of label within function. */ |
| |
| void test_50a (void) |
| { |
| } |
| |
| void test_50b (void) |
| { |
| boxed_ptr ptr; |
| ptr.value = test_50a; |
| free (ptr.value); /* { dg-warning "'free' of '&test_50a' which points to memory not on the heap \\\[CWE-590\\\]" } */ |
| } |
| |
| void test_50c (void) |
| { |
| my_label: |
| boxed_ptr ptr; |
| ptr.value = &&my_label; |
| free (ptr.value); /* { dg-warning "'free' of '&my_label' which points to memory not on the heap \\\[CWE-590\\\]" } */ |
| } |
| |
| /* { dg-prune-output "\\\[-Wfree-nonheap-object" } */ |