php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #79230 FFI call doesn't work twice
Submitted: 2020-02-05 12:05 UTC Modified: 2021-09-16 21:25 UTC
From: imbolk at gmail dot com Assigned:
Status: Re-Opened Package: FFI (PECL)
PHP Version: 7.4.2 OS: CentOS Linux
Private report: No CVE-ID: None
 [2020-02-05 12:05 UTC] imbolk at gmail dot com
Description:
------------
Run test code.

Test script:
---------------
<?php
/**
 * @method object mkdtemp(string $template)
 * @method object strerror(int $errnum)
 * @property-read int $errno
 */
$ffi = FFI::cdef('
        char *mkdtemp(char *template);
        char *strerror(int errnum);
        int errno;
');

$mkdtemp = function (string $template) use ($ffi): string {
    $result = $ffi->mkdtemp($template);

    if ($result === null) {
        $errno = $ffi->errno;
        $errstr = $ffi->strerror($errno);
        throw new RuntimeException(FFI::string($errstr), $errno);
    }

    return FFI::string($result);
};


$template = implode(DIRECTORY_SEPARATOR, [sys_get_temp_dir(), 'ffiphp.XXXXXX']);

try {
    $tmppath = $mkdtemp($template);
    rmdir($tmppath);
    echo "YES\n";
} catch (RuntimeException $e) {
    echo $e->getMessage(), "\n";
}

try {
    $tmppath = $mkdtemp($template);
    rmdir($tmppath);
    echo "YES\n";
} catch (RuntimeException $e) {
    echo $e->getMessage(), "\n";
}

Expected result:
----------------
YES
YES


Actual result:
--------------
YES
Invalid argument

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-02-10 11:01 UTC] cmb@php.net
-Status: Open +Status: Not a bug -Assigned To: +Assigned To: cmb
 [2020-02-10 11:01 UTC] cmb@php.net
mkdtemp() modifies the passed char array, so the second call
fails.
 [2020-02-10 14:55 UTC] imbolk at gmail dot com
But the $template variable is not passed to the function by reference!
 [2020-02-10 16:39 UTC] cmb@php.net
-Status: Not a bug +Status: Re-Opened -Assigned To: cmb +Assigned To:
 [2020-02-10 16:39 UTC] cmb@php.net
No, but a pointer to the memory which actually stores the PHP
string is passed to mkdtemp(), and this memory is modified.  I
think this is a deliberate design decision of FFI.
 [2020-02-11 03:16 UTC] imbolk at gmail dot com
But it's completely counterintuitive. BTW this code changes the value of the constant too:

define("TEMPLATE", implode(DIRECTORY_SEPARATOR, [sys_get_temp_dir(), 'ffiphp.XXXXXX']));

$mkdtemp(TEMPLATE);

var_dump(TEMPLATE);
 [2020-02-11 13:21 UTC] imbolk at gmail dot com
Another funny example:

    $ffi = FFI::cdef('
            char *mkdtemp(char *template);
            char *strerror(int errnum);
            int errno;
    ');

    $mkdtemp = function () use ($ffi): string {
        $t = '/tmp/tXXXXXX';
        $result = $ffi->mkdtemp($t);

        if ($result === null) {
            $errno = $ffi->errno;
            $errstr = $ffi->strerror($errno);
            throw new RuntimeException(FFI::string($errstr), $errno);
        }

        return FFI::string($result);
    };


    //$template = implode(DIRECTORY_SEPARATOR, [sys_get_temp_dir(), 'ffiphp.XXXXXX']);
    $template = '/tmp/tXXXXXX';

    try {
        $tmppath = $mkdtemp($template);
        rmdir($tmppath);
        var_dump($template);
    } catch (RuntimeException $e) {
        echo $e->getMessage(), "\n";
    }


Expected:
    string(12) "/tmp/tXXXXXX"
Actual:
    string(12) "/tmp/ttlGhuM"
 [2020-07-11 20:34 UTC] erik at evanv dot nl
Please don't change this behavior. This is handy when passing a PHP string to use as a char* buffer.
 [2021-01-12 18:34 UTC] imbolk at gmail dot com
Why can't you use & in arguments for this?
 [2021-09-16 21:25 UTC] cmb@php.net
-Package: ffi +Package: FFI
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sun Nov 24 19:01:32 2024 UTC