| /* { 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 *. */ |
| |
| void test_1 (void) |
| { |
| void *ptr = malloc (1024); |
| free (ptr); |
| free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */ |
| } |
| |
| void test_2 (void *ptr) |
| { |
| free (ptr); |
| free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */ |
| } |
| |
| void test_2a (void *ptr) |
| { |
| __builtin_free (ptr); |
| __builtin_free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */ |
| } |
| |
| int *test_3 (void) |
| { |
| int *ptr = (int *)malloc (sizeof (int)); |
| *ptr = 42; /* { dg-warning "dereference of possibly-NULL 'ptr' \\\[CWE-690\\\]" } */ |
| return ptr; |
| } |
| |
| int *test_3a (void) |
| { |
| int *ptr = (int *)__builtin_malloc (sizeof (int)); |
| *ptr = 42; /* { dg-warning "dereference of possibly-NULL 'ptr' \\\[CWE-690\\\]" } */ |
| return ptr; |
| } |
| |
| int *test_4 (void) |
| { |
| int *ptr = (int *)malloc (sizeof (int)); |
| if (ptr) |
| *ptr = 42; |
| else |
| *ptr = 43; /* { dg-warning "dereference of NULL 'ptr' \\\[CWE-476\\\]" } */ |
| return ptr; |
| } |
| |
| int test_5 (int *ptr) |
| { |
| free (ptr); |
| return *ptr; /* { dg-warning "use after 'free' of 'ptr'" } */ |
| } |
| |
| void test_6 (void *ptr) |
| { |
| void *q; |
| q = ptr; |
| free (ptr); |
| free (q); /* { dg-warning "double-'free' of 'q'" } */ |
| /* The above case requires us to handle equivalence classes in |
| state transitions. */ |
| } |
| |
| void test_7 (void) |
| { |
| void *ptr = malloc(4096); |
| if (!ptr) |
| return; |
| __builtin_memset(ptr, 0, 4096); |
| free(ptr); |
| } |
| |
| void *test_8 (void) |
| { |
| void *ptr = malloc(4096); |
| if (!ptr) |
| return NULL; |
| __builtin_memset(ptr, 0, 4096); |
| return ptr; |
| /* This needs phi nodes to affect equivalence classes, or we get a false report |
| of a leak. */ |
| } |
| |
| void test_9 (void) |
| { |
| void *ptr = malloc (1024); |
| |
| int i; |
| for (i = 0; i < 1024; i++) |
| free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */ |
| } |
| |
| void test_10 (void) |
| { |
| void *ptr = malloc (1024); |
| |
| int i; |
| for (i = 0; i < 1024; i++) |
| foo (); |
| |
| free (ptr); |
| free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */ |
| } |
| |
| void test_11 (void) |
| { |
| void *ptr = malloc (1024); |
| |
| while (foo ()) |
| bar (); |
| |
| free (ptr); |
| free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */ |
| } |
| |
| void test_12 (void) |
| { |
| void *ptr = malloc (1024); |
| |
| while (1) |
| { |
| free (ptr); |
| free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */ |
| } |
| } |
| |
| void test_13 (void) |
| { |
| void *p = malloc (1024); /* { dg-message "allocated here" } */ |
| void *q = malloc (1024); |
| |
| foo (); |
| if (!q) |
| { |
| free (q); |
| return; /* { dg-warning "leak of 'p'" } */ |
| } |
| bar (); |
| free (q); |
| free (p); |
| } |
| |
| void test_14 (void) |
| { |
| void *p, *q; |
| p = malloc (1024); |
| if (!p) |
| return; |
| |
| q = malloc (1024); |
| if (!q) |
| { |
| free (p); |
| free (q); |
| /* oops: missing "return". */ |
| } |
| bar (); |
| 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); /* { dg-warning "double-'free' of 'p'" } */ |
| } |
| |
| void test_15 (void) |
| { |
| void *p = NULL, *q = NULL; |
| |
| p = malloc (1024); |
| if (!p) |
| goto fail; |
| |
| foo (); |
| |
| q = malloc (1024); |
| if (!q) |
| goto fail; |
| |
| bar (); |
| |
| fail: |
| free (q); |
| free (p); |
| } |
| |
| void test_16 (void) |
| { |
| void *p, *q; /* { dg-message "region created on stack here" } */ |
| |
| p = malloc (1024); |
| if (!p) |
| goto fail; |
| |
| foo (); |
| |
| q = malloc (1024); |
| if (!q) |
| goto fail; |
| |
| bar (); |
| |
| fail: |
| free (q); /* { dg-warning "use of uninitialized value 'q'" } */ |
| free (p); |
| } |
| |
| void test_17 (void) |
| { |
| void *ptr = malloc (1024); /* { dg-message "allocated here" } */ |
| } /* { dg-warning "leak of 'ptr'" } */ |
| |
| void test_18 (void) |
| { |
| void *ptr = malloc (64); /* { dg-message "allocated here" } */ |
| ptr = NULL; /* { dg-warning "leak of 'ptr'" } */ |
| } |
| |
| void test_19 (void) |
| { |
| void *ptr = malloc (64); |
| free (ptr); |
| ptr = NULL; |
| free (ptr); |
| } |
| |
| void *global_ptr_20; |
| |
| void test_20 (void) |
| { |
| global_ptr_20 = malloc (1024); |
| } |
| |
| int *test_21 (int i) |
| { |
| int *ptr = malloc (sizeof (int)); |
| if (!ptr) |
| abort (); |
| *ptr = i; |
| return ptr; |
| } |
| |
| void test_22 (void) |
| { |
| void *ptr = malloc (1024); |
| |
| int i; |
| for (i = 5; i < 10; i++) |
| foo (); |
| |
| free (ptr); |
| free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */ |
| } |
| |
| int *test_23 (int n) |
| { |
| int *ptr = (int *)calloc (n, sizeof (int)); |
| ptr[0] = 42; /* { dg-warning "dereference of possibly-NULL 'ptr' \\\[CWE-690\\\]" } */ |
| return ptr; |
| } |
| |
| int *test_23a (int n) |
| { |
| int *ptr = (int *)__builtin_calloc (n, sizeof (int)); |
| ptr[0] = 42; /* { dg-warning "dereference of possibly-NULL 'ptr' \\\[CWE-690\\\]" } */ |
| return ptr; |
| } |
| |
| int test_24 (void) |
| { |
| void *ptr = __builtin_alloca (sizeof (int)); /* { dg-message "region created on stack here" } */ |
| free (ptr); /* { dg-warning "'free' of 'ptr' which points to memory on the stack \\\[CWE-590\\\]" } */ |
| } |
| |
| int test_25 (void) |
| { |
| char tmp[100]; /* { dg-message "region created on stack here" } */ |
| void *p = tmp; |
| free (p); /* { dg-warning "'free' of 'p' which points to memory on the stack \\\[CWE-590\\\]" } */ |
| /* TODO: more precise messages here. */ |
| } |
| |
| char global_buffer[100]; /* { dg-message "region created here" } */ |
| |
| int test_26 (void) |
| { |
| void *p = global_buffer; |
| free (p); /* { dg-warning "'free' of 'p' which points to memory not on the heap \\\[CWE-590\\\]" } */ |
| /* TODO: more precise messages here. */ |
| } |
| |
| struct coord { |
| float x; |
| float y; |
| }; |
| |
| struct coord *test_27 (void) |
| { |
| struct coord *p = (struct coord *) malloc (sizeof (struct coord)); /* { dg-message "this call could return NULL" } */ |
| p->x = 0.f; /* { dg-warning "dereference of possibly-NULL 'p' \\\[CWE-690\\\]" } */ |
| |
| /* Only the first such usage should be reported: */ |
| p->y = 0.f; |
| |
| return p; |
| } |
| |
| struct coord *test_28 (void) |
| { |
| struct coord *p = NULL; |
| p->x = 0.f; /* { dg-warning "dereference of NULL 'p' \\\[CWE-476\\\]" } */ |
| |
| /* Only the first such usage should be reported: */ |
| p->y = 0.f; |
| |
| return p; |
| } |
| |
| struct link |
| { |
| struct link *m_ptr; |
| }; |
| |
| struct link *test_29 (void) |
| { |
| struct link *res = (struct link *)malloc (sizeof (struct link)); |
| if (!res) |
| return NULL; |
| res->m_ptr = (struct link *)malloc (sizeof (struct link)); |
| return res; |
| } |
| |
| struct link *test_29a (void) |
| { |
| struct link *res = (struct link *)malloc (sizeof (struct link)); |
| if (!res) |
| return NULL; |
| res->m_ptr = (struct link *)malloc (sizeof (struct link)); |
| if (!res->m_ptr) |
| { |
| free (res); |
| return NULL; |
| } |
| res->m_ptr->m_ptr = (struct link *)malloc (sizeof (struct link)); |
| return res; |
| } |
| |
| /* Without consolidation by EC, this one shows two leaks: |
| warning: leak of '<unknown>' |
| warning: leak of 'tmp.m_ptr' |
| We should only show the latter (favoring the most user-readable |
| expression in the equivalence class). */ |
| void test_30 (void) |
| { |
| struct link tmp; |
| tmp.m_ptr = (struct link *)malloc (sizeof (struct link)); /* { dg-message "allocated here" } */ |
| } /* { dg-warning "leak of 'tmp.m_ptr'" } */ |
| /* { dg-bogus "leak of '<unknown>'" "leak of unknown" { target *-*-* } .-1 } */ |
| |
| void test_31 (void) |
| { |
| struct link tmp; |
| void *ptr = malloc (sizeof (struct link)); /* { dg-message "allocated here" } */ |
| tmp.m_ptr = (struct link *)ptr; |
| } /* { dg-warning "leak of 'ptr'" } */ |
| /* { dg-bogus "leak of 'tmp.m_ptr'" "" { target *-*-* } .-1 } */ |
| |
| void test_32 (void) |
| { |
| void *ptr = malloc (1024); |
| could_free (ptr); |
| } /* { dg-bogus "leak" } */ |
| |
| void test_33 (void) |
| { |
| void *ptr = malloc (1024); /* { dg-message "allocated here" } */ |
| cant_free (ptr); |
| } /* { dg-warning "leak of 'ptr'" } */ |
| |
| void test_34 (void) |
| { |
| float *q; |
| struct coord *p = malloc (sizeof (struct coord)); |
| if (!p) |
| return; |
| p->x = 0.0f; |
| q = &p->x; |
| free (p); |
| *q = 1.0f; /* { dg-warning "use after 'free' of 'q'" } */ |
| }; |
| |
| int test_35 (void) |
| { |
| void *ptr = malloc(4096); |
| if (!ptr) |
| return -1; |
| __builtin_memset(ptr, 0, 4096); |
| free(ptr); |
| return 0; |
| } |
| |
| void test_36 (void) |
| { |
| void *ptr = malloc(4096); |
| if (!ptr) |
| return; |
| __builtin_memset(ptr, 0, 4096); |
| free(ptr); |
| } |
| |
| void *test_37a (void) |
| { |
| void *ptr = malloc(4096); /* { dg-message "this call could return NULL" } */ |
| __builtin_memset(ptr, 0, 4096); /* { dg-warning "use of possibly-NULL 'ptr' where non-null expected \\\[CWE-690\\\]" } */ |
| return ptr; |
| } |
| |
| int test_37b (void) |
| { |
| void *p = malloc(4096); |
| void *q = malloc(4096); /* { dg-message "this call could return NULL" } */ |
| if (p) { |
| __builtin_memset(p, 0, 4096); /* Not a bug: checked */ |
| } else { |
| __builtin_memset(q, 0, 4096); /* { dg-warning "use of possibly-NULL 'q' where non-null expected \\\[CWE-690\\\]" } */ |
| } |
| free(p); |
| free(q); |
| return 0; |
| } |
| |
| extern void might_use_ptr (void *ptr); |
| |
| void test_38(int i) |
| { |
| void *p; |
| |
| p = malloc(1024); |
| if (p) { |
| free(p); |
| might_use_ptr(p); /* { dg-warning "use after 'free' of 'p'" "" { xfail *-*-* } } */ |
| // TODO: xfail |
| } |
| } |
| |
| int * |
| test_39 (int i) |
| { |
| int *p = (int*)malloc(sizeof(int*)); /* { dg-message "this call could return NULL" } */ |
| *p = i; /* { dg-warning "dereference of possibly-NULL 'p' \\\[CWE-690\\\]" } */ |
| return p; |
| } |
| |
| int * |
| test_40 (int i) |
| { |
| int *p = (int*)malloc(sizeof(int*)); /* { dg-message "region created on heap here" } */ |
| i = *p; /* { dg-warning "dereference of possibly-NULL 'p' \\\[CWE-690\\\]" "possibly-null" } */ |
| /* { dg-warning "use of uninitialized value '\\*p'" "uninit" { target *-*-*} .-1 } */ |
| return p; |
| } |
| |
| char * |
| test_41 (int flag) |
| { |
| char *buffer; |
| |
| if (flag) { |
| buffer = (char*)malloc(4096); |
| } else { |
| buffer = NULL; |
| } |
| |
| buffer[0] = 'a'; /* { dg-warning "dereference of possibly-NULL 'buffer' \\\[CWE-690\\\]" "possibly-NULL" } */ |
| /* { dg-warning "dereference of NULL 'buffer' \\\[CWE-476\\\]" "NULL" { target *-*-* } .-1 } */ |
| |
| return buffer; |
| } |
| |
| void test_42a (void) |
| { |
| void *p = malloc (1024); /* { dg-message "allocated here" } */ |
| free (p + 64); /* this could well corrupt the heap. */ |
| /* TODO: ^^^ we should warn about this. */ |
| } /* { dg-warning "leak of 'p'" } */ |
| /* TODO: presumably we should complain about the bogus free, but then |
| maybe not complain about the leak. */ |
| // CWE-761: Free of Pointer not at Start of Buffer |
| |
| void test_42b (void) |
| { |
| void *p = malloc (1024); /* { dg-message "allocated here" } */ |
| free (p - 64); /* this could well corrupt the heap. */ |
| /* TODO: ^^^ we should warn about this. */ |
| } /* { dg-warning "leak of 'p'" } */ |
| /* TODO: presumably we should complain about the bogus free, but then |
| maybe not complain about the leak. */ |
| // CWE-761: Free of Pointer not at Start of Buffer |
| |
| void test_42c (void) |
| { |
| void *p = malloc (1024); |
| void *q = p + 64; |
| free (q - 64); /* this is probably OK. */ |
| } /* { dg-bogus "leak of 'p'" } */ |
| |
| void * |
| test_42d (void) |
| { |
| void *p = malloc (1024); |
| void *q = p + 64; |
| return q; |
| } /* { dg-bogus "leak of 'p'" } */ |
| |
| #if 0 |
| void test_31 (void *p) |
| { |
| void *q = realloc (p, 1024); |
| free (p); /* FIXME: this is a double-'free'. */ |
| free (q); |
| } |
| |
| void test_32 (void) |
| { |
| void *p = malloc (64); |
| p = realloc (p, 1024); /* FIXME: this leaks if it fails. */ |
| free (p); |
| } |
| #endif |
| |
| struct link global_link; |
| |
| void test_43 (void) |
| { |
| global_link.m_ptr = malloc (sizeof (struct link)); /* { dg-message "allocated here" } */ |
| global_link.m_ptr = NULL; /* { dg-warning "leak of 'global_link.m_ptr'" } */ |
| } |
| |
| struct link *global_ptr; |
| |
| void test_44 (void) |
| { |
| global_ptr = malloc (sizeof (struct link)); |
| if (!global_ptr) |
| return; |
| global_ptr->m_ptr = malloc (sizeof (struct link)); /* { dg-message "allocated here" } */ |
| free (global_ptr); /* { dg-warning "leak of '<unknown>'" } */ |
| /* TODO: should be more precise than just '<unknown>'. */ |
| } |
| |
| extern void might_take_ownership (void *ptr); |
| |
| void test_45 (void) |
| { |
| void *p = malloc (1024); |
| might_take_ownership (p); |
| } |
| |
| void test_46 (void) |
| { |
| struct link *p = (struct link *)malloc (sizeof (struct link)); |
| if (!p) |
| return; |
| struct link *q = (struct link *)malloc (sizeof (struct link)); |
| p->m_ptr = q; |
| might_take_ownership (p); |
| } |
| |
| extern int maybe_alloc (char **); |
| |
| int test_47 (void) |
| { |
| char *p = ((void *)0); |
| int p_size = 0; |
| |
| p = malloc (16); |
| if (p) { |
| free (p); |
| } else { |
| int retval = maybe_alloc (&p); /* this might write to "p". */ |
| if (retval) |
| return (retval); |
| p_size = __builtin_strlen(p); /* { dg-bogus "non-null expected" } */ |
| free (p); |
| } |
| return p_size; |
| } |
| |
| void test_48 (void) |
| { |
| int *p = NULL; /* { dg-message "'p' is NULL" } */ |
| *p = 1; /* { dg-warning "dereference of NULL 'p' \\\[CWE-476\\\]" } */ |
| } |
| |
| /* As test_48, but where the assignment of NULL is not at the start of a BB. */ |
| |
| int test_49 (int i) |
| { |
| int *p; |
| int x; |
| |
| x = i * 2; |
| p = NULL; /* { dg-message "'p' is NULL" } */ |
| *p = 1; /* { dg-warning "dereference of NULL 'p' \\\[CWE-476\\\]" } */ |
| return x; |
| } |
| |
| /* Free of function, and of label within function. */ |
| |
| void test_50a (void) |
| { |
| } |
| |
| void test_50b (void) |
| { |
| free (test_50a); /* { dg-warning "'free' of '&test_50a' which points to memory not on the heap \\\[CWE-590\\\]" } */ |
| } |
| |
| void test_50c (void) |
| { |
| my_label: |
| free (&&my_label); /* { dg-warning "'free' of '&my_label' which points to memory not on the heap \\\[CWE-590\\\]" } */ |
| } |
| |
| /* Double free after unconditional dereference. */ |
| |
| int test_51 (int *p) |
| { |
| int result = *p; |
| free (p); /* { dg-message "first 'free' here" } */ |
| free (p); /* { dg-warning "double-'free' of 'p'" } */ |
| return result; |
| } |
| |
| /* { dg-prune-output "\\\[-Wfree-nonheap-object" } */ |