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

Rogerio Alves rcardoso@linux.vnet.ibm.com
Wed May 23 12:33:00 GMT 2018



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
> 



More information about the Libc-alpha mailing list