@@ -369,13 +369,11 @@ PHP_FUNCTION(spl_autoload_extensions)
369
369
typedef struct {
370
370
zend_function * func_ptr ;
371
371
zend_object * obj ;
372
- zval closure ;
372
+ zend_object * closure ;
373
373
zend_class_entry * ce ;
374
374
} autoload_func_info ;
375
375
376
- static void autoload_func_info_dtor (zval * element )
377
- {
378
- autoload_func_info * alfi = (autoload_func_info * )Z_PTR_P (element );
376
+ static void autoload_func_info_destroy (autoload_func_info * alfi ) {
379
377
if (alfi -> obj ) {
380
378
zend_object_release (alfi -> obj );
381
379
}
@@ -384,12 +382,43 @@ static void autoload_func_info_dtor(zval *element)
384
382
zend_string_release_ex (alfi -> func_ptr -> common .function_name , 0 );
385
383
zend_free_trampoline (alfi -> func_ptr );
386
384
}
387
- if (! Z_ISUNDEF ( alfi -> closure ) ) {
388
- zval_ptr_dtor ( & alfi -> closure );
385
+ if (alfi -> closure ) {
386
+ zend_object_release ( alfi -> closure );
389
387
}
390
388
efree (alfi );
391
389
}
392
390
391
+ static void autoload_func_info_zval_dtor (zval * element )
392
+ {
393
+ autoload_func_info_destroy (Z_PTR_P (element ));
394
+ }
395
+
396
+ static autoload_func_info * autoload_func_info_from_fci (
397
+ zend_fcall_info * fci , zend_fcall_info_cache * fcc ) {
398
+ autoload_func_info * alfi = emalloc (sizeof (autoload_func_info ));
399
+ alfi -> ce = fcc -> calling_scope ;
400
+ alfi -> func_ptr = fcc -> function_handler ;
401
+ alfi -> obj = fcc -> object ;
402
+ if (alfi -> obj ) {
403
+ GC_ADDREF (alfi -> obj );
404
+ }
405
+ if (Z_TYPE (fci -> function_name ) == IS_OBJECT ) {
406
+ alfi -> closure = Z_OBJ (fci -> function_name );
407
+ GC_ADDREF (alfi -> closure );
408
+ } else {
409
+ alfi -> closure = NULL ;
410
+ }
411
+ return alfi ;
412
+ }
413
+
414
+ static zend_bool autoload_func_info_equals (
415
+ const autoload_func_info * alfi1 , const autoload_func_info * alfi2 ) {
416
+ return alfi1 -> func_ptr == alfi2 -> func_ptr
417
+ && alfi1 -> obj == alfi2 -> obj
418
+ && alfi1 -> ce == alfi2 -> ce
419
+ && alfi1 -> closure == alfi2 -> closure ;
420
+ }
421
+
393
422
static zend_class_entry * spl_perform_autoload (zend_string * class_name , zend_string * lc_name ) {
394
423
if (!SPL_G (autoload_functions )) {
395
424
return NULL ;
@@ -454,17 +483,29 @@ PHP_FUNCTION(spl_autoload_call)
454
483
zend_hash_rehash(ht); \
455
484
} while (0)
456
485
486
+ static Bucket * spl_find_registered_function (autoload_func_info * find_alfi ) {
487
+ if (!SPL_G (autoload_functions )) {
488
+ return NULL ;
489
+ }
490
+
491
+ autoload_func_info * alfi ;
492
+ ZEND_HASH_FOREACH_PTR (SPL_G (autoload_functions ), alfi ) {
493
+ if (autoload_func_info_equals (alfi , find_alfi )) {
494
+ return _p ;
495
+ }
496
+ } ZEND_HASH_FOREACH_END ();
497
+ return NULL ;
498
+ }
499
+
457
500
/* {{{ proto bool spl_autoload_register([mixed autoload_function [, bool throw [, bool prepend]]])
458
501
Register given function as autoloader */
459
502
PHP_FUNCTION (spl_autoload_register )
460
503
{
461
- zend_string * func_name ;
462
- zend_string * lc_name ;
463
504
zend_bool do_throw = 1 ;
464
505
zend_bool prepend = 0 ;
465
- autoload_func_info alfi ;
466
506
zend_fcall_info fci = {0 };
467
507
zend_fcall_info_cache fcc ;
508
+ autoload_func_info * alfi ;
468
509
469
510
ZEND_PARSE_PARAMETERS_START (0 , 3 )
470
511
Z_PARAM_OPTIONAL
@@ -480,94 +521,45 @@ PHP_FUNCTION(spl_autoload_register)
480
521
481
522
if (!SPL_G (autoload_functions )) {
482
523
ALLOC_HASHTABLE (SPL_G (autoload_functions ));
483
- zend_hash_init (SPL_G (autoload_functions ), 1 , NULL , autoload_func_info_dtor , 0 );
524
+ zend_hash_init (SPL_G (autoload_functions ), 1 , NULL , autoload_func_info_zval_dtor , 0 );
525
+ /* Initialize as non-packed hash table for prepend functionality. */
526
+ zend_hash_real_init_mixed (SPL_G (autoload_functions ));
484
527
}
485
528
486
529
/* If first arg is not null */
487
530
if (ZEND_FCI_INITIALIZED (fci )) {
488
- alfi .ce = fcc .calling_scope ;
489
- alfi .func_ptr = fcc .function_handler ;
490
- alfi .obj = !(alfi .func_ptr -> common .fn_flags & ZEND_ACC_STATIC ) ? fcc .object : NULL ;
491
-
492
531
if (fcc .function_handler -> type == ZEND_INTERNAL_FUNCTION &&
493
532
fcc .function_handler -> internal_function .handler == zif_spl_autoload_call ) {
494
533
zend_argument_value_error (1 , "must not be the spl_autoload_call() function" );
495
534
RETURN_THROWS ();
496
535
}
497
536
498
- /* fci.function_name contains the callable zval */
499
- func_name = zend_get_callable_name (& fci .function_name );
500
- if (Z_TYPE (fci .function_name ) == IS_OBJECT ) {
501
- ZVAL_COPY (& alfi .closure , & fci .function_name );
502
- lc_name = zend_string_alloc (ZSTR_LEN (func_name ) + sizeof (uint32_t ), 0 );
503
- zend_str_tolower_copy (ZSTR_VAL (lc_name ), ZSTR_VAL (func_name ), ZSTR_LEN (func_name ));
504
- memcpy (ZSTR_VAL (lc_name ) + ZSTR_LEN (func_name ), & Z_OBJ_HANDLE (fci .function_name ), sizeof (uint32_t ));
505
- ZSTR_VAL (lc_name )[ZSTR_LEN (lc_name )] = '\0' ;
506
- } else {
507
- ZVAL_UNDEF (& alfi .closure );
508
- /* Skip leading \ */
509
- if (ZSTR_VAL (func_name )[0 ] == '\\' ) {
510
- lc_name = zend_string_alloc (ZSTR_LEN (func_name ) - 1 , 0 );
511
- zend_str_tolower_copy (ZSTR_VAL (lc_name ), ZSTR_VAL (func_name ) + 1 , ZSTR_LEN (func_name ) - 1 );
512
- } else {
513
- lc_name = zend_string_tolower (func_name );
514
- }
515
- }
516
- zend_string_release (func_name );
517
-
518
- if (zend_hash_exists (SPL_G (autoload_functions ), lc_name )) {
519
- if (!Z_ISUNDEF (alfi .closure )) {
520
- Z_DELREF_P (& alfi .closure );
521
- }
522
- goto skip ;
523
- }
524
-
525
- if (alfi .obj ) {
526
- /* add object id to the hash to ensure uniqueness, for more reference look at bug #40091 */
527
- lc_name = zend_string_extend (lc_name , ZSTR_LEN (lc_name ) + sizeof (uint32_t ), 0 );
528
- memcpy (ZSTR_VAL (lc_name ) + ZSTR_LEN (lc_name ) - sizeof (uint32_t ), & alfi .obj -> handle , sizeof (uint32_t ));
529
- ZSTR_VAL (lc_name )[ZSTR_LEN (lc_name )] = '\0' ;
530
- GC_ADDREF (alfi .obj );
531
- }
532
-
533
- if (UNEXPECTED (alfi .func_ptr == & EG (trampoline ))) {
537
+ alfi = autoload_func_info_from_fci (& fci , & fcc );
538
+ if (UNEXPECTED (alfi -> func_ptr == & EG (trampoline ))) {
534
539
zend_function * copy = emalloc (sizeof (zend_op_array ));
535
540
536
- memcpy (copy , alfi .func_ptr , sizeof (zend_op_array ));
537
- alfi .func_ptr -> common .function_name = NULL ;
538
- alfi .func_ptr = copy ;
539
- }
540
- if (zend_hash_add_mem (SPL_G (autoload_functions ), lc_name , & alfi , sizeof (autoload_func_info )) == NULL ) {
541
- if (alfi .obj && !(alfi .func_ptr -> common .fn_flags & ZEND_ACC_STATIC )) {
542
- GC_DELREF (alfi .obj );
543
- }
544
- if (!Z_ISUNDEF (alfi .closure )) {
545
- Z_DELREF (alfi .closure );
546
- }
547
- if (UNEXPECTED (alfi .func_ptr -> common .fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE )) {
548
- zend_string_release_ex (alfi .func_ptr -> common .function_name , 0 );
549
- zend_free_trampoline (alfi .func_ptr );
550
- }
551
- }
552
- if (prepend && SPL_G (autoload_functions )-> nNumOfElements > 1 ) {
553
- /* Move the newly created element to the head of the hashtable */
554
- HT_MOVE_TAIL_TO_HEAD (SPL_G (autoload_functions ));
541
+ memcpy (copy , alfi -> func_ptr , sizeof (zend_op_array ));
542
+ alfi -> func_ptr -> common .function_name = NULL ;
543
+ alfi -> func_ptr = copy ;
555
544
}
556
- skip :
557
- zend_string_release_ex (lc_name , 0 );
558
545
} else {
559
- autoload_func_info spl_alfi ;
560
- spl_alfi . func_ptr = zend_hash_str_find_ptr (
546
+ alfi = emalloc ( sizeof ( autoload_func_info )) ;
547
+ alfi -> func_ptr = zend_hash_str_find_ptr (
561
548
CG (function_table ), "spl_autoload" , sizeof ("spl_autoload" ) - 1 );
562
- spl_alfi .obj = NULL ;
563
- spl_alfi .ce = NULL ;
564
- ZVAL_UNDEF (& spl_alfi .closure );
565
- zend_hash_add_mem (SPL_G (autoload_functions ), spl_alfi .func_ptr -> common .function_name ,
566
- & spl_alfi , sizeof (autoload_func_info ));
567
- if (prepend && SPL_G (autoload_functions )-> nNumOfElements > 1 ) {
568
- /* Move the newly created element to the head of the hashtable */
569
- HT_MOVE_TAIL_TO_HEAD (SPL_G (autoload_functions ));
570
- }
549
+ alfi -> obj = NULL ;
550
+ alfi -> ce = NULL ;
551
+ alfi -> closure = NULL ;
552
+ }
553
+
554
+ if (spl_find_registered_function (alfi )) {
555
+ autoload_func_info_destroy (alfi );
556
+ RETURN_TRUE ;
557
+ }
558
+
559
+ zend_hash_next_index_insert_ptr (SPL_G (autoload_functions ), alfi );
560
+ if (prepend && SPL_G (autoload_functions )-> nNumOfElements > 1 ) {
561
+ /* Move the newly created element to the head of the hashtable */
562
+ HT_MOVE_TAIL_TO_HEAD (SPL_G (autoload_functions ));
571
563
}
572
564
573
565
RETURN_TRUE ;
@@ -577,68 +569,29 @@ PHP_FUNCTION(spl_autoload_register)
577
569
Unregister given function as autoloader */
578
570
PHP_FUNCTION (spl_autoload_unregister )
579
571
{
580
- zend_string * func_name = NULL ;
581
- char * error = NULL ;
582
- zend_string * lc_name ;
583
- zval * zcallable ;
584
- int success = FAILURE ;
585
- zend_object * obj_ptr ;
572
+ zend_fcall_info fci ;
586
573
zend_fcall_info_cache fcc ;
587
574
588
- if (zend_parse_parameters (ZEND_NUM_ARGS (), "z " , & zcallable ) == FAILURE ) {
575
+ if (zend_parse_parameters (ZEND_NUM_ARGS (), "f " , & fci , & fcc ) == FAILURE ) {
589
576
RETURN_THROWS ();
590
577
}
591
578
592
- if (!zend_is_callable_ex (zcallable , NULL , IS_CALLABLE_CHECK_SYNTAX_ONLY , & func_name , & fcc , & error )) {
593
- zend_throw_exception_ex (spl_ce_LogicException , 0 , "Unable to unregister invalid function (%s)" , error );
594
- if (error ) {
595
- efree (error );
596
- }
597
- if (func_name ) {
598
- zend_string_release_ex (func_name , 0 );
599
- }
600
- RETURN_FALSE ;
601
- }
602
- obj_ptr = fcc .object ;
603
- if (error ) {
604
- efree (error );
605
- }
606
-
607
- if (Z_TYPE_P (zcallable ) == IS_OBJECT ) {
608
- lc_name = zend_string_alloc (ZSTR_LEN (func_name ) + sizeof (uint32_t ), 0 );
609
- zend_str_tolower_copy (ZSTR_VAL (lc_name ), ZSTR_VAL (func_name ), ZSTR_LEN (func_name ));
610
- memcpy (ZSTR_VAL (lc_name ) + ZSTR_LEN (func_name ), & Z_OBJ_HANDLE_P (zcallable ), sizeof (uint32_t ));
611
- ZSTR_VAL (lc_name )[ZSTR_LEN (lc_name )] = '\0' ;
612
- } else {
613
- /* Skip leading \ */
614
- if (ZSTR_VAL (func_name )[0 ] == '\\' ) {
615
- lc_name = zend_string_alloc (ZSTR_LEN (func_name ) - 1 , 0 );
616
- zend_str_tolower_copy (ZSTR_VAL (lc_name ), ZSTR_VAL (func_name ) + 1 , ZSTR_LEN (func_name ) - 1 );
617
- } else {
618
- lc_name = zend_string_tolower (func_name );
619
- }
579
+ if (zend_string_equals_literal (
580
+ fcc .function_handler -> common .function_name , "spl_autoload_call" )) {
581
+ /* Don't destroy the hash table, as we might be iterating over it right now. */
582
+ zend_hash_clean (SPL_G (autoload_functions ));
583
+ RETURN_TRUE ;
620
584
}
621
- zend_string_release_ex (func_name , 0 );
622
585
623
- if (SPL_G (autoload_functions )) {
624
- if (zend_string_equals_literal (lc_name , "spl_autoload_call" )) {
625
- /* Don't destroy the hash table, as we might be iterating over it right now. */
626
- zend_hash_clean (SPL_G (autoload_functions ));
627
- success = SUCCESS ;
628
- } else {
629
- /* remove specific */
630
- success = zend_hash_del (SPL_G (autoload_functions ), lc_name );
631
- if (success != SUCCESS && obj_ptr ) {
632
- lc_name = zend_string_extend (lc_name , ZSTR_LEN (lc_name ) + sizeof (uint32_t ), 0 );
633
- memcpy (ZSTR_VAL (lc_name ) + ZSTR_LEN (lc_name ) - sizeof (uint32_t ), & obj_ptr -> handle , sizeof (uint32_t ));
634
- ZSTR_VAL (lc_name )[ZSTR_LEN (lc_name )] = '\0' ;
635
- success = zend_hash_del (SPL_G (autoload_functions ), lc_name );
636
- }
637
- }
586
+ autoload_func_info * alfi = autoload_func_info_from_fci (& fci , & fcc );
587
+ Bucket * p = spl_find_registered_function (alfi );
588
+ autoload_func_info_destroy (alfi );
589
+ if (p ) {
590
+ zend_hash_del_bucket (SPL_G (autoload_functions ), p );
591
+ RETURN_TRUE ;
638
592
}
639
593
640
- zend_string_release_ex (lc_name , 0 );
641
- RETURN_BOOL (success == SUCCESS );
594
+ RETURN_FALSE ;
642
595
} /* }}} */
643
596
644
597
/* {{{ proto false|array spl_autoload_functions()
@@ -654,9 +607,11 @@ PHP_FUNCTION(spl_autoload_functions)
654
607
array_init (return_value );
655
608
if (SPL_G (autoload_functions )) {
656
609
ZEND_HASH_FOREACH_PTR (SPL_G (autoload_functions ), alfi ) {
657
- if (!Z_ISUNDEF (alfi -> closure )) {
658
- Z_ADDREF (alfi -> closure );
659
- add_next_index_zval (return_value , & alfi -> closure );
610
+ if (alfi -> closure ) {
611
+ zval obj_zv ;
612
+ ZVAL_OBJ (& obj_zv , alfi -> closure );
613
+ Z_ADDREF (obj_zv );
614
+ add_next_index_zval (return_value , & obj_zv );
660
615
} else if (alfi -> func_ptr -> common .scope ) {
661
616
zval tmp ;
662
617
0 commit comments