--- /dev/null
+/* { dg-additional-options "-fanalyzer-call-summaries" } */
+
+typedef __SIZE_TYPE__ size_t;
+#define NULL ((void *)0)
+
+/* data structures */
+
+struct screen_s {
+ size_t rows;
+ size_t cols;
+ char **data;
+};
+
+struct context_s {
+ struct screen_s *scr;
+};
+
+/* global context variable */
+
+static struct context_s *ctx;
+
+/* prototypes */
+
+struct screen_s *screen_create(size_t cols, size_t rows);
+void screen_destroy(struct screen_s *scr);
+void resize_screen(size_t cols, size_t rows);
+
+/* functions */
+
+struct screen_s *screen_create(size_t cols, size_t rows)
+{
+ struct screen_s *result = NULL;
+
+ result = __builtin_calloc(1, sizeof(*result));
+ if (!result)
+ return NULL;
+
+ result->cols = cols;
+ result->rows = rows;
+
+ /* make one allocation which will be accessed like a 2D array */
+ result->data = __builtin_calloc(rows, sizeof(result->data) + sizeof(*result->data) * cols);
+ if (!result->data) {
+ __builtin_free(result);
+ return NULL;
+ }
+
+ /* obtain pointer to start of data area */
+ char *ptr = (char *)(result->data + rows);
+
+ /* setup pointers for each row of data to allow 2D array access */
+ for (size_t row = 0; row < rows; row++)
+ result->data[row] = (ptr + row * cols);
+ /* array can now be accessed like data[row][col] */
+
+ return result;
+}
+
+void screen_destroy(struct screen_s *scr)
+{
+ if (!scr)
+ return;
+
+ __builtin_free(scr->data);
+
+ scr->data = NULL;
+ scr->rows = 0;
+ scr->cols = 0;
+
+ __builtin_free(scr);
+}
+
+void resize_screen(size_t cols, size_t rows)
+{
+ /* create a new screen */
+ struct screen_s *new_scr = NULL;
+ new_scr = screen_create(cols, rows); /* { dg-bogus "leak" "PR 108045" { xfail *-*-* } } */
+ if (!new_scr) {
+ return;
+ }
+
+ /* swap the old screen with the new one */
+ struct screen_s *old_scr = ctx->scr;
+ ctx->scr = new_scr;
+
+ /* omitted: copy the old screen contents to the new screen */
+
+ /* free the old screen */
+ screen_destroy(old_scr);
+}
+
+int main(void)
+{
+ ctx = __builtin_calloc(1, sizeof(*ctx));
+ if (!ctx)
+ __builtin_abort();
+
+ ctx->scr = screen_create(80, 25); /* { dg-bogus "leak" "PR 108045" { xfail *-*-* } } */
+ resize_screen(100, 20);
+
+ /* tidy up and quit */
+ screen_destroy(ctx->scr);
+ __builtin_free(ctx);
+ ctx = NULL;
+ return 0;
+}
--- /dev/null
+/* { dg-additional-options "-fno-analyzer-call-summaries" } */
+/* { dg-additional-options "-Wno-analyzer-too-complex" } */
+
+typedef __SIZE_TYPE__ size_t;
+#define NULL ((void *)0)
+
+/* data structures */
+
+struct screen_s {
+ size_t rows;
+ size_t cols;
+ char **data;
+};
+
+struct context_s {
+ struct screen_s *scr;
+};
+
+/* global context variable */
+
+static struct context_s *ctx;
+
+/* prototypes */
+
+struct screen_s *screen_create(size_t cols, size_t rows);
+void screen_destroy(struct screen_s *scr);
+void resize_screen(size_t cols, size_t rows);
+
+/* functions */
+
+struct screen_s *screen_create(size_t cols, size_t rows)
+{
+ struct screen_s *result = NULL;
+
+ result = __builtin_calloc(1, sizeof(*result));
+ if (!result)
+ return NULL;
+
+ result->cols = cols;
+ result->rows = rows;
+
+ /* make one allocation which will be accessed like a 2D array */
+ result->data = __builtin_calloc(rows, sizeof(result->data) + sizeof(*result->data) * cols);
+ if (!result->data) {
+ __builtin_free(result);
+ return NULL;
+ }
+
+ /* obtain pointer to start of data area */
+ char *ptr = (char *)(result->data + rows);
+
+ /* setup pointers for each row of data to allow 2D array access */
+ for (size_t row = 0; row < rows; row++)
+ result->data[row] = (ptr + row * cols);
+ /* array can now be accessed like data[row][col] */
+
+ return result;
+}
+
+void screen_destroy(struct screen_s *scr)
+{
+ if (!scr)
+ return;
+
+ __builtin_free(scr->data);
+
+ scr->data = NULL;
+ scr->rows = 0;
+ scr->cols = 0;
+
+ __builtin_free(scr); /* { dg-bogus "leak" } */
+}
+
+void resize_screen(size_t cols, size_t rows)
+{
+ /* create a new screen */
+ struct screen_s *new_scr = NULL;
+ new_scr = screen_create(cols, rows); /* { dg-bogus "leak" } */
+ if (!new_scr) {
+ return;
+ }
+
+ /* swap the old screen with the new one */
+ struct screen_s *old_scr = ctx->scr;
+ ctx->scr = new_scr;
+
+ /* omitted: copy the old screen contents to the new screen */
+
+ /* free the old screen */
+ screen_destroy(old_scr);
+}
+
+int main(void)
+{
+ ctx = __builtin_calloc(1, sizeof(*ctx));
+ if (!ctx)
+ __builtin_abort();
+
+ ctx->scr = screen_create(80, 25); /* { dg-bogus "leak" } */
+ resize_screen(100, 20);
+
+ /* tidy up and quit */
+ screen_destroy(ctx->scr);
+ __builtin_free(ctx);
+ ctx = NULL;
+ return 0;
+}