【问题标题】:PHP extension: why int var changes to 0?PHP 扩展:为什么 int var 变为 0?
【发布时间】:2019-09-20 00:27:37
【问题描述】:

我正在 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 Version 7.2.17-1, PHP CLI 为 PHP 7.2.2 (cli) (build: Apr 29 2019 09:57:40) (ZTS DEBUG)

我注意到有问题的代码,如果我注释以下代码 frpm 第三个 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;
      }

【问题讨论】:

  • 我对C一无所知,但这行只是设置默认值吗? int ssh_port = 0, remote_port = 0, local_port = 0, to_close_tunnel = 0, thread_is_runnning = 0, is_authenticated = 0;
  • 我也不是 C 方面的专家。这就是我在这里问的原因。我猜是的 - 它应该用 int 类型定义变量并设置 0 值

标签: php c php-extension


【解决方案1】:

其实,我认为你有一个未定义的行为。

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

根据C Standard

6.8.6.4 返回语句

约束

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

6.9.1 函数定义

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

因此,在您的情况下,zend_parse_parameters 返回 FAILURE,然后将其转换为“在到达关闭 { 之前结束,这就是为什么永远不会返回 ssh_port 的值。

zend_parse_parameters 失败的原因是因为其中一个参数未初始化为不同于 0

【讨论】:

  • 感谢您的回答,但我刚刚检查过,zend_parse_parameters - 没有失败
  • 我刚看到你的编辑。如果您注释了代码并显示了ssh_port 的正确值,这并不意味着注释的if 子句通过调用return;var_dump 使函数提前返回以显示return; 给出的内容碰巧是0?
  • 你知道,这不是事实。我确信 zend_parse_parameters 是成功的,它不会进入 if(zend_parse_parameters) 块。我认为它确实出于某种原因将 0 设置为 ssh_port 变量
  • 我还注意到 remote_port 也有 0 值。但是 local_port 得到了正确的值
猜你喜欢
  • 2013-04-06
  • 1970-01-01
  • 1970-01-01
  • 2015-11-07
  • 1970-01-01
  • 1970-01-01
  • 2016-07-28
  • 2017-06-10
相关资源
最近更新 更多