On Wed, Nov 26, 2025 at 10:01:09AM +0100, Richard Biener wrote:
> 
> I do wonder whether we want to go this route though - in principle
> we have similar info for computed goto.  I'm not 100% sure about non-local
> goto, but we know all possible targets here as well.

At eh pass time we don't have such info for computed gotos, only at cfg pass
time and more importantly, it isn't in the form this statement may jump
here, but this statement does computed goto and these are possible
destinations of computed gotos.  For the cleanups the knowledge this jumps
from here to here is essential.  And for computed gotos we have also no way
to adjust where we branch to, all we have is the computed goto and spots
which take &&label, but how exactly those addresses bubble up to the
computed goto can be hidden behind various function calls etc.
Even for mere
int cnt;

static void
my_cleanup (int *p)
{
  ++cnt;
}

void bar (int);

void
foo (int x, int y)
{
  static void *p[] = { &&l1, &&l2, &&l3 };
  {
    int x __attribute__((cleanup (my_cleanup))) = 0;
    {
      int y __attribute__((cleanup (my_cleanup))) = 0;
      {
        int z __attribute__((cleanup (my_cleanup))) = 0;
        if (x == 0)
          goto *p[y];
        bar (0);
      }
l1:
      if (x == 1)
        goto *p[y];
      bar (1);
    }
l2:
    if (x == 2)
      goto *p[y];
    bar (2);
  }
l3:
  bar (3);
}
how could one actually adjust the computed gotos to perform the needed
cleanups?  All of sudden it couldn't branch to p[y] in each case, but to
l1 variant which performs z cleanup, l2 variant which performs z and y
cleanups, l3 variant which performs z, y and z cleanups in one spot,
l1, l2 variant which performs y cleanup and l3 variant which performs
z and y cleanups in the second case, etc.
And now you can also obfuscate it, leak p address into global state with
one function and change p[y] into qux (y);

        Jakub

Reply via email to