我正在C上开发一些PHP扩展。在C代码的顶部全局定义了几个函数和几个变量(char和int)。在php端,我调用第一个函数并为ssh_port参数传递一些值-22。该值设置为global var。然后我调用第二个函数。但是,当我调用第三个函数时,ssh_port变量突然变为0值?为什么呢代码如下:
#include <php.h>
#include "super_ssh.h"
#include <libssh2.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <pthread.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifndef INADDR_NONE
#define INADDR_NONE (in_addr_t)-1
#endif
char *ssh_ip, *ssh_username, *ssh_password, *remote_host, *last_error = "";
size_t ssh_ip_len, ssh_username_len, ssh_password_len, remote_host_len;
int ssh_port = 0, remote_port = 0, local_port = 0, to_close_tunnel = 0, thread_is_runnning = 0, is_authenticated = 0;
PHP_FUNCTION(super_ssh_connect) {
if (zend_parse_parameters(
ZEND_NUM_ARGS(),
"sl",
&ssh_ip,
&ssh_ip_len,
&ssh_port
) == FAILURE) {
return;
}
RETURN_LONG(ssh_port);
}
PHP_FUNCTION(super_ssh_authenticate) {
if (zend_parse_parameters(
ZEND_NUM_ARGS(),
"ss",
&ssh_username,
&ssh_username_len,
&ssh_password,
&ssh_password_len
) == FAILURE) {
return;
}
RETURN_LONG(ssh_port);
}
PHP_FUNCTION(super_ssh_open_tunnel) {
if (zend_parse_parameters(
ZEND_NUM_ARGS(),
"sll",
&remote_host,
&remote_host_len,
&remote_port,
&local_port
) == FAILURE) {
return;
}
RETURN_LONG(ssh_port);
}
ZEND_BEGIN_ARG_INFO_EX(arginfo_super_ssh_connect, 0, 0, 2)
ZEND_ARG_INFO(0, ssh_ip)
ZEND_ARG_INFO(0, ssh_port)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_super_ssh_authenticate, 0, 0, 2)
ZEND_ARG_INFO(0, ssh_username)
ZEND_ARG_INFO(0, ssh_password)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_super_ssh_open_tunnel, 0, 0, 3)
ZEND_ARG_INFO(0, remote_host)
ZEND_ARG_INFO(0, remote_port)
ZEND_ARG_INFO(0, local_port)
ZEND_END_ARG_INFO()
zend_function_entry super_ssh_functions[] = {
PHP_FE(super_ssh_connect, arginfo_super_ssh_connect)
PHP_FE(super_ssh_authenticate, arginfo_super_ssh_authenticate)
PHP_FE(super_ssh_open_tunnel, arginfo_super_ssh_open_tunnel)
PHP_FE_END
};
zend_module_entry super_ssh_module_entry = {
STANDARD_MODULE_HEADER,
PHP_SUPER_SSH_EXTNAME,
super_ssh_functions,
NULL,
PHP_MSHUTDOWN(super_ssh),
NULL,
NULL,
NULL,
PHP_SUPER_SSH_VERSION,
STANDARD_MODULE_PROPERTIES,
};
ZEND_GET_MODULE(super_ssh);
以及PHP端的代码:
<?php
var_dump(super_ssh_connect("234.43.23.3", 22));
var_dump(super_ssh_authenticate("dfds", "mofsdfdsnitor"));
var_dump(super_ssh_open_tunnel("server", 993, 4444));
实际结果是:
int(22)int(22)int(0)
预期结果是:
int(22)int(22)int(22)
所以问题是为什么ssh_port变量得到0值?我没有在任何地方设置它!真的听不懂:(
有趣的是,该问题对于Apache php来说是实际的。因此,当我从浏览器运行脚本时,就会发生这种情况。 (apache2 + php)
如果我尝试对PHP CLI进行相同的编译,并且可以按预期工作,则输出为:
int(22)int(22)int(22)
可能与垃圾收集器有某种联系吗?也许您只是可以为我的代码提出更好的方法来使用变量?
我的环境:
Ubuntu 18.04.1 LTS,apache2 + PHP版本7.2.17-1和PHP CLI是PHP 7.2.2(cli)(内置:2019年4月29日09:57:40)(ZTS DEBUG)
我注意到有问题的代码,如果我在fsuper第三个super_ssh_open_tunnel函数中注释以下代码,则它起作用。
注释此代码使其工作,没有此代码,我在ssh_port var中仍然有22
if (zend_parse_parameters(
ZEND_NUM_ARGS(),
"sll",
&remote_host,
&remote_host_len,
&remote_port,
&local_port
) == FAILURE) {
return;
}
答案 0 :(得分:0)
实际上,我认为您的行为是不确定的。
首先将PHP_FUNCTION
扩展为void zif_FUNCNAME(zend_execute_data *execute_data, zval *return_value)
。
根据C Standard:
6.8.6.4返回语句
约束
- 带有表达式的return语句不得出现在其返回类型为void的函数中。没有表达式的return语句只能出现在返回类型为void的函数中。
6.9.1函数定义
- 如果到达终止函数的},并且调用者使用了函数调用的值,则该行为未定义。
因此,在您的情况下,zend_parse_parameters
返回FAILURE
,然后将其转换为“在结束{
之前结束”,因此这就是从未返回ssh_port
的原因。
zend_parse_parameters
失败的原因是,其中一个参数未初始化为不同于0的参数