Coverage Report

Created: 2026-06-02 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/hash/hash_murmur.c
Line
Count
Source
1
/*
2
   +----------------------------------------------------------------------+
3
   | Copyright © The PHP Group and Contributors.                          |
4
   +----------------------------------------------------------------------+
5
   | This source file is subject to the Modified BSD License that is      |
6
   | bundled with this package in the file LICENSE, and is available      |
7
   | through the World Wide Web at <https://www.php.net/license/>.        |
8
   |                                                                      |
9
   | SPDX-License-Identifier: BSD-3-Clause                                |
10
   +----------------------------------------------------------------------+
11
   | Author: Anatol Belski <ab@php.net>                                   |
12
   +----------------------------------------------------------------------+
13
*/
14
15
#include "php_hash.h"
16
#include "php_hash_murmur.h"
17
18
#include "murmur/PMurHash.h"
19
#include "murmur/PMurHash128.h"
20
21
22
const php_hash_ops php_hash_murmur3a_ops = {
23
  "murmur3a",
24
  (php_hash_init_func_t) PHP_MURMUR3AInit,
25
  (php_hash_update_func_t) PHP_MURMUR3AUpdate,
26
  (php_hash_final_func_t) PHP_MURMUR3AFinal,
27
  (php_hash_copy_func_t) PHP_MURMUR3ACopy,
28
  php_hash_serialize,
29
  php_hash_unserialize,
30
  PHP_MURMUR3A_SPEC,
31
  4,
32
  4,
33
  sizeof(PHP_MURMUR3A_CTX),
34
  0
35
};
36
37
PHP_HASH_API void PHP_MURMUR3AInit(PHP_MURMUR3A_CTX *ctx, HashTable *args)
38
0
{
39
0
  if (args) {
40
0
    zval *seed = zend_hash_str_find_deref(args, "seed", sizeof("seed") - 1);
41
    /* This might be a bit too restrictive, but thinking that a seed might be set
42
      once and for all, it should be done a clean way. */
43
0
    if (seed) {
44
0
      if (IS_LONG == Z_TYPE_P(seed)) {
45
0
        ctx->h = (uint32_t) Z_LVAL_P(seed);
46
0
      } else {
47
0
        php_error_docref(NULL, E_DEPRECATED, "Passing a seed of a type other than int is deprecated because it is the same as setting the seed to 0");
48
0
        ctx->h = 0;
49
0
      }
50
0
    } else {
51
0
      ctx->h = 0;
52
0
    }
53
0
  } else {
54
0
    ctx->h = 0;
55
0
  }
56
0
  ctx->carry = 0;
57
0
  ctx->len = 0;
58
0
}
59
60
PHP_HASH_API void PHP_MURMUR3AUpdate(PHP_MURMUR3A_CTX *ctx, const unsigned char *in, size_t len)
61
0
{
62
0
  ctx->len += len;
63
0
  PMurHash32_Process(&ctx->h, &ctx->carry, in, len);
64
0
}
65
66
PHP_HASH_API void PHP_MURMUR3AFinal(unsigned char digest[4], PHP_MURMUR3A_CTX *ctx)
67
0
{
68
0
  ctx->h = PMurHash32_Result(ctx->h, ctx->carry, ctx->len);
69
70
0
  digest[0] = (unsigned char)((ctx->h >> 24) & 0xff);
71
0
  digest[1] = (unsigned char)((ctx->h >> 16) & 0xff);
72
0
  digest[2] = (unsigned char)((ctx->h >> 8) & 0xff);
73
0
  digest[3] = (unsigned char)(ctx->h & 0xff);
74
0
}
75
76
PHP_HASH_API zend_result PHP_MURMUR3ACopy(const php_hash_ops *ops, const PHP_MURMUR3A_CTX *orig_context, PHP_MURMUR3A_CTX *copy_context)
77
0
{
78
0
  copy_context->h = orig_context->h;
79
0
  copy_context->carry = orig_context->carry;
80
0
  copy_context->len = orig_context->len;
81
0
  return SUCCESS;
82
0
}
83
84
const php_hash_ops php_hash_murmur3c_ops = {
85
  "murmur3c",
86
  (php_hash_init_func_t) PHP_MURMUR3CInit,
87
  (php_hash_update_func_t) PHP_MURMUR3CUpdate,
88
  (php_hash_final_func_t) PHP_MURMUR3CFinal,
89
  (php_hash_copy_func_t) PHP_MURMUR3CCopy,
90
  php_hash_serialize,
91
  php_hash_unserialize,
92
  PHP_MURMUR3C_SPEC,
93
  16,
94
  4,
95
  sizeof(PHP_MURMUR3C_CTX),
96
  0
97
};
98
99
PHP_HASH_API void PHP_MURMUR3CInit(PHP_MURMUR3C_CTX *ctx, HashTable *args)
100
0
{
101
0
  if (args) {
102
0
    zval *seed = zend_hash_str_find_deref(args, "seed", sizeof("seed") - 1);
103
    /* This might be a bit too restrictive, but thinking that a seed might be set
104
      once and for all, it should be done a clean way. */
105
0
    if (seed) {
106
0
      if (IS_LONG == Z_TYPE_P(seed)) {
107
0
        uint32_t _seed = (uint32_t)Z_LVAL_P(seed);
108
0
        ctx->h[0] = _seed;
109
0
        ctx->h[1] = _seed;
110
0
        ctx->h[2] = _seed;
111
0
        ctx->h[3] = _seed;
112
0
      } else {
113
0
        php_error_docref(NULL, E_DEPRECATED, "Passing a seed of a type other than int is deprecated because it is the same as setting the seed to 0");
114
0
        memset(&ctx->h, 0, sizeof ctx->h);
115
0
      }
116
0
    } else {
117
0
      memset(&ctx->h, 0, sizeof ctx->h);
118
0
    }
119
0
  } else {
120
0
    memset(&ctx->h, 0, sizeof ctx->h);
121
0
  }
122
0
  memset(&ctx->carry, 0, sizeof ctx->carry);
123
0
  ctx->len = 0;
124
0
}
125
126
PHP_HASH_API void PHP_MURMUR3CUpdate(PHP_MURMUR3C_CTX *ctx, const unsigned char *in, size_t len)
127
0
{
128
0
  ctx->len += len;
129
0
  PMurHash128x86_Process(ctx->h, ctx->carry, in, len);
130
0
}
131
132
PHP_HASH_API void PHP_MURMUR3CFinal(unsigned char digest[16], PHP_MURMUR3C_CTX *ctx)
133
0
{
134
0
  uint32_t h[4] = {0, 0, 0, 0};
135
0
  PMurHash128x86_Result(ctx->h, ctx->carry, ctx->len, h);
136
137
0
  digest[0]  = (unsigned char)((h[0] >> 24) & 0xff);
138
0
  digest[1]  = (unsigned char)((h[0] >> 16) & 0xff);
139
0
  digest[2]  = (unsigned char)((h[0] >> 8) & 0xff);
140
0
  digest[3]  = (unsigned char)(h[0] & 0xff);
141
0
  digest[4]  = (unsigned char)((h[1] >> 24) & 0xff);
142
0
  digest[5]  = (unsigned char)((h[1] >> 16) & 0xff);
143
0
  digest[6]  = (unsigned char)((h[1] >> 8) & 0xff);
144
0
  digest[7]  = (unsigned char)(h[1] & 0xff);
145
0
  digest[8]  = (unsigned char)((h[2] >> 24) & 0xff);
146
0
  digest[9]  = (unsigned char)((h[2] >> 16) & 0xff);
147
0
  digest[10] = (unsigned char)((h[2] >> 8) & 0xff);
148
0
  digest[11] = (unsigned char)(h[2] & 0xff);
149
0
  digest[12] = (unsigned char)((h[3] >> 24) & 0xff);
150
0
  digest[13] = (unsigned char)((h[3] >> 16) & 0xff);
151
0
  digest[14] = (unsigned char)((h[3] >> 8) & 0xff);
152
0
  digest[15] = (unsigned char)(h[3] & 0xff);
153
0
}
154
155
PHP_HASH_API zend_result PHP_MURMUR3CCopy(const php_hash_ops *ops, const PHP_MURMUR3C_CTX *orig_context, PHP_MURMUR3C_CTX *copy_context)
156
0
{
157
0
  memcpy(&copy_context->h, &orig_context->h, sizeof orig_context->h);
158
0
  memcpy(&copy_context->carry, &orig_context->carry, sizeof orig_context->carry);
159
0
  copy_context->len = orig_context->len;
160
0
  return SUCCESS;
161
0
}
162
163
const php_hash_ops php_hash_murmur3f_ops = {
164
  "murmur3f",
165
  (php_hash_init_func_t) PHP_MURMUR3FInit,
166
  (php_hash_update_func_t) PHP_MURMUR3FUpdate,
167
  (php_hash_final_func_t) PHP_MURMUR3FFinal,
168
  (php_hash_copy_func_t) PHP_MURMUR3FCopy,
169
  php_hash_serialize,
170
  php_hash_unserialize,
171
  PHP_MURMUR3F_SPEC,
172
  16,
173
  8,
174
  sizeof(PHP_MURMUR3F_CTX),
175
  0
176
};
177
178
PHP_HASH_API void PHP_MURMUR3FInit(PHP_MURMUR3F_CTX *ctx, HashTable *args)
179
0
{
180
0
  if (args) {
181
0
    zval *seed = zend_hash_str_find_deref(args, "seed", sizeof("seed") - 1);
182
    /* This might be a bit too restrictive, but thinking that a seed might be set
183
      once and for all, it should be done a clean way. */
184
0
    if (seed) {
185
0
      if (IS_LONG == Z_TYPE_P(seed)) {
186
0
        uint64_t _seed = (uint64_t) Z_LVAL_P(seed);
187
0
        ctx->h[0] = _seed;
188
0
        ctx->h[1] = _seed;
189
0
      } else {
190
0
        php_error_docref(NULL, E_DEPRECATED, "Passing a seed of a type other than int is deprecated because it is the same as setting the seed to 0");
191
0
        memset(&ctx->h, 0, sizeof ctx->h);
192
0
      }
193
0
    } else {
194
0
      memset(&ctx->h, 0, sizeof ctx->h);
195
0
    }
196
0
  } else {
197
0
    memset(&ctx->h, 0, sizeof ctx->h);
198
0
  }
199
0
  memset(&ctx->carry, 0, sizeof ctx->carry);
200
0
  ctx->len = 0;
201
0
}
202
203
PHP_HASH_API void PHP_MURMUR3FUpdate(PHP_MURMUR3F_CTX *ctx, const unsigned char *in, size_t len)
204
0
{
205
0
  ctx->len += len;
206
0
  PMurHash128x64_Process(ctx->h, ctx->carry, in, len);
207
0
}
208
209
PHP_HASH_API void PHP_MURMUR3FFinal(unsigned char digest[16], PHP_MURMUR3F_CTX *ctx)
210
0
{
211
0
  uint64_t h[2] = {0, 0};
212
0
  PMurHash128x64_Result(ctx->h, ctx->carry, ctx->len, h);
213
214
0
  digest[0]  = (unsigned char)((h[0] >> 56) & 0xff);
215
0
  digest[1]  = (unsigned char)((h[0] >> 48) & 0xff);
216
0
  digest[2]  = (unsigned char)((h[0] >> 40) & 0xff);
217
0
  digest[3]  = (unsigned char)((h[0] >> 32) & 0xff);
218
0
  digest[4]  = (unsigned char)((h[0] >> 24) & 0xff);
219
0
  digest[5]  = (unsigned char)((h[0] >> 16) & 0xff);
220
0
  digest[6]  = (unsigned char)((h[0] >> 8) & 0xff);
221
0
  digest[7]  = (unsigned char)(h[0] & 0xff);
222
0
  digest[8]  = (unsigned char)((h[1] >> 56) & 0xff);
223
0
  digest[9]  = (unsigned char)((h[1] >> 48) & 0xff);
224
0
  digest[10] = (unsigned char)((h[1] >> 40) & 0xff);
225
0
  digest[11] = (unsigned char)((h[1] >> 32) & 0xff);
226
0
  digest[12] = (unsigned char)((h[1] >> 24) & 0xff);
227
0
  digest[13] = (unsigned char)((h[1] >> 16) & 0xff);
228
0
  digest[14] = (unsigned char)((h[1] >> 8) & 0xff);
229
0
  digest[15] = (unsigned char)(h[1] & 0xff);
230
0
}
231
232
PHP_HASH_API zend_result PHP_MURMUR3FCopy(const php_hash_ops *ops, const PHP_MURMUR3F_CTX *orig_context, PHP_MURMUR3F_CTX *copy_context)
233
0
{
234
0
  memcpy(&copy_context->h, &orig_context->h, sizeof orig_context->h);
235
0
  memcpy(&copy_context->carry, &orig_context->carry, sizeof orig_context->carry);
236
0
  copy_context->len = orig_context->len;
237
0
  return SUCCESS;
238
0
}