(ruby-devへ河岸をうつします)

> +#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
> +    static int try_dup3 = 1;
> +    if (try_dup3) {
> +        ret = dup3(oldfd, newfd, O_CLOEXEC);
> +        /* dup3 is available since Linux 2.6.27. */
> +        if (ret == -1 && errno == ENOSYS) {
> +            try_dup3 = 0;
> +            ret = dup2(oldfd, newfd);
> +        }
> +    }
> +    else {
> +        ret = dup2(oldfd, newfd);
> +    }
> +#else
>     ret = dup2(oldfd, newfd);
> +#endif
>     if (ret == -1) return -1;
>     fd_set_cloexec(ret);
>     return ret;

akrさん、このコードなんですが、rb_cloexec_dup2(oldfd, newfd)のoldfdとnewfdが一致する可能性は
あるでしょうか?あるとしたら、どういう動作をすべきと意図しているAPIでしょうか?

といいますのも、さいきんglibcのメーリングリストでdup2とdup3とで oldfd == newfd のときの
仕様が異なっており、libcのdup2() が システムコールのdup3() を呼ぶようにしてしまったので、
regressionしたというバグが報告されています。

http://cygwin.com/ml/libc-alpha/2011-09/msg00061.html


いまのコードだと

 - dup3 がない
   dup2()がNOPになったあと、fd_set_cloexec()が呼ばれるのでCLOEXECがつく
 - dup3 がある
   dup3()でEINVALが返ってくるので return -1してしまい、 fd_set_cloexec()は呼ばれない

と動作が変わってしまうように見えます。自分で直そうかとも思ったのですが仕様がわからないので
投げてます。すいません。コメントいただけると助かります。


btw, めちゃくちゃ余談なんですが、dup3でEINVALにしてるのは本当にいい仕様なんですかねえ?