| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent e733dc9 commit 2712e72
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -274,8 +274,11 @@ extern void _PyLineTable_InitAddressRange( | |||
| 274 | 274 | /** API for traversing the line number table. */ | |
| 275 | 275 | PyAPI_FUNC(int) _PyLineTable_NextAddressRange(PyCodeAddressRange *range); | |
| 276 | 276 | extern int _PyLineTable_PreviousAddressRange(PyCodeAddressRange *range); | |
| 277 | - // This is used in dump_frame() in traceback.c without an attached tstate. | ||
| 278 | - extern int _PyCode_Addr2LineNoTstate(PyCodeObject *co, int addr); | ||
| 277 | + | ||
| 278 | + // Similar to PyCode_Addr2Line(), but return -1 if the code object is invalid. | ||
| 279 | + // Used by dump_frame() in Python/traceback.c. | ||
| 280 | + extern int _PyCode_SafeAddr2Line(PyCodeObject *co, int addr); | ||
| 281 | + | ||
| 279 | 282 | ||
| 280 | 283 | /** API for executors */ | |
| 281 | 284 | extern void _PyCode_Clear_Executors(PyCodeObject *code); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -24,6 +24,27 @@ static inline PyCodeObject *_PyFrame_GetCode(_PyInterpreterFrame *f) { | |||
| 24 | 24 | return (PyCodeObject *)executable; | |
| 25 | 25 | } | |
| 26 | 26 | ||
| 27 | + // Similar to _PyFrame_GetCode(), but return NULL if the frame is invalid or | ||
| 28 | + // freed. Used by dump_frame() in Python/traceback.c. | ||
| 29 | + static inline PyCodeObject* _PyFrame_SafeGetCode(_PyInterpreterFrame *f) { | ||
| 30 | + if (PyStackRef_IsNull(f->f_executable)) { | ||
| 31 | + return NULL; | ||
| 32 | + } | ||
| 33 | + void *ptr; | ||
| 34 | + memcpy(&ptr, &f->f_executable, sizeof(f->f_executable)); | ||
| 35 | + if (_PyMem_IsPtrFreed(ptr)) { | ||
| 36 | + return NULL; | ||
| 37 | + } | ||
| 38 | + PyObject *executable = PyStackRef_AsPyObjectBorrow(f->f_executable); | ||
| 39 | + if (_PyObject_IsFreed(executable)) { | ||
| 40 | + return NULL; | ||
| 41 | + } | ||
| 42 | + if (!PyCode_Check(executable)) { | ||
| 43 | + return NULL; | ||
| 44 | + } | ||
| 45 | + return (PyCodeObject *)executable; | ||
| 46 | + } | ||
| 47 | + | ||
| 27 | 48 | static inline _Py_CODEUNIT * | |
| 28 | 49 | _PyFrame_GetBytecode(_PyInterpreterFrame *f) | |
| 29 | 50 | { | |
@@ -37,6 +58,41 @@ _PyFrame_GetBytecode(_PyInterpreterFrame *f) | |||
| 37 | 58 | #endif | |
| 38 | 59 | } | |
| 39 | 60 | ||
| 61 | + // Similar to _PyFrame_GetCode(), but return NULL if the code object is invalid | ||
| 62 | + // or freed. Used by _PyFrame_SafeGetLasti(). | ||
| 63 | + static inline _Py_CODEUNIT * | ||
| 64 | + _PyFrame_SafeGetBytecode(_PyInterpreterFrame *f) | ||
| 65 | + { | ||
| 66 | + #ifdef Py_GIL_DISABLED | ||
| 67 | + PyCodeObject *co = _PyFrame_SafeGetCode(f); | ||
| 68 | + if (co == NULL) { | ||
| 69 | + return NULL; | ||
| 70 | + } | ||
| 71 | + _PyCodeArray *tlbc = _PyCode_GetTLBCArray(co); | ||
| 72 | + assert(f->tlbc_index >= 0 && f->tlbc_index < tlbc->size); | ||
| 73 | + return (_Py_CODEUNIT *)tlbc->entries[f->tlbc_index]; | ||
| 74 | + #else | ||
| 75 | + PyCodeObject *co = _PyFrame_SafeGetCode(f); | ||
| 76 | + if (co == NULL) { | ||
| 77 | + return NULL; | ||
| 78 | + } | ||
| 79 | + return _PyCode_CODE(co); | ||
| 80 | + #endif | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + // Similar to _PyFrame_GetCode(), but return NULL if the frame is invalid or | ||
| 84 | + // freed. Used by dump_frame() in Python/traceback.c. | ||
| 85 | + static inline int | ||
| 86 | + _PyFrame_SafeGetLasti(struct _PyInterpreterFrame *frame) | ||
| 87 | + { | ||
| 88 | + _Py_CODEUNIT *bytecode = _PyFrame_SafeGetBytecode(frame); | ||
| 89 | + if (bytecode == NULL) { | ||
| 90 | + return -1; | ||
| 91 | + } | ||
| 92 | + int lasti = ((int)(frame->instr_ptr - bytecode)); | ||
| 93 | + return lasti * sizeof(_Py_CODEUNIT); | ||
| 94 | + } | ||
| 95 | + | ||
| 40 | 96 | static inline PyFunctionObject *_PyFrame_GetFunction(_PyInterpreterFrame *f) { | |
| 41 | 97 | PyObject *func = PyStackRef_AsPyObjectBorrow(f->f_funcobj); | |
| 42 | 98 | assert(PyFunction_Check(func)); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -54,12 +54,12 @@ static inline int _PyMem_IsPtrFreed(const void *ptr) | |||
| 54 | 54 | { | |
| 55 | 55 | uintptr_t value = (uintptr_t)ptr; | |
| 56 | 56 | #if SIZEOF_VOID_P == 8 | |
| 57 | - return (value == 0 | ||
| 57 | + return (value < 256 // NULL, 0x1, 0x2, ... | ||
| 58 | 58 | || value == (uintptr_t)0xCDCDCDCDCDCDCDCD | |
| 59 | 59 | || value == (uintptr_t)0xDDDDDDDDDDDDDDDD | |
| 60 | 60 | || value == (uintptr_t)0xFDFDFDFDFDFDFDFD); | |
| 61 | 61 | #elif SIZEOF_VOID_P == 4 | |
| 62 | - return (value == 0 | ||
| 62 | + return (value < 256 | ||
| 63 | 63 | || value == (uintptr_t)0xCDCDCDCD | |
| 64 | 64 | || value == (uintptr_t)0xDDDDDDDD | |
| 65 | 65 | || value == (uintptr_t)0xFDFDFDFD); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1005,8 +1005,8 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno) | |||
| 1005 | 1005 | * source location tracking (co_lines/co_positions) | |
| 1006 | 1006 | ******************/ | |
| 1007 | 1007 | ||
| 1008 | - int | ||
| 1009 | - _PyCode_Addr2LineNoTstate(PyCodeObject *co, int addrq) | ||
| 1008 | + static int | ||
| 1009 | + _PyCode_Addr2Line(PyCodeObject *co, int addrq) | ||
| 1010 | 1010 | { | |
| 1011 | 1011 | if (addrq < 0) { | |
| 1012 | 1012 | return co->co_firstlineno; | |
@@ -1020,12 +1020,29 @@ _PyCode_Addr2LineNoTstate(PyCodeObject *co, int addrq) | |||
| 1020 | 1020 | return _PyCode_CheckLineNumber(addrq, &bounds); | |
| 1021 | 1021 | } | |
| 1022 | 1022 | ||
| 1023 | + int | ||
| 1024 | + _PyCode_SafeAddr2Line(PyCodeObject *co, int addrq) | ||
| 1025 | + { | ||
| 1026 | + if (addrq < 0) { | ||
| 1027 | + return co->co_firstlineno; | ||
| 1028 | + } | ||
| 1029 | + if (co->_co_monitoring && co->_co_monitoring->lines) { | ||
| 1030 | + return _Py_Instrumentation_GetLine(co, addrq/sizeof(_Py_CODEUNIT)); | ||
| 1031 | + } | ||
| 1032 | + if (!(addrq >= 0 && addrq < _PyCode_NBYTES(co))) { | ||
| 1033 | + return -1; | ||
| 1034 | + } | ||
| 1035 | + PyCodeAddressRange bounds; | ||
| 1036 | + _PyCode_InitAddressRange(co, &bounds); | ||
| 1037 | + return _PyCode_CheckLineNumber(addrq, &bounds); | ||
| 1038 | + } | ||
| 1039 | + | ||
| 1023 | 1040 | int | |
| 1024 | 1041 | PyCode_Addr2Line(PyCodeObject *co, int addrq) | |
| 1025 | 1042 | { | |
| 1026 | 1043 | int lineno; | |
| 1027 | 1044 | Py_BEGIN_CRITICAL_SECTION(co); | |
| 1028 | - lineno = _PyCode_Addr2LineNoTstate(co, addrq); | ||
| 1045 | + lineno = _PyCode_Addr2Line(co, addrq); | ||
| 1029 | 1046 | Py_END_CRITICAL_SECTION(); | |
| 1030 | 1047 | return lineno; | |
| 1031 | 1048 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1028,44 +1028,61 @@ _Py_DumpWideString(int fd, wchar_t *str) | |||
| 1028 | 1028 | ||
| 1029 | 1029 | /* Write a frame into the file fd: "File "xxx", line xxx in xxx". | |
| 1030 | 1030 | ||
| 1031 | - This function is signal safe. */ | ||
| 1031 | + This function is signal safe. | ||
| 1032 | 1032 | ||
| 1033 | - static void | ||
| 1033 | + Return 0 on success. Return -1 if the frame is invalid. */ | ||
| 1034 | + | ||
| 1035 | + static int | ||
| 1034 | 1036 | dump_frame(int fd, _PyInterpreterFrame *frame) | |
| 1035 | 1037 | { | |
| 1036 | - assert(frame->owner < FRAME_OWNED_BY_INTERPRETER); | ||
| 1038 | + if (frame->owner == FRAME_OWNED_BY_INTERPRETER) { | ||
| 1039 | + /* Ignore trampoline frame */ | ||
| 1040 | + return 0; | ||
| 1041 | + } | ||
| 1037 | 1042 | ||
| 1038 | - PyCodeObject *code =_PyFrame_GetCode(frame); | ||
| 1043 | + PyCodeObject *code = _PyFrame_SafeGetCode(frame); | ||
| 1044 | + if (code == NULL) { | ||
| 1045 | + return -1; | ||
| 1046 | + } | ||
| 1047 | + | ||
| 1048 | + int res = 0; | ||
| 1039 | 1049 | PUTS(fd, " File "); | |
| 1040 | 1050 | if (code->co_filename != NULL | |
| 1041 | 1051 | && PyUnicode_Check(code->co_filename)) | |
| 1042 | 1052 | { | |
| 1043 | 1053 | PUTS(fd, "\""); | |
| 1044 | 1054 | _Py_DumpASCII(fd, code->co_filename); | |
| 1045 | 1055 | PUTS(fd, "\""); | |
| 1046 | - } else { | ||
| 1056 | + } | ||
| 1057 | + else { | ||
| 1047 | 1058 | PUTS(fd, "???"); | |
| 1059 | + res = -1; | ||
| 1048 | 1060 | } | |
| 1049 | - int lasti = PyUnstable_InterpreterFrame_GetLasti(frame); | ||
| 1050 | - int lineno = _PyCode_Addr2LineNoTstate(code, lasti); | ||
| 1061 | + | ||
| 1051 | 1062 | PUTS(fd, ", line "); | |
| 1063 | + int lasti = _PyFrame_SafeGetLasti(frame); | ||
| 1064 | + int lineno = -1; | ||
| 1065 | + if (0 <= lasti) { | ||
| 1066 | + lineno = _PyCode_SafeAddr2Line(code, lasti); | ||
| 1067 | + } | ||
| 1052 | 1068 | if (lineno >= 0) { | |
| 1053 | 1069 | _Py_DumpDecimal(fd, (size_t)lineno); | |
| 1054 | 1070 | } | |
| 1055 | 1071 | else { | |
| 1056 | 1072 | PUTS(fd, "???"); | |
| 1073 | + res = -1; | ||
| 1057 | 1074 | } | |
| 1058 | - PUTS(fd, " in "); | ||
| 1059 | 1075 | ||
| 1060 | - if (code->co_name != NULL | ||
| 1061 | - && PyUnicode_Check(code->co_name)) { | ||
| 1076 | + PUTS(fd, " in "); | ||
| 1077 | + if (code->co_name != NULL && PyUnicode_Check(code->co_name)) { | ||
| 1062 | 1078 | _Py_DumpASCII(fd, code->co_name); | |
| 1063 | 1079 | } | |
| 1064 | 1080 | else { | |
| 1065 | 1081 | PUTS(fd, "???"); | |
| 1082 | + res = -1; | ||
| 1066 | 1083 | } | |
| 1067 | - | ||
| 1068 | 1084 | PUTS(fd, "\n"); | |
| 1085 | + return res; | ||
| 1069 | 1086 | } | |
| 1070 | 1087 | ||
| 1071 | 1088 | static int | |
@@ -1108,17 +1125,6 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header) | |||
| 1108 | 1125 | ||
| 1109 | 1126 | unsigned int depth = 0; | |
| 1110 | 1127 | while (1) { | |
| 1111 | - if (frame->owner == FRAME_OWNED_BY_INTERPRETER) { | ||
| 1112 | - /* Trampoline frame */ | ||
| 1113 | - frame = frame->previous; | ||
| 1114 | - if (frame == NULL) { | ||
| 1115 | - break; | ||
| 1116 | - } | ||
| 1117 | - | ||
| 1118 | - /* Can't have more than one shim frame in a row */ | ||
| 1119 | - assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); | ||
| 1120 | - } | ||
| 1121 | - | ||
| 1122 | 1128 | if (MAX_FRAME_DEPTH <= depth) { | |
| 1123 | 1129 | if (MAX_FRAME_DEPTH < depth) { | |
| 1124 | 1130 | PUTS(fd, "plus "); | |
@@ -1128,11 +1134,19 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header) | |||
| 1128 | 1134 | break; | |
| 1129 | 1135 | } | |
| 1130 | 1136 | ||
| 1131 | - dump_frame(fd, frame); | ||
| 1137 | + if (dump_frame(fd, frame) < 0) { | ||
| 1138 | + PUTS(fd, " <invalid frame>\n"); | ||
| 1139 | + break; | ||
| 1140 | + } | ||
| 1141 | + | ||
| 1132 | 1142 | frame = frame->previous; | |
| 1133 | 1143 | if (frame == NULL) { | |
| 1134 | 1144 | break; | |
| 1135 | 1145 | } | |
| 1146 | + if (_PyMem_IsPtrFreed(frame)) { | ||
| 1147 | + PUTS(fd, " <freed frame>\n"); | ||
| 1148 | + break; | ||
| 1149 | + } | ||
| 1136 | 1150 | depth++; | |
| 1137 | 1151 | } | |
| 1138 | 1152 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments