Skip to content

gh-116437: Use new C API PyDict_Pop() to simplify the code - #116438

Merged
serhiy-storchaka merged 3 commits into
python:mainfrom
serhiy-storchaka:use-pydict-pop
Mar 7, 2024
Merged

gh-116437: Use new C API PyDict_Pop() to simplify the code#116438
serhiy-storchaka merged 3 commits into
python:mainfrom
serhiy-storchaka:use-pydict-pop

Conversation

@serhiy-storchaka

@serhiy-storchakaserhiy-storchaka commented Mar 6, 2024

Copy link
Copy Markdown
Member

@serhiy-storchaka

Copy link
Copy Markdown
MemberAuthor

It also fixes leaks in Python/Python-ast.c.

@vstinnervstinner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe replace == -1 with < 0 to check for failure.

Comment threadModules/_csv.c Outdated
Comment threadModules/_threadmodule.c Outdated
Comment threadObjects/moduleobject.c Outdated
Comment threadObjects/moduleobject.c Outdated
Comment threadObjects/typeobject.c
Comment threadObjects/typeobject.c

@vstinnervstinner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

I don't know if < 0 to check for errors is a common idiom, but I prefer to use it rather than == 0. Currently, https://devguide.python.org/developer-workflow/c-api/index.html#guidelines-for-expanding-changing-the-public-api only mentions "return -1: internal error or API misuse; exception raised".

@serhiy-storchaka
serhiy-storchaka merged commit 72d3cc9 into python:mainMar 7, 2024
@serhiy-storchaka
serhiy-storchaka deleted the use-pydict-pop branch March 7, 2024 09:21
@serhiy-storchaka

Copy link
Copy Markdown
MemberAuthor

Thank you for your review Victor.

@bedevere-bot

Copy link
Copy Markdown

⚠️⚠️⚠️ Buildbot failure ⚠️⚠️⚠️

Hi! The buildbot AMD64 Ubuntu NoGIL Refleaks 3.x has failed when building commit 72d3cc9.

