PHP扩展:为什么int变量会变成0?

3

我正在开发一些关于C的PHP扩展。在C代码的顶部,我定义了几个函数和几个变量(char和int)全局变量。在php侧,我调用第一个函数并传递ssh_port参数的一些值-22。这个值被设置为全局变量。然后我调用第二个函数。但是当我调用第三个函数时,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)

我注意到有问题的代码,如果我从第三个super_ssh_open_tunnel函数中注释以下代码-它可以工作。

注释此代码使其工作,即使没有此代码,ssh_port变量中仍然有22

 if (zend_parse_parameters(
        ZEND_NUM_ARGS(),
        "sll",
        &remote_host,
        &remote_host_len,
        &remote_port,
        &local_port
      ) == FAILURE) {
          return;
      }

我对C语言一无所知,但这行代码只是设置默认值吗?int ssh_port = 0, remote_port = 0, local_port = 0, to_close_tunnel = 0, thread_is_runnning = 0, is_authenticated = 0; - SpacePhoenix
我也不是C语言专家,这就是为什么我在这里提问的原因。我猜应该使用int类型定义变量并将其设置为0。 - Mikael
1个回答

0

实际上,我认为你遇到了未定义的行为。

首先,PHP_FUNCTION被扩展为void zif_FUNCNAME(zend_execute_data *execute_data, zval *return_value)

根据C标准

6.8.6.4 返回语句

约束条件

  1. 带有表达式的返回语句不得出现在返回类型为void的函数中。不带表达式的返回语句只能出现在返回类型为void的函数中。

6.9.1 函数定义

  1. 如果到达终止函数的},并且函数调用的值由调用者使用,则行为未定义。

因此,在您的情况下,zend_parse_parameters返回FAILURE,然后被转换为“在未到达闭合{之前结束”,这就是为什么ssh_port的值从未返回的原因。

原因是zend_parse_parameters失败是因为其中一个参数未初始化而不是0。

谢谢您的回答,但我刚刚检查了一下,zend_parse_parameters不会失败。 - Mikael
我刚看到了你的编辑。如果你对代码进行了注释,并且正确的ssh_port值被显示出来,这是否意味着if语句块中的注释使得函数通过调用return;提前返回,而var_dump则显示了return;所给出的结果,这恰好是0? - bogdan tudose
你知道的,这不是事实。我确信zend_parse_parameters成功了,并且它没有进入if(zend_parse_parameters)块。我认为真正的原因是它将0设置为ssh_port变量。 - Mikael
我还注意到remote_port的值也为0。但是local_port的值是正确的。 - Mikael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接