// Skip pointers that are also assigned from libc allocators (e.g. #ifdef FRONTEND) @ palloc_skip exists @ type T; T *ptr; identifier libc_alloc =~ "^(malloc|calloc|realloc|strdup)$"; identifier dealloc =~ "^(free|pg_free)$"; position p; @@ ptr = libc_alloc(...); ... dealloc@p(ptr); // palloc-family allocated memory must be freed with pfree, not free/pg_free. // Handles: ptr = palloc(...); @ exists @ type T; T *ptr; identifier alloc =~ "^p(strdup|nstrdup|alloc|alloc0|alloc_extended|sprintf)$"; identifier dealloc =~ "^(free|pg_free)$"; position p != palloc_skip.p; @@ ptr = alloc(...); ... when any - dealloc@p(ptr); + pfree(ptr); // palloc-family with chained assignment: x = ptr = palloc(...); @ exists @ type T; T *ptr; expression E; identifier alloc =~ "^p(strdup|nstrdup|alloc|alloc0|alloc_extended|sprintf)$"; identifier dealloc =~ "^(free|pg_free)$"; position p != palloc_skip.p; @@ E = ptr = alloc(...); ... when any - dealloc@p(ptr); + pfree(ptr); // palloc-family with typedef'd pointer: T ptr = palloc(...); @ exists @ type T; T ptr; identifier alloc =~ "^p(strdup|nstrdup|alloc|alloc0|alloc_extended|sprintf)$"; identifier dealloc =~ "^(free|pg_free)$"; position p != palloc_skip.p; @@ ptr = alloc(...); ... when any - dealloc@p(ptr); + pfree(ptr); // palloc-family with cast: ptr = (C *) palloc(...); @ exists @ type T, C; T *ptr; identifier alloc =~ "^p(strdup|nstrdup|alloc|alloc0|alloc_extended|sprintf)$"; identifier dealloc =~ "^(free|pg_free)$"; position p != palloc_skip.p; @@ ptr = (C *) alloc(...); ... when any - dealloc@p(ptr); + pfree(ptr); // palloc-family with declaration: T *ptr = palloc(...); @ exists @ type T; identifier ptr; identifier alloc =~ "^p(strdup|nstrdup|alloc|alloc0|alloc_extended|sprintf)$"; identifier dealloc =~ "^(free|pg_free)$"; position p != palloc_skip.p; @@ T *ptr = alloc(...); ... when any - dealloc@p(ptr); + pfree(ptr); // palloc-family with declaration and cast: T *ptr = (C *) palloc(...); @ exists @ type T, C; identifier ptr; identifier alloc =~ "^p(strdup|nstrdup|alloc|alloc0|alloc_extended|sprintf)$"; identifier dealloc =~ "^(free|pg_free)$"; position p != palloc_skip.p; @@ T *ptr = (C *) alloc(...); ... when any - dealloc@p(ptr); + pfree(ptr); // Skip pointers that are also assigned from libc allocators for pg_malloc rules @ pgmalloc_skip exists @ type T; T *ptr; identifier libc_alloc =~ "^(malloc|calloc|realloc|strdup)$"; identifier dealloc =~ "^(free|pfree)$"; position p; @@ ptr = libc_alloc(...); ... dealloc@p(ptr); // pg_malloc-family allocated memory must be freed with pg_free, not free/pfree. // Handles: ptr = pg_malloc(...); @ exists @ type T; T *ptr; identifier alloc =~ "^pg_(strdup|nstrdup|malloc|malloc0|malloc_array|malloc0_array|malloc_object|malloc0_object|malloc_extended|sprintf)$"; identifier dealloc =~ "^(free|pfree)$"; position p != pgmalloc_skip.p; @@ ptr = alloc(...); ... when any - dealloc@p(ptr); + pg_free(ptr); // pg_malloc-family with chained assignment: x = ptr = pg_malloc(...); @ exists @ type T; T *ptr; expression E; identifier alloc =~ "^pg_(strdup|nstrdup|malloc|malloc0|malloc_array|malloc0_array|malloc_object|malloc0_object|malloc_extended|sprintf)$"; identifier dealloc =~ "^(free|pfree)$"; position p != pgmalloc_skip.p; @@ E = ptr = alloc(...); ... when any - dealloc@p(ptr); + pg_free(ptr); // pg_malloc-family with typedef'd pointer: T ptr = pg_malloc(...); @ exists @ type T; T ptr; identifier alloc =~ "^pg_(strdup|nstrdup|malloc|malloc0|malloc_array|malloc0_array|malloc_object|malloc0_object|malloc_extended|sprintf)$"; identifier dealloc =~ "^(free|pfree)$"; position p != pgmalloc_skip.p; @@ ptr = alloc(...); ... when any - dealloc@p(ptr); + pg_free(ptr); // pg_malloc-family with cast: ptr = (C *) pg_malloc(...); @ exists @ type T, C; T *ptr; identifier alloc =~ "^pg_(strdup|nstrdup|malloc|malloc0|malloc_array|malloc0_array|malloc_object|malloc0_object|malloc_extended|sprintf)$"; identifier dealloc =~ "^(free|pfree)$"; position p != pgmalloc_skip.p; @@ ptr = (C *) alloc(...); ... when any - dealloc@p(ptr); + pg_free(ptr); // pg_malloc-family with declaration: T *ptr = pg_malloc(...); @ exists @ type T; identifier ptr; identifier alloc =~ "^pg_(strdup|nstrdup|malloc|malloc0|malloc_array|malloc0_array|malloc_object|malloc0_object|malloc_extended|sprintf)$"; identifier dealloc =~ "^(free|pfree)$"; position p != pgmalloc_skip.p; @@ T *ptr = alloc(...); ... when any - dealloc@p(ptr); + pg_free(ptr); // pg_malloc-family with declaration and cast: T *ptr = (C *) pg_malloc(...); @ exists @ type T, C; identifier ptr; identifier alloc =~ "^pg_(strdup|nstrdup|malloc|malloc0|malloc_array|malloc0_array|malloc_object|malloc0_object|malloc_extended|sprintf)$"; identifier dealloc =~ "^(free|pfree)$"; position p != pgmalloc_skip.p; @@ T *ptr = (C *) alloc(...); ... when any - dealloc@p(ptr); + pg_free(ptr);