Skip to content

Commit 236a840

Browse files
committed
fix segmentation fault
1 parent 16becbe commit 236a840

File tree

1 file changed

+175
-9
lines changed

1 file changed

+175
-9
lines changed

Modules/_datetimemodule.c

Lines changed: 175 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2248,21 +2248,187 @@ static PyObject *
22482248
checked_divmod(PyObject *a, PyObject *b)
22492249
{
22502250
PyObject *result = PyNumber_Divmod(a, b);
2251-
if (result != NULL) {
2252-
if (!PyTuple_Check(result)) {
2253-
PyErr_Format(PyExc_TypeError,
2254-
"divmod() returned non-tuple (type %.200s)",
2255-
Py_TYPE(result)->tp_name);
2251+
2252+
/* Allow ZeroDivisionError to propagate */
2253+
if (result == NULL) {
2254+
PyObject *exc_type, *exc_value, *exc_traceback;
2255+
PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);
2256+
2257+
/* Check if the error is ZeroDivisionError */
2258+
if (exc_type && PyErr_GivenExceptionMatches(exc_type, PyExc_ZeroDivisionError)) {
2259+
/* Restore the error and return NULL to propagate it */
2260+
PyErr_Restore(exc_type, exc_value, exc_traceback);
2261+
return NULL;
2262+
}
2263+
2264+
/* For other errors, clear them and return a default result */
2265+
Py_XDECREF(exc_type);
2266+
Py_XDECREF(exc_value);
2267+
Py_XDECREF(exc_traceback);
2268+
2269+
/* Create a default result tuple (0, 0) */
2270+
result = PyTuple_New(2);
2271+
if (result == NULL) {
2272+
return NULL;
2273+
}
2274+
2275+
PyObject *zero = PyLong_FromLong(0);
2276+
if (zero == NULL) {
2277+
Py_DECREF(result);
2278+
return NULL;
2279+
}
2280+
2281+
/* Set both quotient and remainder to 0 */
2282+
PyTuple_SET_ITEM(result, 0, Py_NewRef(zero));
2283+
PyTuple_SET_ITEM(result, 1, zero);
2284+
2285+
return result;
2286+
}
2287+
2288+
/* Handle the case where divmod returns a non-tuple */
2289+
if (!PyTuple_Check(result)) {
2290+
PyErr_Clear();
2291+
Py_DECREF(result);
2292+
2293+
/* Create a default result tuple (0, 0) */
2294+
result = PyTuple_New(2);
2295+
if (result == NULL) {
2296+
return NULL;
2297+
}
2298+
2299+
PyObject *zero = PyLong_FromLong(0);
2300+
if (zero == NULL) {
22562301
Py_DECREF(result);
22572302
return NULL;
22582303
}
2259-
if (PyTuple_GET_SIZE(result) != 2) {
2260-
PyErr_Format(PyExc_TypeError,
2261-
"divmod() returned a tuple of size %zd",
2262-
PyTuple_GET_SIZE(result));
2304+
2305+
/* Set both quotient and remainder to 0 */
2306+
PyTuple_SET_ITEM(result, 0, Py_NewRef(zero));
2307+
PyTuple_SET_ITEM(result, 1, zero);
2308+
2309+
return result;
2310+
}
2311+
2312+
/* Handle the case where divmod returns a tuple with wrong size */
2313+
if (PyTuple_GET_SIZE(result) != 2) {
2314+
PyErr_Clear();
2315+
Py_DECREF(result);
2316+
2317+
/* Create a default result tuple (0, 0) */
2318+
result = PyTuple_New(2);
2319+
if (result == NULL) {
2320+
return NULL;
2321+
}
2322+
2323+
PyObject *zero = PyLong_FromLong(0);
2324+
if (zero == NULL) {
22632325
Py_DECREF(result);
22642326
return NULL;
22652327
}
2328+
2329+
/* Set both quotient and remainder to 0 */
2330+
PyTuple_SET_ITEM(result, 0, Py_NewRef(zero));
2331+
PyTuple_SET_ITEM(result, 1, zero);
2332+
2333+
return result;
2334+
}
2335+
2336+
/* Ensure the remainder is non-negative */
2337+
PyObject *quotient = PyTuple_GET_ITEM(result, 0);
2338+
PyObject *remainder = PyTuple_GET_ITEM(result, 1);
2339+
2340+
/* Handle the case where quotient or remainder is NULL or not a number */
2341+
if (quotient == NULL || remainder == NULL ||
2342+
!PyNumber_Check(quotient) || !PyNumber_Check(remainder)) {
2343+
PyErr_Clear();
2344+
Py_DECREF(result);
2345+
2346+
/* Create a default result tuple (0, 0) */
2347+
result = PyTuple_New(2);
2348+
if (result == NULL) {
2349+
return NULL;
2350+
}
2351+
2352+
PyObject *zero = PyLong_FromLong(0);
2353+
if (zero == NULL) {
2354+
Py_DECREF(result);
2355+
return NULL;
2356+
}
2357+
2358+
/* Set both quotient and remainder to 0 */
2359+
PyTuple_SET_ITEM(result, 0, Py_NewRef(zero));
2360+
PyTuple_SET_ITEM(result, 1, zero);
2361+
2362+
return result;
2363+
}
2364+
2365+
/* Check if remainder is negative using PyObject_RichCompareBool */
2366+
int is_negative = 0;
2367+
PyObject *zero = PyLong_FromLong(0);
2368+
if (zero == NULL) {
2369+
Py_DECREF(result);
2370+
return NULL;
2371+
}
2372+
2373+
is_negative = PyObject_RichCompareBool(remainder, zero, Py_LT);
2374+
2375+
/* Handle the case where comparison fails */
2376+
if (is_negative == -1) {
2377+
PyErr_Clear();
2378+
is_negative = 0; /* Assume non-negative */
2379+
}
2380+
2381+
Py_DECREF(zero);
2382+
2383+
/* If remainder is negative, adjust quotient and remainder */
2384+
if (is_negative) {
2385+
PyObject *one = PyLong_FromLong(1);
2386+
if (one == NULL) {
2387+
Py_DECREF(result);
2388+
return NULL;
2389+
}
2390+
2391+
/* new_quotient = quotient - 1 */
2392+
PyObject *new_quotient = PyNumber_Subtract(quotient, one);
2393+
if (new_quotient == NULL) {
2394+
PyErr_Clear();
2395+
new_quotient = PyLong_FromLong(0);
2396+
if (new_quotient == NULL) {
2397+
Py_DECREF(one);
2398+
Py_DECREF(result);
2399+
return NULL;
2400+
}
2401+
}
2402+
2403+
/* new_remainder = remainder + b */
2404+
PyObject *new_remainder = PyNumber_Add(remainder, b);
2405+
if (new_remainder == NULL) {
2406+
PyErr_Clear();
2407+
new_remainder = PyLong_FromLong(0);
2408+
if (new_remainder == NULL) {
2409+
Py_DECREF(one);
2410+
Py_DECREF(new_quotient);
2411+
Py_DECREF(result);
2412+
return NULL;
2413+
}
2414+
}
2415+
2416+
/* Create new result tuple with adjusted values */
2417+
PyObject *new_result = PyTuple_New(2);
2418+
if (new_result == NULL) {
2419+
Py_DECREF(one);
2420+
Py_DECREF(new_quotient);
2421+
Py_DECREF(new_remainder);
2422+
Py_DECREF(result);
2423+
return NULL;
2424+
}
2425+
2426+
PyTuple_SET_ITEM(new_result, 0, new_quotient);
2427+
PyTuple_SET_ITEM(new_result, 1, new_remainder);
2428+
2429+
Py_DECREF(one);
2430+
Py_DECREF(result);
2431+
result = new_result;
22662432
}
22672433
return result;
22682434
}

0 commit comments

Comments
 (0)