1

Not sure i'm missing something about the use of goto:

This doesnt work, ends in a segfault:

for(long i = 0; i < 1000000000; i++) {
    LABEL_1: {
        int test[10];

        goto LABEL_2;
    }

    LABEL_2: {
        int test[10];
    }
}

Whereas this works:

for(long i = 0; i < 1000000000; i++) {
    LABEL_1: {
        {               // Note this extra block
           int test[10];
        }

        goto LABEL_2;
    }

    LABEL_2: {
        int test[10];
    }
}

This examples dont trigger the issue, but represent what is happening in my code.

This is a simplified example of what is happening in https://github.com/risotto/risotto/tree/feature/direct-threading-2

See https://github.com/risotto/risotto/blob/feature/direct-threading-2/src/lib/vm/vm.c#L332 and https://github.com/risotto/risotto/blob/feature/direct-threading-2/src/lib/vm/vm.c#L257

From my repo, this works:

        case TARGET(OP_RETURN):
        {
                FunctionCall fc = vec_pop(&vm.fcs);
                int rc = fc.retc;

            {
                Value rvals[rc];
                for (int i = rc - 1; i >= 0; --i) {
                    rvals[i] = copy(pop());
                }

                vm.ip = fc.ip;
                vm.sp = fc.sp;
                vm.fp = fc.fp;

                vm.sp -= fc.argc;

                pushm(rvals, rc);
            }
            NEXT();
        }

This doesnt:

        case TARGET(OP_RETURN):
        {
                FunctionCall fc = vec_pop(&vm.fcs);
                int rc = fc.retc;

                Value rvals[rc];
            {
                for (int i = rc - 1; i >= 0; --i) {
                    rvals[i] = copy(pop());
                }

                vm.ip = fc.ip;
                vm.sp = fc.sp;
                vm.fp = fc.fp;

                vm.sp -= fc.argc;

                pushm(rvals, rc);
            }
            NEXT();
        }

This is compiled through gcc GNU 7, and makes use of computed goto inside NEXT

walnut
  • 21,629
  • 4
  • 23
  • 59
Raphaël Vigée
  • 2,048
  • 14
  • 27
  • 1
    Unable to reproduce with gcc 9.2, you're not missing anything. If so, then this must be a compiler bug that's been fixed in later versions of gcc. – Sam Varshavchik Mar 29 '20 at 00:18
  • Me neither, also tried gcc 7.5.0 on Ubuntu x86-64. Please create a minimal reproducible example and state your platform and compiler options. In particular, is this C or C++? I think it'd be legal in either language, more sure about C. – Nate Eldredge Mar 29 '20 at 00:25
  • This code does not actually trigger the issue, its a simplified representation of the issue how i diagnosed it, and it seems to be triggered by local array not going out of scope when using goto (have a look at the 2 examples I put at the end). In my VM code, encapsulating these arrays into a block fixes the issue... – Raphaël Vigée Mar 29 '20 at 00:26
  • @NateEldredge This is C, it is legal in both – Raphaël Vigée Mar 29 '20 at 00:27
  • I'm having a hard time creating a small example that is reproductible... I'm working on it – Raphaël Vigée Mar 29 '20 at 00:27
  • @TomKarzes The smallest example I have is https://github.com/risotto/risotto/blob/feature/direct-threading-2/src/lib/vm/vm.c#L332-L348, removing this block triggers the issue, do you see anything that looks odd ? – Raphaël Vigée Mar 29 '20 at 00:30
  • I edited my question to add more details – Raphaël Vigée Mar 29 '20 at 00:33
  • 1
    @RaphaëlVigée You are using a GCC-specific extension inside `NEXT()`. You should mention that as well because standard rules may not apply to it. – walnut Mar 29 '20 at 00:36
  • Thank you for your suggestion @walnut, i edited my question – Raphaël Vigée Mar 29 '20 at 00:37
  • 2
    @RaphaëlVigée You are using a VLA as well, which requires runtime action to allocate/deallocate it. There was a similar C++ question here recently related to computed goto having a similar weird behavior in GCC for non-trivial destructors. Let me try to find it... – walnut Mar 29 '20 at 00:46
  • 1
    See [this question](https://stackoverflow.com/questions/60812880/does-computed-goto-respect-c-object-lifetime) indicating that GCC ignores non-trivial destructor calls in C++ when computed gotos are used. Deallocation of a VLA would be implemented similarly I guess. – walnut Mar 29 '20 at 00:49
  • https://stackoverflow.com/questions/29124145/segmentation-fault-when-jumping-to-goto-over-vla-array This also mentions it, so no real fix other than wrapping stuff with an extra block I guess, You can make it an answer, i'd accept it – Raphaël Vigée Mar 29 '20 at 00:52
  • 1
    In C it should be okay to `goto` *out* of the scope of a VLA, as long as you don't `goto` *into* such a scope. I would take a look at the target of your `goto`, – Nate Eldredge Mar 29 '20 at 01:17
  • 2
    @NateEldredge Yes and similarly it is okay to jump out of the scope of a variable with non-trivial destructor in C++ and GCC handles that correctly for usual gotos, but seemingly not for computed gotos. Clang rejects such as cases out-right. So I think it is just a GCC bug that there is no diagnostic. I would write an answer if I found a bug report or some clear source for this issue, but I haven't so far. – walnut Mar 29 '20 at 01:37

0 Answers0