#include #include typedef struct { int x; int y; } foo_t; typedef struct gcpro { void *addr; struct gcpro *next; } gcpro_t; gcpro_t *foo_root; static foo_t * foo_add (gcpro_t *fl, void *fooaddr) { /* printf ("New local var at %p\n", fooaddr); */ fl->addr = fooaddr; fl->next = foo_root; foo_root = fl; return NULL; } static void foo_remove (void *fooaddr) { /* printf ("Drop local var at %p\n", fooaddr); */ if (fooaddr != foo_root->addr) abort (); foo_root = foo_root->next; } #define FOOPTR(name) \ foo_t __attribute__ ((cleanup (foo_remove))) *name = \ ({ gcpro_t *fl = alloca (sizeof (gcpro_t)); foo_add (fl, &name); }) void gc (int locals) { gcpro_t *fl; /* We should print addresses of all live locals defined with FOOPTR. */ printf ("In GC, expect %d locals at:\n", locals); for (fl = foo_root; fl; fl = fl->next) printf (" %p\n", fl->addr); printf ("GC end\n"); } int foofun (foo_t *f1, foo_t *f2) { FOOPTR (fooptr3); int ret; printf ("In foofun, local var at %p\n", &fooptr3); fooptr3 = malloc (sizeof *fooptr3); fooptr3->x = f1->x + f2->x; fooptr3->y = f1->y - f2->y; if (fooptr3->x > 0) { FOOPTR (fooptr4); printf ("In foofun, inner local var at %p\n", &fooptr4); gc (4); /* Here we expect 4 fooptrs on C stack. */ } ret = fooptr3->x + fooptr3->y; free (fooptr3); return ret; } int main (int argc, char *argv[]) { FOOPTR (fooptr1); FOOPTR (fooptr2); int val; printf ("In main, local vars at %p and %p\n", &fooptr1, &fooptr2); fooptr1 = malloc (sizeof *fooptr1); fooptr1->x = argc; fooptr1->y = argc + 1; fooptr2 = malloc (sizeof *fooptr2); fooptr2->x = argc * 2; fooptr2->y = argc * 2 + 1; val = foofun (fooptr1, fooptr2); free (fooptr1); free (fooptr2); gc (2); /* Here we expect 2 fooptrs on C stack. */ return val; }