Understanding Safety of Function Pointers vs. Addresses of Functions

H. S. Teoh via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Tue Jul 7 13:19:57 PDT 2015


On Tue, Jul 07, 2015 at 07:54:18PM +0000, jmh530 via Digitalmars-d-learn wrote:
> I'm not sure I understand the safety of function pointers vs. the addresses
> of functions. The code below illustrates the issue.

Function pointers and addresses of functions are the same thing. There
is no difference between them.


> I was under the impression that pointers are not allowed in safe code.

This is incorrect. Pointers are allowed in safe code as long as they are
not manipulated in unsafe ways (e.g., assigning a literal value to them,
pointer arithmetic, casting to a pointer to an incompatible type, using
a pointer to call an un- at safe function from @safe code, etc.).


> Naturally, I took that to also mean that function pointers are not
> allowed in safe code. Indeed, I haven't been able to pass a function
> pointer to a safe function. However, I am able to take the address of
> a function and pass that as a parameter. It seems to work fine for
> taking the address of functions and templates (so long as I !)

The reason for this is that function pointers have attributes associated
with them, as part of the type system. The address of a @safe function
is a @safe function pointer, meaning that it's legal to call the
function through this pointer in @safe code. The address of a @system
function is a @system function pointer, which *cannot* be used to call
the function from @safe code.

However, while it is not allowed to assign a @system function pointer to
a @safe function pointer (since that could be used to bypass the @safe
restriction on calling @system functions), it is OK to assign a @safe
function pointer to a @system function pointer (this is called
covariance). This is allowed because a @system function pointer can only
be dereferenced in @system code, and @system code can freely call any
function with no restrictions. Where this might become a problem,
though, is when you inadvertently assign a @safe function pointer to a
@system function pointer, and then attempt to call it from @safe code --
the compiler will reject that. This is what happened with your sample
code:


[...]
> void main()
> {
> 	function_safety(&cbrt);  //prints fp is trusted
> 	real function(real) fp = &cbrt;

Here, fp is a @system function pointer. While &cbrt is a @safe function
pointer, it is covariant with a @system function pointer, so the
assignment is allowed.


> 	function_safety(fp);     //prints fp is system
[...]

The result, however, is now @system, so you can no longer call cbrt from
@safe code through this particular function pointer (though you can
obviously call it through a @safe function pointer).

The correct syntax for declaring a @safe function pointer would be:

	real function(real) @safe fp = ...;

Either that, or use `auto` to let the compiler figure out the correct
function pointer attributes for you:

	auto fp = &cbrt;
	pragma(msg, typeof(fp).stringof);

The compiler prints:

	real function(real x) nothrow @nogc @trusted

So you see here that two other attributes, nothrow and @nogc, are also
inferred by the compiler, which is a good thing because otherwise your
function pointer wouldn't be usable from nothrow or @nogc code,
respectively.


T

-- 
Music critic: "That's an imitation fugue!"


More information about the Digitalmars-d-learn mailing list