What do you need to do:

  1. Don't panic.
  2. Check the buildbot page in the devguide if you don't know what the buildbots are or how they work.
  3. Go to the page of the buildbot that failed (https://buildbot.python.org/all/#builders/1226/builds/1401) and take a look at the build logs.
  4. Check if the failure is related to this commit (72d3cc9) or if it is a false positive.
  5. If the failure is related to this commit, please, reflect that on the issue and make a new Pull Request with a fix.

You can take a look at the buildbot page here:

https://buildbot.python.org/all/#builders/1226/builds/1401

Failed tests:

  • test_logging
  • test_eintr

Failed subtests:

  • test_flock - main.FNTLEINTRTest.test_flock
  • test_all - test.test_eintr.EINTRTests.test_all
  • test_rollover_at_midnight - test.test_logging.TimedRotatingFileHandlerTest.test_rollover_at_midnight
  • test_map_timeout - test.test_concurrent_futures.test_process_pool.ProcessPoolSpawnProcessPoolExecutorTest.test_map_timeout
  • test_lockf - main.FNTLEINTRTest.test_lockf

Test leaking resources:

  • test_queue: memory blocks

Summary of the results of the build (if available):

==

Click to see traceback logs
Traceback (most recent call last):
File "/home/ubuntu/buildarea/3.x.itamaro-ubuntu-aws.refleak.nogil/build/Lib/test/test_eintr.py", line 17, in test_all
script_helper.run_test_script(script)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
File "/home/ubuntu/buildarea/3.x.itamaro-ubuntu-aws.refleak.nogil/build/Lib/test/support/script_helper.py", line 316, in run_test_scriptraiseAssertionError(f"{name} failed")
AssertionError: script _test_eintr.py failed
Traceback (most recent call last):
File "/home/ubuntu/buildarea/3.x.itamaro-ubuntu-aws.refleak.nogil/build/Lib/test/test_logging.py", line 6111, in test_rollover_at_midnightself.assertIn(f'testing2 {i}', line)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^AssertionError: 'testing2 0' not found in '2024-03-07 12:13:26,043 testing1 0\n'
Traceback (most recent call last):
File "/home/ubuntu/buildarea/3.x.itamaro-ubuntu-aws.refleak.nogil/build/Lib/threading.py", line 1080, in _bootstrap_innerself.run()
~~~~~~~~^^
File "/home/ubuntu/buildarea/3.x.itamaro-ubuntu-aws.refleak.nogil/build/Lib/threading.py", line 1017, in runself._target(*self._args, **self._kwargs)
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/buildarea/3.x.itamaro-ubuntu-aws.refleak.nogil/build/Lib/queue.py", line 85, in task_doneraiseValueError('task_done() called too many times')
ValueError: task_done() called too many times
k
Traceback (most recent call last):
File "/home/ubuntu/buildarea/3.x.itamaro-ubuntu-aws.refleak.nogil/build/Lib/test/test_concurrent_futures/executor.py", line 71, in test_map_timeoutself.assertEqual([None, None], results)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^AssertionError: Lists differ: [None, None] != []
Traceback (most recent call last):
File "/home/ubuntu/buildarea/3.x.itamaro-ubuntu-aws.refleak.nogil/build/Lib/test/_test_eintr.py", line 535, in test_flockself._lock(fcntl.flock, "flock")
~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/buildarea/3.x.itamaro-ubuntu-aws.refleak.nogil/build/Lib/test/_test_eintr.py", line 517, in _lockraiseException("failed to sync child in %.1f sec"% dt)
Exception: failed to sync child in 300.5 sec
Traceback (most recent call last):
File "/home/ubuntu/buildarea/3.x.itamaro-ubuntu-aws.refleak.nogil/build/Lib/test/_test_eintr.py", line 532, in test_lockfself._lock(fcntl.lockf, "lockf")
~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "/home/ubuntu/buildarea/3.x.itamaro-ubuntu-aws.refleak.nogil/build/Lib/test/_test_eintr.py", line 517, in _lockraiseException("failed to sync child in %.1f sec"% dt)
Exception: failed to sync child in 300.6 sec
Traceback (most recent call last):
File "/home/ubuntu/buildarea/3.x.itamaro-ubuntu-aws.refleak.nogil/build/Lib/test/test_logging.py", line 6111, in test_rollover_at_midnightself.assertIn(f'testing2 {i}', line)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^AssertionError: 'testing2 0' not found in '2024-03-07 11:49:20,006 testing1 0\n'

@ericsnowcurrentlyericsnowcurrently left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the post-merge review. I was curious about what changed and happened to notice a few things.

Comment threadModules/posixmodule.c
Comment on lines -17559 to +17563
if (PyDict_DelItemString(dct, "pwritev") == -1) {
PyErr_Clear();
if (PyDict_PopString(dct, "pwritev", NULL) < 0) {
return -1;
}
if (PyDict_DelItemString(dct, "preadv") == -1) {
PyErr_Clear();
if (PyDict_PopString(dct, "preadv", NULL) < 0) {
return -1;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is slightly different behavior, isn't it? Before, we tried removing each item and ignored all errors. Now we fail at the first error. Is that okay? (Maybe @ronaldoussoren has some thoughts on this?) Was this intentional?

(The same applies to the changes in Modules/timemodule.c.)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not ignoring errors is always a good thing.

Comment threadParser/asdl_c.py
Comment on lines +1081 to -1093
int rc = PyDict_Pop(remaining_dict, name, &value);
Py_DECREF(name);
if (rc < 0) {
goto cleanup;
}
if (!value) {
if (PyErr_Occurred()) {
goto cleanup;
}
break;
}
if (PyList_Append(positional_args, value) < 0) {
rc = PyList_Append(positional_args, value);
Py_DECREF(value);
if (rc < 0) {
goto cleanup;
}
if (PyDict_DelItem(remaining_dict, name) < 0) {
goto cleanup;
}
Py_DECREF(name);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch about fixing the decrefs.

Comment threadPython/pythonrun.c
Comment on lines 475 to 480
if (set_file_name) {
if (PyDict_DelItemString(dict, "__file__")) {
PyErr_Clear();
if (PyDict_PopString(dict, "__file__", NULL) < 0) {
PyErr_Print();
}
if (PyDict_DelItemString(dict, "__cached__")) {
PyErr_Clear();
if (PyDict_PopString(dict, "__cached__", NULL) < 0) {
PyErr_Print();
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. Using PyErr_Print() here makes sense.

Comment on lines 2045 to +2057
swap_current_task(asyncio_state *state, PyObject *loop, PyObject *task)
{
PyObject *prev_task;

if (task == Py_None) {
if (PyDict_Pop(state->current_tasks, loop, &prev_task) < 0) {
return NULL;
}
if (prev_task == NULL) {
Py_RETURN_NONE;
}
return prev_task;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It took me a minute to make sense of your changes in this file, but now I get it. 👍

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. I blocked here for 5 minutes :-D

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@serhiy-storchaka@bedevere-bot@vstinner@ericsnowcurrently