@@ -94,6 +94,22 @@ framelocalsproxy_hasval(_PyInterpreterFrame *frame, PyCodeObject *co, int i)
9494 return true;
9595}
9696
97+ static int
98+ framelocalsproxy_is_first_occurrence (PyObject * seen , PyObject * name )
99+ {
100+ int found = PySet_Contains (seen , name );
101+ if (found < 0 ) {
102+ return -1 ;
103+ }
104+ if (found ) {
105+ return 0 ;
106+ }
107+ if (PySet_Add (seen , name ) < 0 ) {
108+ return -1 ;
109+ }
110+ return 1 ;
111+ }
112+
97113static int
98114framelocalsproxy_getkeyindex (PyFrameObject * frame , PyObject * key , bool read , PyObject * * value_ptr )
99115{
@@ -390,18 +406,14 @@ framelocalsproxy_keys(PyObject *self, PyObject *Py_UNUSED(ignored))
390406 for (int i = 0 ; i < co -> co_nlocalsplus ; i ++ ) {
391407 if (framelocalsproxy_hasval (frame -> f_frame , co , i )) {
392408 PyObject * name = PyTuple_GET_ITEM (co -> co_localsplusnames , i );
393- int found = PySet_Contains (seen , name );
394- if (found < 0 ) {
409+ int first = framelocalsproxy_is_first_occurrence (seen , name );
410+ if (first < 0 ) {
395411 goto error ;
396412 }
397- if (found ) {
398- continue ;
399- }
400- if (PySet_Add (seen , name ) < 0 ) {
401- goto error ;
402- }
403- if (PyList_Append (names , name ) < 0 ) {
404- goto error ;
413+ if (first ) {
414+ if (PyList_Append (names , name ) < 0 ) {
415+ goto error ;
416+ }
405417 }
406418 }
407419 }
@@ -610,18 +622,30 @@ framelocalsproxy_values(PyObject *self, PyObject *Py_UNUSED(ignored))
610622 if (values == NULL ) {
611623 return NULL ;
612624 }
625+ PyObject * seen = PySet_New (NULL );
626+ if (seen == NULL ) {
627+ Py_DECREF (values );
628+ return NULL ;
629+ }
613630
614631 for (int i = 0 ; i < co -> co_nlocalsplus ; i ++ ) {
615632 PyObject * value = framelocalsproxy_getval (frame -> f_frame , co , i );
616633 if (value ) {
617- if (PyList_Append (values , value ) < 0 ) {
618- Py_DECREF (values );
619- Py_DECREF (value );
620- return NULL ;
634+ PyObject * name = PyTuple_GET_ITEM (co -> co_localsplusnames , i );
635+ int first = framelocalsproxy_is_first_occurrence (seen , name );
636+ if (first == 1 ) {
637+ if (PyList_Append (values , value ) < 0 ) {
638+ Py_DECREF (value );
639+ goto error ;
640+ }
621641 }
622642 Py_DECREF (value );
643+ if (first < 0 ) {
644+ goto error ;
645+ }
623646 }
624647 }
648+ Py_DECREF (seen );
625649
626650 // Iterate through the extra locals
627651 if (frame -> f_extra_locals ) {
@@ -637,6 +661,11 @@ framelocalsproxy_values(PyObject *self, PyObject *Py_UNUSED(ignored))
637661 }
638662
639663 return values ;
664+
665+ error :
666+ Py_DECREF (seen );
667+ Py_DECREF (values );
668+ return NULL ;
640669}
641670
642671static PyObject *
@@ -648,22 +677,37 @@ framelocalsproxy_items(PyObject *self, PyObject *Py_UNUSED(ignored))
648677 if (items == NULL ) {
649678 return NULL ;
650679 }
680+ PyObject * seen = PySet_New (NULL );
681+ if (seen == NULL ) {
682+ Py_DECREF (items );
683+ return NULL ;
684+ }
651685
652686 for (int i = 0 ; i < co -> co_nlocalsplus ; i ++ ) {
653687 PyObject * name = PyTuple_GET_ITEM (co -> co_localsplusnames , i );
654688 PyObject * value = framelocalsproxy_getval (frame -> f_frame , co , i );
655689
656690 if (value ) {
657- PyObject * pair = _PyTuple_FromPairSteal (Py_NewRef (name ), value );
658- if (pair == NULL ) {
659- goto error ;
691+ int first = framelocalsproxy_is_first_occurrence (seen , name );
692+ if (first == 1 ) {
693+ PyObject * pair = _PyTuple_FromPairSteal (Py_NewRef (name ), value );
694+ if (pair == NULL ) {
695+ goto error ;
696+ }
697+ if (_PyList_AppendTakeRef ((PyListObject * )items , pair ) < 0 ) {
698+ goto error ;
699+ }
660700 }
661-
662- if (_PyList_AppendTakeRef ((PyListObject * )items , pair ) < 0 ) {
663- goto error ;
701+ else {
702+ Py_DECREF (value );
703+ if (first < 0 ) {
704+ goto error ;
705+ }
664706 }
665707 }
666708 }
709+ Py_DECREF (seen );
710+ seen = NULL ;
667711
668712 // Iterate through the extra locals
669713 if (frame -> f_extra_locals ) {
@@ -685,6 +729,7 @@ framelocalsproxy_items(PyObject *self, PyObject *Py_UNUSED(ignored))
685729 return items ;
686730
687731error :
732+ Py_XDECREF (seen );
688733 Py_DECREF (items );
689734 return NULL ;
690735}
@@ -701,11 +746,24 @@ framelocalsproxy_length(PyObject *self)
701746 size += PyDict_Size (frame -> f_extra_locals );
702747 }
703748
749+ PyObject * seen = PySet_New (NULL );
750+ if (seen == NULL ) {
751+ return -1 ;
752+ }
704753 for (int i = 0 ; i < co -> co_nlocalsplus ; i ++ ) {
705754 if (framelocalsproxy_hasval (frame -> f_frame , co , i )) {
706- size ++ ;
755+ PyObject * name = PyTuple_GET_ITEM (co -> co_localsplusnames , i );
756+ int first = framelocalsproxy_is_first_occurrence (seen , name );
757+ if (first < 0 ) {
758+ Py_DECREF (seen );
759+ return -1 ;
760+ }
761+ else if (first ) {
762+ size ++ ;
763+ }
707764 }
708765 }
766+ Py_DECREF (seen );
709767 return size ;
710768}
711769
0 commit comments