This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC] powerpc: restore TOC when static longjmp to shared object




Em 23-05-2018 06:26, Alexander Monakov escreveu:
On Tue, 22 May 2018, Rogerio Alves wrote:

I've attached patch v2 to this email with the fixes suggested by Adhemerval.

Why was it necessary to change the prototype of lbar(), and does the testcase
still demonstrate the issue with that change (does it fail without the patch)?


Yes it fails without the patch.

The change on lbar() prototype was made only because glibc is being compiled with and it give me an error due a -Werror=strict-prototypes. But lbar(void) works fine but, you don't have a segmentation fault.

The problem is that if you have a parameter area on the stack alloca/memset will set TOC to 0x0 and lbar() prototype doesn't mean "no parameters" in C it means "any arguments" - C Standard, subclause 6.7.6.3, paragraph 14 [ISO/IEC 9899:2011] - so the compiler ends up creating a parameter area for the function.

This code works if you use lbar(void) or if you don't have a parameter save area on stack:

lbar() - Segmentation fault
lbar(void) - Works (no arguments).
lbar(int a, int b, int c, int d, int e, int f, int g) - Works (less than 8 parameters, use registers, no parameter saving area) lbar(int a, int b, int c, int d, int e, int f, int g, int h, int i) - Segmentation fault


Note that as soon as gcc is capable of optimizing out the alloca-memset code
in the testcase, it will no longer serve the purpose (maybe it's alread > capable, when preparing the testcase I only checked -O0 IIRC). Surely
there
are more direct and robust ways of checking that TOC is correctly restored?

I've tested with -O3 here and get the same problem here. If alloca/memset is optimized out or removed from the code the problem doesn't happens but, that's only if the caller stack frame doesn't change if don't, when longjmp execute you still have a valid TOC on the stack.

But described in https://sourceware.org/bugzilla/show_bug.cgi?id=269

"In this (simple) case the appl calls [bsd]_setjmp() which transfers to __setjmp. Both are in libc.so. So by the time __setjmp() gets control libc.so's TOC is already loaded. In this case we need to reach back into the callers frame and retrieve the callers TOC from the TOC save area. But in the static case the TOC is not saved and has not changed.

In GLIBC sysdeps/powerpc/powerpc64/setjmp.S is built 4 times (static, shared, profiled, and a special version (rtld-setjmp) for the dynamic linker. In the SHARED case (libc.so), external calls to setjmp will save the TOC on the stack, but internal libc calls will not. So the trick is to do the correct thing for each case."

So your test has a example of a code that use a static function to call a longjmp that was set on a shared object called via (static) dlopen. In that case we should have to restore it to caller frame as the jump area is in shared object but, since longjmp is inside static compiled unit TOC is not restored.

I don't think that alloca/memset should destroy the caller stack like is happening but, also I think we have to restore TOC to the caller frame after the longjmp in that case also. I don't know if there's any other more direct and robust ways to checking if TOC is correctly restored. I can't think in anything easier than always restore.

Rogerio


Alexander



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]