summaryrefslogtreecommitdiff
path: root/src/sp_sloppy.c
blob: f9ed7183693b66d114871a19b18f9ed4b17eaf4c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "php_snuffleupagus.h"

ZEND_API zend_op_array* (*orig_zend_compile_file)(zend_file_handle* file_handle,
                                                  int type) = NULL;
#if PHP_VERSION_ID >= 80000
ZEND_API zend_op_array* (*orig_zend_compile_string)(
    zend_string* source_string, const char* filename) = NULL;
#else
ZEND_API zend_op_array* (*orig_zend_compile_string)(zval* source_string,
                                                    char* filename) = NULL;
#endif

static void modify_opcode(zend_op_array* opline) {
  if (NULL != opline) {
    for (size_t i = 0; i < opline->last; i++) {
      zend_op* orig_opline = &(opline->opcodes[i]);
      if (orig_opline->opcode == ZEND_IS_EQUAL) {
        orig_opline->opcode = ZEND_IS_IDENTICAL;
        zend_vm_set_opcode_handler(orig_opline);
      } else if (orig_opline->opcode == ZEND_IS_NOT_EQUAL) {
        orig_opline->opcode = ZEND_IS_NOT_IDENTICAL;
        zend_vm_set_opcode_handler(orig_opline);
      }
    }
  }
}

#if PHP_VERSION_ID >= 80000
ZEND_API zend_op_array* sp_compile_string(zend_string* source_string,
                                          const char* filename) {
#else
ZEND_API zend_op_array* sp_compile_string(zval* source_string, char* filename) {
#endif
  zend_op_array* opline = orig_zend_compile_string(source_string, filename);
  modify_opcode(opline);
  return opline;
}

ZEND_API zend_op_array* sp_compile_file(zend_file_handle* file_handle,
                                        int type) {
  zend_op_array* opline = orig_zend_compile_file(file_handle, type);
  modify_opcode(opline);
  return opline;
}

static void array_handler(INTERNAL_FUNCTION_PARAMETERS, const char* name,
                          size_t size, zif_handler orig_handler,
                          const char* spec) {
  zif_handler handler;
  zval func_name;
  zval params[3];
  zval *value, *array = NULL;
  zend_bool strict = 0;
  uint32_t nb_params = ZEND_NUM_ARGS();

  zend_parse_parameters(nb_params, spec, &value, &array, &strict);

  ZVAL_COPY(&params[0], value);
  ZVAL_BOOL(&params[2], 1);  // we want to always have strict mode enabled

  if (array) {
    ZVAL_COPY(&params[1], array);
    // Lie about the number of parameters,
    // since we are always passing strict = 1
    nb_params = 3;
  } else {
    ZVAL_NULL(&params[1]);
  }

  ZVAL_STRING(&func_name, name);

  handler = zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook),
                                   name, size);
  zend_internal_function* func =
      zend_hash_str_find_ptr(CG(function_table), name, size);
  func->handler = handler;

  call_user_function(CG(function_table), NULL, &func_name, return_value,
                     nb_params, params);

  func->handler = orig_handler;
}

PHP_FUNCTION(sp_in_array) {
  array_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, "in_array",
                sizeof("in_array") - 1, PHP_FN(sp_in_array), "zz|b");
}

PHP_FUNCTION(sp_array_search) {
  array_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, "array_search",
                sizeof("array_search") - 1, PHP_FN(sp_array_search), "zz|b");
}

PHP_FUNCTION(sp_array_keys) {
  array_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, "array_keys",
                sizeof("array_keys") - 1, PHP_FN(sp_array_keys), "z|zb");
}

void hook_sloppy() {
  TSRMLS_FETCH();

  if (NULL == orig_zend_compile_file) {
    orig_zend_compile_file = zend_compile_file;
    zend_compile_file = sp_compile_file;
  }

  if (NULL == orig_zend_compile_string) {
    orig_zend_compile_string = zend_compile_string;
    zend_compile_string = sp_compile_string;
  }

  HOOK_FUNCTION("in_array", sp_internal_functions_hook, PHP_FN(sp_in_array));
  HOOK_FUNCTION("array_search", sp_internal_functions_hook,
                PHP_FN(sp_array_search));
  HOOK_FUNCTION("array_keys", sp_internal_functions_hook,
                PHP_FN(sp_array_keys));
}