Расширение PHP: почему int var меняется на 0? - PullRequest
3 голосов
/ 01 мая 2019

Я занимаюсь разработкой PHP-расширения на C. У меня мало функций и несколько переменных (char и int), определенных глобально в верхней части кода C. На стороне 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) (сборка: 29 апреля 2019 09:57:40) (ZTS DEBUG)

Я заметил проблемный код, если я прокомментирую следующий код для третьей функции super_ssh_open_tunnel - она ​​работает.

Комментируя этот код, он работает, без этого кода у меня все еще есть 22 в ssh_port var

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

1 Ответ

0 голосов
/ 01 мая 2019

На самом деле, я думаю, что у вас есть неопределенное поведение.

Сначала PHP_FUNCTION расширяется до void zif_FUNCNAME(zend_execute_data *execute_data, zval *return_value).

Согласно C Standard :

6.8.6.4.оператор возврата

Ограничения

  1. Оператор возврата с выражением не должен появляться в функции, тип возвращаемого значения void.Оператор возврата без выражения должен появляться только в функции, тип возврата которой равен void.

6.9.1 Определения функций

Если}, завершающий функцию, достигнут, и вызывающая сторона использует значение вызова функции, поведение не определено.

Итак, в вашем случае zend_parse_parameters возвращает FAILURE, что затем переводится в "окончание до достижения закрытия {, поэтому значение ssh_port никогда не возвращается.

Причина сбоя zend_parse_parameters заключается в том, что один изаргументы не инициализируются отличными от 0

...