'goto *foo' where foo is not a pointer. What is this?

那年仲夏 提交于 2019-12-04 15:27:58

问题


I was playing around with labels as values and ended up with this code.

int foo = 0;
goto *foo;

My C/C++ experience tells me *foo means dereference foo and that this won't compile because foo isn't a pointer. But it does compile. What does this actually do?

gcc (Ubuntu 4.9.2-0ubuntu1~12.04) 4.9.2, if important.


回答1:


This is a known bug in gcc.

gcc has a documented extension that permits a statement of the form

goto *ptr;

where ptr can be any expression of type void*. As part of this extension, applying a unary && to a label name yields the address of the label, of type void*.

In your example:

int foo = 0;
goto *foo;

foo clearly is of type int, not of type void*. An int value can be converted to void*, but only with an explicit cast (except in the special case of a null pointer constant, which does not apply here).

The expression *foo by itself is correctly diagnosed as an error. And this:

goto *42;

compiles without error (the generated machine code appears to be a jump to address 42, if I'm reading the assembly code correctly).

A quick experiment indicates that gcc generates the same assembly code for

goto *42;

as it does for

goto *(void*)42;

The latter is a correct use of the documented extension, and it's what you should probably if, for some reason, you want to jump to address 42.

I've submitted a bug report -- which was quickly closed as a duplicate of this bug report, submitted in 2007.




回答2:


Seems to be a GCC bug. Here is a clang output as a comparison. It seems that these are the errors we should expect.

$ cc -v
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.3.0
Thread model: posix
$ cc goto.c 
goto.c:5:7: warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'const void *' [-Wint-conversion]
        goto *foo;
             ^~~~
goto.c:5:2: error: indirect goto in function with no address-of-label expressions
        goto *foo;
        ^
1 warning and 1 error generated.

goto.c source code:

int main(int argc, char const *argv[])
{
    int foo = 0;
    goto *foo;
}



回答3:


This is not a bug, rather a consequence of GCC's Labels and Values extension. I'm guessing they had things like fast jump tables and JIT's in mind. With this (mis)feature, you can jump into functions

// c
goto *(int *)exit;
// c++
goto *reinterpret_cast<int *>(std::exit);

and do wonderfully tasteful things like jump into a string literal

goto *&"\xe8\r\0\0\0Hello, World!Yj\1[j\rZj\4X\xcd\x80,\f\xcd\x80";

Try it online!

Don't forget that pointer arithmetic is permitted!

goto *(24*(a==1)+"\xe8\7\0\0\0Hello, Yj\1[j\7Zj\4X\xcd\x80\xe8\6\0\0\0World!Yj\1[j\6Zj\4X\xcd\x80,\5\xcd\x80");

I'll leave additional consequences as an exercise to the reader (argv[0], __FILE__, __DATE__, etc.)

Note that you'll need to ensure that you have executable permission for the area of memory to which you jump.



来源:https://stackoverflow.com/questions/35236834/goto-foo-where-foo-is-not-a-pointer-what-is-this

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!