/* Verify that the analyzer correctly purges state when it sees a call to an unknown function. */ #include /* Verify fix for false-positive when checking for CVE-2005-1689. */ typedef struct _krb5_data { char *data; } krb5_data; extern void krb5_read_message(krb5_data *buf); void test_1 (krb5_data inbuf) { free(inbuf.data); krb5_read_message(&inbuf); free(inbuf.data); /* { dg-bogus "double-'free'" } */ } /* Verify that __pure__ functions are treated as not having side-effects. */ extern int called_by_test_1a (void *) __attribute__ ((__pure__)); void test_1a (krb5_data inbuf) { free (inbuf.data); called_by_test_1a (&inbuf); free (inbuf.data); /* { dg-warning "double-'free'" } */ } /* Verify that global pointers can be affected by an unknown function. */ void *global_ptr; extern void unknown_side_effects (void); void test_2 (void) { free (global_ptr); unknown_side_effects (); free (global_ptr); } extern void called_by_test_3 (void *); void test_3a (void) { void *ptr = malloc (1024); called_by_test_3 (ptr); } /* { dg-bogus "leak" } */ void test_3b (void) { krb5_data k; k.data = malloc (1024); called_by_test_3 (&k); } /* { dg-bogus "leak" } */ /* Verify that we traverse the graph of regions that are reachable from the call. */ struct foo { struct foo *next; int *ptr; }; /* First, without a call to an unknown function. */ void test_4a (void) { struct foo node_a; struct foo node_b; node_a.next = &node_b; node_b.ptr = malloc (sizeof (int)); global_ptr = &node_a; *node_b.ptr = 42; /* { dg-warning "possibly-NULL" "possibly-NULL" } */ /* Although there's a chain of pointers to the allocation, pointed to by global_ptr, the chain goes through the stack frame and thus there's a leak when it is popped. */ } /* { dg-warning "leak of 'node_b.ptr'" } */ /* With a call to an unknown function. */ void test_4b (void) { struct foo node_a; struct foo node_b; node_a.next = &node_b; node_b.ptr = malloc (sizeof (int)); global_ptr = &node_a; unknown_side_effects (); /* everything potentially visible through global_ptr. */ *node_b.ptr = 42; /* { dg-bogus "possibly-NULL" } */ } /* { dg-bogus "leak" } */ extern void called_by_test_5 (const char *); void test_5 (void) { called_by_test_5 ("???"); } extern void called_by_test_6 (const struct foo *); void test_6 (void) { struct foo node; node.next = NULL; node.ptr = malloc (sizeof (int)); /* This is a const ptr, but struct foo's ptr is non-const, so we ought to assume it could be written to. */ called_by_test_6 (&node); } /* { dg-bogus "leak" } */ /* TODO: things reachable from "outside" i.e. by params to caller to entrypoint. */