5451


## 背景

`void *` と関数ポインタとの相互変換は、ISO/IEC 9899 や ISO/IEC 14882 では未定義となっています
(広く使われている言語拡張の例として挙げられてはいますが) が、そのままでは POSIX の`dlsym()`
が使い物にならなくなるため、`dlsym()` の解説に以下のような注釈が付けられ、`void*` から関数ポインタへの変換が認められています。

IEEE Std 1003.1, 2013 Edition の `dlsym()` の解説より引用:

> Note that conversion from a void * pointer to a function pointer as in:
[code]

>     fptr = (int (*)(int))dlsym(handle, "my_function");
>  
[/code]

>
> is not defined by the ISO C standard. This standard requires this conversion
> to work correctly on conforming implementations.

## 質問

そこで気になったのですが、逆方向の変換、即ち関数ポインタから `void *` への変換は認められているのでしょうか。  
私が IEEE Std 1003.1 を調べた範囲内ではそのような記述を見付けられなかったのですが、見落しかもしれないと思い、質問させて頂きました。

関数ポインタを`void
*`に変換することは、Linux上でプログラミングをするにあたり、今までちょくちょくやっていたのですが、もしPOSIXで認められていければ避けるようにしようかと考えています。


CC BY-SA 3.0
2015-01-27T14:48:07.367
5443
2015-01-28T09:25:29.870
2015-01-27T15:35:09.890
49
7831
question
linux c++ c
POSIXでは、関数ポインタ から void * への変換は認められているのでしょうか？


~~POSIXでは、"任意の関数へのポインタ型"と"`void*`型"の相互変換は安全に行えると思います。~~

**訂正：**
`dlsym()`戻り値型(`void*`)から関数ポインタ型への一方向変換のみが許容され、"任意の関数ポインタ型"と"`void*`型"の相互変換は認められないと考えます。詳細は後述追記を参照ください。

英語版SOの関連質問"[Are all data pointers of the same size in one
platform?](https://stackoverflow.com/questions/1241205/)"回答には下記引用がありました。
~~（これに直接該当する公開資料は見つけられず…）~~ しかし、この引用元は改訂により削除されています。

> 2.12.3 Pointer Types
>
> All function pointer types shall have the same representation as the type
> pointer to void. Conversion of a function pointer to void * shall not alter
> the representation. A void * value resulting from such a conversion can be
> converted back to the original function pointer type, using an explicit
> cast, without loss of information.
>
> Note: The ISO C standard does not require this, but it is required for POSIX
> conformance.

また、[The Open Group Base Specifications Issue 7, IEEE Std 1003.1, 2013
Edition](http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xsh_chap02.html)には次の記載があります。

> B.2.12 Data Types
>
> Pointer Types
>
> POSIX.1-2008 explicitly requires implementations to convert pointers to void
> * and back with no loss of information. This is an extension over the ISO C
> standard.

* * *

**追記：** 当初は「相互変換OK」と考えていたのですが、少し雲行きが怪しい気がしてきました。

[ISO/IEC/IEEE 9945:2009 Technical Corrigendum
1](http://webstore.iec.ch/corrigenda/iso/isoiecieee9945-cor1%7Bed1.0%7Den.pdf)（POSIX
Base Specifications, Issue 7 TC1）で"2.12.3 Pointer
Types"が削除されています。[OpenGroupのWebサイト](http://pubs.opengroup.org/onlinepubs/9699919799/)はTC適用済みのため、引用文面が記載されていないと考えられます。この削除の根拠として、[Austin
Group Defect Report(s)
#74](http://austingroupbugs.net/view.php?id=74)へのリンクがありました。そこでは

  * 任意の関数ポインタ型⇔`void*`相互変換を許容すると、POSIXでは下記のような危険なコードを合法化してしまう（任意コード実行のような脆弱性につながる）
  * 元々の意図は「`dlsym()`戻り値から適切な関数型ポインタキャストのみを特例として許容する」であったはず

の2点が挙げられていました。

[code]

    char buf[1024];
    void *p;
    int (*f)(void);
    
    // assemble instructions into buf
    p = buf;
    f = p;
    f();
    
[/code]


CC BY-SA 3.0
2015-01-27T15:56:44.583
5451
2015-01-28T09:25:29.870
2017-05-23T12:38:55.307
-1
49
5443
answer