|
26 | 26 |
|
27 | 27 | #include "Zend/zend_enum.h"
|
28 | 28 | #include "Zend/zend_exceptions.h"
|
| 29 | +#include "zend_portability.h" |
29 | 30 |
|
30 | 31 | static inline void randomizer_common_init(php_random_randomizer *randomizer, zend_object *engine_object) {
|
31 | 32 | if (engine_object->ce->type == ZEND_INTERNAL_CLASS) {
|
@@ -292,14 +293,48 @@ PHP_METHOD(Random_Randomizer, getBytes)
|
292 | 293 | size_t length = (size_t)user_length;
|
293 | 294 | retval = zend_string_alloc(length, 0);
|
294 | 295 |
|
| 296 | + php_random_result result; |
| 297 | + while (total_size + 8 <= length) { |
| 298 | + result = engine.algo->generate(engine.state); |
| 299 | + if (EG(exception)) { |
| 300 | + zend_string_free(retval); |
| 301 | + RETURN_THROWS(); |
| 302 | + } |
| 303 | + |
| 304 | + /* If the result is not 64 bits, we can't use the fast path and |
| 305 | + * we don't attempt to use it in the future, because we don't |
| 306 | + * expect engines to change their output size. |
| 307 | + * |
| 308 | + * While it would be possible to always memcpy() the entire output, |
| 309 | + * using result.size as the length that would result in much worse |
| 310 | + * assembly, because it will actually emit a call to memcpy() |
| 311 | + * instead of just storing the 64 bit value at a memory offset. |
| 312 | + */ |
| 313 | + if (result.size != 8) { |
| 314 | + goto non_64; |
| 315 | + } |
| 316 | + |
| 317 | +#ifdef WORDS_BIGENDIAN |
| 318 | + uint64_t swapped = ZEND_BYTES_SWAP64(result.result); |
| 319 | + memcpy(ZSTR_VAL(retval) + total_size, &swapped, 8); |
| 320 | +#else |
| 321 | + memcpy(ZSTR_VAL(retval) + total_size, &result.result, 8); |
| 322 | +#endif |
| 323 | + total_size += 8; |
| 324 | + } |
| 325 | + |
295 | 326 | while (total_size < length) {
|
296 |
| - php_random_result result = engine.algo->generate(engine.state); |
| 327 | + result = engine.algo->generate(engine.state); |
297 | 328 | if (EG(exception)) {
|
298 | 329 | zend_string_free(retval);
|
299 | 330 | RETURN_THROWS();
|
300 | 331 | }
|
| 332 | + |
| 333 | + non_64: |
| 334 | + |
301 | 335 | for (size_t i = 0; i < result.size; i++) {
|
302 |
| - ZSTR_VAL(retval)[total_size++] = (result.result >> (i * 8)) & 0xff; |
| 336 | + ZSTR_VAL(retval)[total_size++] = result.result & 0xff; |
| 337 | + result.result >>= 8; |
303 | 338 | if (total_size >= length) {
|
304 | 339 | break;
|
305 | 340 | }
|
|
0 commit comments