Coverage Report

Created: 2026-07-25 06:39

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
  0
36
};
37
38
PHP_HASH_API void PHP_MURMUR3AInit(PHP_MURMUR3A_CTX *ctx, HashTable *args)
39
21
{
40
21
  if (args) {
41
0
    zval *seed = zend_hash_str_find_deref(args, "seed", sizeof("seed") - 1);
42
    /* This might be a bit too restrictive, but thinking that a seed might be set
43
      once and for all, it should be done a clean way. */
44
0
    if (seed) {
45
0
      if (IS_LONG == Z_TYPE_P(seed)) {
46
0
        ctx->h = (uint32_t) Z_LVAL_P(seed);
47
0
      } else {
48
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");
49
0
        ctx->h = 0;
50
0
      }
51
0
    } else {
52
0
      ctx->h = 0;
53
0
    }
54
21
  } else {
55
21
    ctx->h = 0;
56
21
  }
57
21
  ctx->carry = 0;
58
21
  ctx->len = 0;
59
21
}
60
61
PHP_HASH_API void PHP_MURMUR3AUpdate(PHP_MURMUR3A_CTX *ctx, const unsigned char *in, size_t len)
62
19
{
63
19
  ctx->len += len;
64
19
  PMurHash32_Process(&ctx->h, &ctx->carry, in, len);
65
19
}
66
67
PHP_HASH_API void PHP_MURMUR3AFinal(unsigned char digest[4], PHP_MURMUR3A_CTX *ctx)
68
19
{
69
19
  ctx->h = PMurHash32_Result(ctx->h, ctx->carry, ctx->len);
70
71
19
  digest[0] = (unsigned char)((ctx->h >> 24) & 0xff);
72
19
  digest[1] = (unsigned char)((ctx->h >> 16) & 0xff);
73
19
  digest[2] = (unsigned char)((ctx->h >> 8) & 0xff);
74
19
  digest[3] = (unsigned char)(ctx->h & 0xff);
75
19
}
76
77
PHP_HASH_API zend_result PHP_MURMUR3ACopy(const php_hash_ops *ops, const PHP_MURMUR3A_CTX *orig_context, PHP_MURMUR3A_CTX *copy_context)
78
0
{
79
0
  copy_context->h = orig_context->h;
80
0
  copy_context->carry = orig_context->carry;
81
0
  copy_context->len = orig_context->len;
82
0
  return SUCCESS;
83
0
}
84
85
const php_hash_ops php_hash_murmur3c_ops = {
86
  "murmur3c",
87
  (php_hash_init_func_t) PHP_MURMUR3CInit,
88
  (php_hash_update_func_t) PHP_MURMUR3CUpdate,
89
  (php_hash_final_func_t) PHP_MURMUR3CFinal,
90
  (php_hash_copy_func_t) PHP_MURMUR3CCopy,
91
  php_hash_serialize,
92
  php_hash_unserialize,
93
  PHP_MURMUR3C_SPEC,
94
  16,
95
  4,
96
  sizeof(PHP_MURMUR3C_CTX),
97
  0,
98
  0
99
};
100
101
PHP_HASH_API void PHP_MURMUR3CInit(PHP_MURMUR3C_CTX *ctx, HashTable *args)
102
41
{
103
41
  if (args) {
104
0
    zval *seed = zend_hash_str_find_deref(args, "seed", sizeof("seed") - 1);
105
    /* This might be a bit too restrictive, but thinking that a seed might be set
106
      once and for all, it should be done a clean way. */
107
0
    if (seed) {
108
0
      if (IS_LONG == Z_TYPE_P(seed)) {
109
0
        uint32_t _seed = (uint32_t)Z_LVAL_P(seed);
110
0
        ctx->h[0] = _seed;
111
0
        ctx->h[1] = _seed;
112
0
        ctx->h[2] = _seed;
113
0
        ctx->h[3] = _seed;
114
0
      } else {
115
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");
116
0
        memset(&ctx->h, 0, sizeof ctx->h);
117
0
      }
118
0
    } else {
119
0
      memset(&ctx->h, 0, sizeof ctx->h);
120
0
    }
121
41
  } else {
122
41
    memset(&ctx->h, 0, sizeof ctx->h);
123
41
  }
124
41
  memset(&ctx->carry, 0, sizeof ctx->carry);
125
41
  ctx->len = 0;
126
41
}
127
128
PHP_HASH_API void PHP_MURMUR3CUpdate(PHP_MURMUR3C_CTX *ctx, const unsigned char *in, size_t len)
129
39
{
130
39
  ctx->len += len;
131
39
  PMurHash128x86_Process(ctx->h, ctx->carry, in, len);
132
39
}
133
134
PHP_HASH_API void PHP_MURMUR3CFinal(unsigned char digest[16], PHP_MURMUR3C_CTX *ctx)
135
39
{
136
39
  uint32_t h[4] = {0, 0, 0, 0};
137
39
  PMurHash128x86_Result(ctx->h, ctx->carry, ctx->len, h);
138
139
39
  digest[0]  = (unsigned char)((h[0] >> 24) & 0xff);
140
39
  digest[1]  = (unsigned char)((h[0] >> 16) & 0xff);
141
39
  digest[2]  = (unsigned char)((h[0] >> 8) & 0xff);
142
39
  digest[3]  = (unsigned char)(h[0] & 0xff);
143
39
  digest[4]  = (unsigned char)((h[1] >> 24) & 0xff);
144
39
  digest[5]  = (unsigned char)((h[1] >> 16) & 0xff);
145
39
  digest[6]  = (unsigned char)((h[1] >> 8) & 0xff);
146
39
  digest[7]  = (unsigned char)(h[1] & 0xff);
147
39
  digest[8]  = (unsigned char)((h[2] >> 24) & 0xff);
148
39
  digest[9]  = (unsigned char)((h[2] >> 16) & 0xff);
149
39
  digest[10] = (unsigned char)((h[2] >> 8) & 0xff);
150
39
  digest[11] = (unsigned char)(h[2] & 0xff);
151
39
  digest[12] = (unsigned char)((h[3] >> 24) & 0xff);
152
39
  digest[13] = (unsigned char)((h[3] >> 16) & 0xff);
153
39
  digest[14] = (unsigned char)((h[3] >> 8) & 0xff);
154
39
  digest[15] = (unsigned char)(h[3] & 0xff);
155
39
}
156
157
PHP_HASH_API zend_result PHP_MURMUR3CCopy(const php_hash_ops *ops, const PHP_MURMUR3C_CTX *orig_context, PHP_MURMUR3C_CTX *copy_context)
158
0
{
159
0
  memcpy(&copy_context->h, &orig_context->h, sizeof orig_context->h);
160
0
  memcpy(&copy_context->carry, &orig_context->carry, sizeof orig_context->carry);
161
0
  copy_context->len = orig_context->len;
162
0
  return SUCCESS;
163
0
}
164
165
const php_hash_ops php_hash_murmur3f_ops = {
166
  "murmur3f",
167
  (php_hash_init_func_t) PHP_MURMUR3FInit,
168
  (php_hash_update_func_t) PHP_MURMUR3FUpdate,
169
  (php_hash_final_func_t) PHP_MURMUR3FFinal,
170
  (php_hash_copy_func_t) PHP_MURMUR3FCopy,
171
  php_hash_serialize,
172
  php_hash_unserialize,
173
  PHP_MURMUR3F_SPEC,
174
  16,
175
  8,
176
  sizeof(PHP_MURMUR3F_CTX),
177
  0,
178
  0
179
};
180
181
PHP_HASH_API void PHP_MURMUR3FInit(PHP_MURMUR3F_CTX *ctx, HashTable *args)
182
29
{
183
29
  if (args) {
184
0
    zval *seed = zend_hash_str_find_deref(args, "seed", sizeof("seed") - 1);
185
    /* This might be a bit too restrictive, but thinking that a seed might be set
186
      once and for all, it should be done a clean way. */
187
0
    if (seed) {
188
0
      if (IS_LONG == Z_TYPE_P(seed)) {
189
0
        uint64_t _seed = (uint64_t) Z_LVAL_P(seed);
190
0
        ctx->h[0] = _seed;
191
0
        ctx->h[1] = _seed;
192
0
      } else {
193
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");
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
29
  } else {
200
29
    memset(&ctx->h, 0, sizeof ctx->h);
201
29
  }
202
29
  memset(&ctx->carry, 0, sizeof ctx->carry);
203
29
  ctx->len = 0;
204
29
}
205
206
PHP_HASH_API void PHP_MURMUR3FUpdate(PHP_MURMUR3F_CTX *ctx, const unsigned char *in, size_t len)
207
24
{
208
24
  ctx->len += len;
209
24
  PMurHash128x64_Process(ctx->h, ctx->carry, in, len);
210
24
}
211
212
PHP_HASH_API void PHP_MURMUR3FFinal(unsigned char digest[16], PHP_MURMUR3F_CTX *ctx)
213
24
{
214
24
  uint64_t h[2] = {0, 0};
215
24
  PMurHash128x64_Result(ctx->h, ctx->carry, ctx->len, h);
216
217
24
  digest[0]  = (unsigned char)((h[0] >> 56) & 0xff);
218
24
  digest[1]  = (unsigned char)((h[0] >> 48) & 0xff);
219
24
  digest[2]  = (unsigned char)((h[0] >> 40) & 0xff);
220
24
  digest[3]  = (unsigned char)((h[0] >> 32) & 0xff);
221
24
  digest[4]  = (unsigned char)((h[0] >> 24) & 0xff);
222
24
  digest[5]  = (unsigned char)((h[0] >> 16) & 0xff);
223
24
  digest[6]  = (unsigned char)((h[0] >> 8) & 0xff);
224
24
  digest[7]  = (unsigned char)(h[0] & 0xff);
225
24
  digest[8]  = (unsigned char)((h[1] >> 56) & 0xff);
226
24
  digest[9]  = (unsigned char)((h[1] >> 48) & 0xff);
227
24
  digest[10] = (unsigned char)((h[1] >> 40) & 0xff);
228
24
  digest[11] = (unsigned char)((h[1] >> 32) & 0xff);
229
24
  digest[12] = (unsigned char)((h[1] >> 24) & 0xff);
230
24
  digest[13] = (unsigned char)((h[1] >> 16) & 0xff);
231
24
  digest[14] = (unsigned char)((h[1] >> 8) & 0xff);
232
24
  digest[15] = (unsigned char)(h[1] & 0xff);
233
24
}
234
235
PHP_HASH_API zend_result PHP_MURMUR3FCopy(const php_hash_ops *ops, const PHP_MURMUR3F_CTX *orig_context, PHP_MURMUR3F_CTX *copy_context)
236
0
{
237
0
  memcpy(&copy_context->h, &orig_context->h, sizeof orig_context->h);
238
0
  memcpy(&copy_context->carry, &orig_context->carry, sizeof orig_context->carry);
239
0
  copy_context->len = orig_context->len;
240
0
  return SUCCESS;
241
0
}