Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
0ddbf479
Commit
0ddbf479
authored
Oct 08, 2014
by
Antoine Pitrou
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue #22462: Fix pyexpat's creation of a dummy frame to make it appear in exception tracebacks.
Initial patch by Mark Shannon.
parent
b2fdafe3
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
63 additions
and
161 deletions
+63
-161
Include/traceback.h
Include/traceback.h
+1
-0
Lib/test/test_pyexpat.py
Lib/test/test_pyexpat.py
+17
-1
Misc/NEWS
Misc/NEWS
+3
-0
Modules/_ctypes/callbacks.c
Modules/_ctypes/callbacks.c
+1
-44
Modules/_ctypes/callproc.c
Modules/_ctypes/callproc.c
+1
-1
Modules/_ctypes/ctypes.h
Modules/_ctypes/ctypes.h
+0
-2
Modules/pyexpat.c
Modules/pyexpat.c
+7
-113
Python/traceback.c
Python/traceback.c
+33
-0
No files found.
Include/traceback.h
View file @
0ddbf479
...
...
@@ -24,6 +24,7 @@ PyAPI_FUNC(int) PyTraceBack_Here(struct _frame *);
PyAPI_FUNC
(
int
)
PyTraceBack_Print
(
PyObject
*
,
PyObject
*
);
#ifndef Py_LIMITED_API
PyAPI_FUNC
(
int
)
_Py_DisplaySourceLine
(
PyObject
*
,
PyObject
*
,
int
,
int
);
PyAPI_FUNC
(
void
)
_PyTraceback_Add
(
char
*
,
char
*
,
int
);
#endif
/* Reveal traceback type so we can typecheck traceback objects */
...
...
Lib/test/test_pyexpat.py
View file @
0ddbf479
...
...
@@ -2,7 +2,9 @@
# handler, are obscure and unhelpful.
from
io
import
BytesIO
import
os
import
unittest
import
traceback
from
xml.parsers
import
expat
from
xml.parsers.expat
import
errors
...
...
@@ -419,7 +421,11 @@ class HandlerExceptionTest(unittest.TestCase):
def
StartElementHandler
(
self
,
name
,
attrs
):
raise
RuntimeError
(
name
)
def
test
(
self
):
def
check_traceback_entry
(
self
,
entry
,
filename
,
funcname
):
self
.
assertEqual
(
os
.
path
.
basename
(
entry
[
0
]),
filename
)
self
.
assertEqual
(
entry
[
2
],
funcname
)
def
test_exception
(
self
):
parser
=
expat
.
ParserCreate
()
parser
.
StartElementHandler
=
self
.
StartElementHandler
try
:
...
...
@@ -429,6 +435,16 @@ class HandlerExceptionTest(unittest.TestCase):
self
.
assertEqual
(
e
.
args
[
0
],
'a'
,
"Expected RuntimeError for element 'a', but"
+
\
" found %r"
%
e
.
args
[
0
])
# Check that the traceback contains the relevant line in pyexpat.c
entries
=
traceback
.
extract_tb
(
e
.
__traceback__
)
self
.
assertEqual
(
len
(
entries
),
3
)
self
.
check_traceback_entry
(
entries
[
0
],
"test_pyexpat.py"
,
"test_exception"
)
self
.
check_traceback_entry
(
entries
[
1
],
"pyexpat.c"
,
"StartElement"
)
self
.
check_traceback_entry
(
entries
[
2
],
"test_pyexpat.py"
,
"StartElementHandler"
)
self
.
assertIn
(
'call_with_frame("StartElement"'
,
entries
[
1
][
3
])
# Test Current* members:
...
...
Misc/NEWS
View file @
0ddbf479
...
...
@@ -24,6 +24,9 @@ Core and Builtins
Library
-------
- Issue #22462: Fix pyexpat'
s
creation
of
a
dummy
frame
to
make
it
appear
in
exception
tracebacks
.
-
Issue
#
21173
:
Fix
len
()
on
a
WeakKeyDictionary
when
.
clear
()
was
called
with
an
iterator
alive
.
...
...
Modules/_ctypes/callbacks.c
View file @
0ddbf479
...
...
@@ -92,49 +92,6 @@ PrintError(char *msg, ...)
}
/* after code that pyrex generates */
void
_ctypes_add_traceback
(
char
*
funcname
,
char
*
filename
,
int
lineno
)
{
PyObject
*
py_globals
=
0
;
PyCodeObject
*
py_code
=
0
;
PyFrameObject
*
py_frame
=
0
;
PyObject
*
exception
,
*
value
,
*
tb
;
/* (Save and) Clear the current exception. Python functions must not be
called with an exception set. Calling Python functions happens when
the codec of the filesystem encoding is implemented in pure Python. */
PyErr_Fetch
(
&
exception
,
&
value
,
&
tb
);
py_globals
=
PyDict_New
();
if
(
!
py_globals
)
goto
bad
;
py_code
=
PyCode_NewEmpty
(
filename
,
funcname
,
lineno
);
if
(
!
py_code
)
goto
bad
;
py_frame
=
PyFrame_New
(
PyThreadState_Get
(),
/*PyThreadState *tstate,*/
py_code
,
/*PyCodeObject *code,*/
py_globals
,
/*PyObject *globals,*/
0
/*PyObject *locals*/
);
if
(
!
py_frame
)
goto
bad
;
py_frame
->
f_lineno
=
lineno
;
PyErr_Restore
(
exception
,
value
,
tb
);
PyTraceBack_Here
(
py_frame
);
Py_DECREF
(
py_globals
);
Py_DECREF
(
py_code
);
Py_DECREF
(
py_frame
);
return
;
bad:
Py_XDECREF
(
py_globals
);
Py_XDECREF
(
py_code
);
Py_XDECREF
(
py_frame
);
}
#ifdef MS_WIN32
/*
* We must call AddRef() on non-NULL COM pointers we receive as arguments
...
...
@@ -254,7 +211,7 @@ static void _CallPythonObject(void *mem,
}
#define CHECK(what, x) \
if (x == NULL) _
ctypes_add_traceback
(what, "_ctypes/callbacks.c", __LINE__ - 1), PyErr_Print()
if (x == NULL) _
PyTraceback_Add
(what, "_ctypes/callbacks.c", __LINE__ - 1), PyErr_Print()
if
(
flags
&
(
FUNCFLAG_USE_ERRNO
|
FUNCFLAG_USE_LASTERROR
))
{
error_object
=
_ctypes_get_errobj
(
&
space
);
...
...
Modules/_ctypes/callproc.c
View file @
0ddbf479
...
...
@@ -919,7 +919,7 @@ static PyObject *GetResult(PyObject *restype, void *result, PyObject *checker)
v
=
PyObject_CallFunctionObjArgs
(
checker
,
retval
,
NULL
);
if
(
v
==
NULL
)
_
ctypes_add_traceback
(
"GetResult"
,
"_ctypes/callproc.c"
,
__LINE__
-
2
);
_
PyTraceback_Add
(
"GetResult"
,
"_ctypes/callproc.c"
,
__LINE__
-
2
);
Py_DECREF
(
retval
);
return
v
;
}
...
...
Modules/_ctypes/ctypes.h
View file @
0ddbf479
...
...
@@ -353,8 +353,6 @@ extern char *_ctypes_conversion_errors;
extern
void
_ctypes_free_closure
(
void
*
);
extern
void
*
_ctypes_alloc_closure
(
void
);
extern
void
_ctypes_add_traceback
(
char
*
,
char
*
,
int
);
extern
PyObject
*
PyCData_FromBaseObj
(
PyObject
*
type
,
PyObject
*
base
,
Py_ssize_t
index
,
char
*
adr
);
extern
char
*
_ctypes_alloc_format_string
(
const
char
*
prefix
,
const
char
*
suffix
);
extern
char
*
_ctypes_alloc_format_string_with_shape
(
int
ndim
,
...
...
Modules/pyexpat.c
View file @
0ddbf479
...
...
@@ -8,8 +8,6 @@
#define XML_COMBINED_VERSION (10000*XML_MAJOR_VERSION+100*XML_MINOR_VERSION+XML_MICRO_VERSION)
#define FIX_TRACE
static
XML_Memory_Handling_Suite
ExpatMemoryHandler
=
{
PyObject_Malloc
,
PyObject_Realloc
,
PyObject_Free
};
...
...
@@ -210,121 +208,17 @@ flag_error(xmlparseobject *self)
error_external_entity_ref_handler
);
}
static
PyCodeObject
*
getcode
(
enum
HandlerTypes
slot
,
char
*
func_name
,
int
lineno
)
{
if
(
handler_info
[
slot
].
tb_code
==
NULL
)
{
handler_info
[
slot
].
tb_code
=
PyCode_NewEmpty
(
__FILE__
,
func_name
,
lineno
);
}
return
handler_info
[
slot
].
tb_code
;
}
#ifdef FIX_TRACE
static
int
trace_frame
(
PyThreadState
*
tstate
,
PyFrameObject
*
f
,
int
code
,
PyObject
*
val
)
{
int
result
=
0
;
if
(
!
tstate
->
use_tracing
||
tstate
->
tracing
)
return
0
;
if
(
tstate
->
c_profilefunc
!=
NULL
)
{
tstate
->
tracing
++
;
result
=
tstate
->
c_profilefunc
(
tstate
->
c_profileobj
,
f
,
code
,
val
);
tstate
->
use_tracing
=
((
tstate
->
c_tracefunc
!=
NULL
)
||
(
tstate
->
c_profilefunc
!=
NULL
));
tstate
->
tracing
--
;
if
(
result
)
return
result
;
}
if
(
tstate
->
c_tracefunc
!=
NULL
)
{
tstate
->
tracing
++
;
result
=
tstate
->
c_tracefunc
(
tstate
->
c_traceobj
,
f
,
code
,
val
);
tstate
->
use_tracing
=
((
tstate
->
c_tracefunc
!=
NULL
)
||
(
tstate
->
c_profilefunc
!=
NULL
));
tstate
->
tracing
--
;
}
return
result
;
}
static
int
trace_frame_exc
(
PyThreadState
*
tstate
,
PyFrameObject
*
f
)
{
PyObject
*
type
,
*
value
,
*
traceback
,
*
arg
;
int
err
;
if
(
tstate
->
c_tracefunc
==
NULL
)
return
0
;
PyErr_Fetch
(
&
type
,
&
value
,
&
traceback
);
if
(
value
==
NULL
)
{
value
=
Py_None
;
Py_INCREF
(
value
);
}
arg
=
PyTuple_Pack
(
3
,
type
,
value
,
traceback
);
if
(
arg
==
NULL
)
{
PyErr_Restore
(
type
,
value
,
traceback
);
return
0
;
}
err
=
trace_frame
(
tstate
,
f
,
PyTrace_EXCEPTION
,
arg
);
Py_DECREF
(
arg
);
if
(
err
==
0
)
PyErr_Restore
(
type
,
value
,
traceback
);
else
{
Py_XDECREF
(
type
);
Py_XDECREF
(
value
);
Py_XDECREF
(
traceback
);
}
return
err
;
}
#endif
static
PyObject
*
call_with_frame
(
PyCodeObject
*
c
,
PyObject
*
func
,
PyObject
*
args
,
call_with_frame
(
char
*
funcname
,
int
lineno
,
PyObject
*
func
,
PyObject
*
args
,
xmlparseobject
*
self
)
{
PyThreadState
*
tstate
=
PyThreadState_GET
();
PyFrameObject
*
f
;
PyObject
*
res
,
*
globals
;
PyObject
*
res
;
if
(
c
==
NULL
)
return
NULL
;
globals
=
PyEval_GetGlobals
();
if
(
globals
==
NULL
)
{
return
NULL
;
}
f
=
PyFrame_New
(
tstate
,
c
,
globals
,
NULL
);
if
(
f
==
NULL
)
return
NULL
;
tstate
->
frame
=
f
;
#ifdef FIX_TRACE
if
(
trace_frame
(
tstate
,
f
,
PyTrace_CALL
,
Py_None
)
<
0
)
{
return
NULL
;
}
#endif
res
=
PyEval_CallObject
(
func
,
args
);
if
(
res
==
NULL
)
{
if
(
tstate
->
curexc_traceback
==
NULL
)
PyTraceBack_Here
(
f
);
_PyTraceback_Add
(
funcname
,
__FILE__
,
lineno
);
XML_StopParser
(
self
->
itself
,
XML_FALSE
);
#ifdef FIX_TRACE
if
(
trace_frame_exc
(
tstate
,
f
)
<
0
)
{
return
NULL
;
}
}
else
{
if
(
trace_frame
(
tstate
,
f
,
PyTrace_RETURN
,
res
)
<
0
)
{
Py_CLEAR
(
res
);
}
}
#else
}
#endif
tstate
->
frame
=
f
->
f_back
;
Py_DECREF
(
f
);
return
res
;
}
...
...
@@ -376,7 +270,7 @@ call_character_handler(xmlparseobject *self, const XML_Char *buffer, int len)
PyTuple_SET_ITEM
(
args
,
0
,
temp
);
/* temp is now a borrowed reference; consider it unused. */
self
->
in_callback
=
1
;
temp
=
call_with_frame
(
getcode
(
CharacterData
,
"CharacterData"
,
__LINE__
)
,
temp
=
call_with_frame
(
"CharacterData"
,
__LINE__
,
self
->
handlers
[
CharacterData
],
args
,
self
);
/* temp is an owned reference again, or NULL */
self
->
in_callback
=
0
;
...
...
@@ -508,7 +402,7 @@ my_StartElementHandler(void *userData,
}
/* Container is now a borrowed reference; ignore it. */
self
->
in_callback
=
1
;
rv
=
call_with_frame
(
getcode
(
StartElement
,
"StartElement"
,
__LINE__
)
,
rv
=
call_with_frame
(
"StartElement"
,
__LINE__
,
self
->
handlers
[
StartElement
],
args
,
self
);
self
->
in_callback
=
0
;
Py_DECREF
(
args
);
...
...
@@ -537,7 +431,7 @@ my_##NAME##Handler PARAMS {\
args = Py_BuildValue PARAM_FORMAT ;\
if (!args) { flag_error(self); return RETURN;} \
self->in_callback = 1; \
rv = call_with_frame(
getcode(NAME,#NAME,__LINE__)
, \
rv = call_with_frame(
#NAME,__LINE__
, \
self->handlers[NAME], args, self); \
self->in_callback = 0; \
Py_DECREF(args); \
...
...
@@ -669,7 +563,7 @@ my_ElementDeclHandler(void *userData,
goto
finally
;
}
self
->
in_callback
=
1
;
rv
=
call_with_frame
(
getcode
(
ElementDecl
,
"ElementDecl"
,
__LINE__
)
,
rv
=
call_with_frame
(
"ElementDecl"
,
__LINE__
,
self
->
handlers
[
ElementDecl
],
args
,
self
);
self
->
in_callback
=
0
;
if
(
rv
==
NULL
)
{
...
...
Python/traceback.c
View file @
0ddbf479
...
...
@@ -142,6 +142,39 @@ PyTraceBack_Here(PyFrameObject *frame)
return
0
;
}
/* Insert a frame into the traceback for (funcname, filename, lineno). */
void
_PyTraceback_Add
(
char
*
funcname
,
char
*
filename
,
int
lineno
)
{
PyObject
*
globals
=
NULL
;
PyCodeObject
*
code
=
NULL
;
PyFrameObject
*
frame
=
NULL
;
PyObject
*
exception
,
*
value
,
*
tb
;
/* Save and clear the current exception. Python functions must not be
called with an exception set. Calling Python functions happens when
the codec of the filesystem encoding is implemented in pure Python. */
PyErr_Fetch
(
&
exception
,
&
value
,
&
tb
);
globals
=
PyDict_New
();
if
(
!
globals
)
goto
done
;
code
=
PyCode_NewEmpty
(
filename
,
funcname
,
lineno
);
if
(
!
code
)
goto
done
;
frame
=
PyFrame_New
(
PyThreadState_Get
(),
code
,
globals
,
NULL
);
if
(
!
frame
)
goto
done
;
frame
->
f_lineno
=
lineno
;
PyErr_Restore
(
exception
,
value
,
tb
);
PyTraceBack_Here
(
frame
);
done:
Py_XDECREF
(
globals
);
Py_XDECREF
(
code
);
Py_XDECREF
(
frame
);
}
static
PyObject
*
_Py_FindSourceFile
(
PyObject
*
filename
,
char
*
namebuf
,
size_t
namelen
,
PyObject
*
io
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment