pure/const function attribute and memoization

Florian Weimer fweimer@redhat.com
Sat May 18 20:22:00 GMT 2013


On 05/18/2013 10:02 PM, Jan Hubicka wrote:
>> On 05/15/2013 11:01 AM, Richard Biener wrote:
>>> Now - if there would ever be an architecture where special call-site preparation
>>> is required for a callee to write to global memory then marking a function 'const'
>>> when it does in fact write to global memory then GCC may choose to optimize
>>> the call site to not do that call-site preparation.  At least that
>>> would be valid according to the current documentation.
>>
>> That's a good point.
>>
>> The more immediate concern is that the compiler could apply the
>> const attribute to the function definition itself and deduct that
>> code paths with global memory references are unreachable.
>> Apparently, this is something that Clang does in some cases.
>
> It is bit crazy idea though :)  Do you have reference to the corresponding thread?

<http://sourceware.org/ml/libc-alpha/2013-05/msg00389.html>

The function is in glibc's math/atest-exp2.c file.

> BTW we deduce all loops to be finite within const/pure functions that is also
> bit crazy effect of the attribute.

Uhm, okay.

> The memoization you mention is IMO not really safe even with current GCC.  With
> bit of trickery one can convince GCC to early inline the memoizing const
> function in some cases and not in others. Optimizers will then expect your
> memoizing cache to not change across the non-inlined calls that may lead to
> wrong code.

Oh.

> At the moment I can not think of anything that would break if you had pure/const
> function modifying global memory and restoring it before returning.

Well, with a bit of cheating, that's actually easy:

int f1(void) __attribute__((const));
void f2(int);
void lock(void);
void unlock(void);

void
g()
{
   for (int i = 0; i < 10; ++i) {
     lock();
     f2(f1());
     unlock();
   }
}

As expected, the loop turns into:

.L2:
	call	lock
	movl	%ebp, %edi
	call	f2
	call	unlock
	subl	$1, %ebx
	jne	.L2

If g() is called from multiple threads, this is no longer thread-safe 
unless f1() performs its own locking.

I think we should warn about memoization and thread safety issues. 
Trying to come up with more general semantics for const/pure appears to 
be difficult to impossible, and as you say, does not match what the 
compiler does today.

-- 
Florian Weimer / Red Hat Product Security Team



More information about the Gcc mailing list