Skip to content

Returning arrays in frankenphp extensions seems broken #1891

@SpencerMalone

Description

@SpencerMalone

What happened?

Working on a PDO extension for frankenphp, but got to implementing statement fetches and am a bit stuck with the new frankenphp.PHPAssociativeArray. I've tried a few of the new methods, and in all cases I get:
panic: runtime error: cgo result is unpinned Go pointer or points to unpinned Go pointer

My C method looks like:

PHP_METHOD(FrankenPDO_PDOStatement, fetch) {
    php_printf("stmt_fetch: called\n");
    stmt_object *intern = stmt_object_from_obj(Z_OBJ_P(ZEND_THIS));
    zend_long mode = 4; // PDO::FETCH_BOTH
    zend_long cursor_orientation = 0;
    zend_long cursor_offset = 0;
    
    VALIDATE_GO_HANDLE(intern);
    
    ZEND_PARSE_PARAMETERS_START(0, 3)
        Z_PARAM_OPTIONAL
        Z_PARAM_LONG(mode)
        Z_PARAM_LONG(cursor_orientation)
        Z_PARAM_LONG(cursor_offset)
    ZEND_PARSE_PARAMETERS_END();
    
    zend_array *result = stmt_fetch();
    php_printf("stmt_fetch: returned array\n");
   
    if (result) {
        RETURN_ARR(result);
    }

    RETURN_FALSE; 
}

My go method looks like:

//export stmt_fetch
func stmt_fetch() unsafe.Pointer {
	return frankenphp.PHPAssociativeArray(frankenphp.AssociativeArray{
		Map: map[string]any{
			"key1": "value1",
			"key2": "value2",
		},
		Order: []string{"key1", "key2"},
	})
}

And my PHP test code is:

    <snip of PDO setup / data inserting>
    echo "Querying data...\n";
    $new_stmt = $pdo->prepare("SELECT * FROM users");
    $new_stmt->execute();
    
    echo "Results:\n";
    $count = 0;
    while ($row = $new_stmt->fetch(\FrankenPDO\PDO::FETCH_ASSOC)) {
        $count++;
        var_dump($row);
        // echo "  - ID: {$row['id']}, Name: {$row['name']}, Email: {$row['email']}\n";
    }

With my relevant failing output being:

Querying data...
Results:
stmt_fetch: called
panic: runtime error: cgo result is unpinned Go pointer or points to unpinned Go pointer

goroutine 17 [running, locked to thread]:
panic({0x1049941e0?, 0x1400067c040?})
	runtime/panic.go:802 +0x150
runtime.cgoCheckArg(0x1048c8e20, 0x1400090a020, 0x89?, 0x0, {0x10428c7cf, 0x42})
	runtime/cgocall.go:708 +0x298
runtime.cgoCheckResult({0x1048c8e20, 0x1400090a020})
	runtime/cgocall.go:795 +0x58
_cgoexp_11bae6f8194b_stmt_fetch(0x1749765a0)
	_cgo_gotypes.go:835 +0x54
runtime.cgocallbackg1(0x103fe2450, 0x1749765a0, 0x0)
	runtime/cgocall.go:446 +0x240
runtime.cgocallbackg(0x103fe2450, 0x1749765a0, 0x0)
	runtime/cgocall.go:350 +0x104
runtime.cgocallbackg(0x103fe2450, 0x1749765a0, 0x0)
	<autogenerated>:1 +0x1c
runtime.cgocallback(0x0, 0x0, 0x0)
	runtime/asm_arm64.s:1180 +0xb0
runtime.goexit({})
	runtime/asm_arm64.s:1268 +0x4

Note that I originally had more params and such, but cut them all out to give a minimal replication.

Am I messing up my signature somewhere?

Build Type

Standalone binary

Worker Mode

No

Operating System

macOS

CPU Architecture

Apple Silicon

PHP configuration

Running `PHP 8.3.25` lemme know if you actually need the full phpinfo()

Relevant log output

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions