Skip to content

Pointer arithmetic on NULL in INSTRUMENTED_JUMP #152375

Description

@StanFromIreland

Bug report

Bug description:

Found by the CI UBSan job, e.g. this run:

Python/generated_cases.c.h:8158:17: runtime error: applying non-zero offset 44 to null pointer
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior Python/generated_cases.c.h:8158:17 

Note this requires applying #152311 which seems to change the state ever so slightly uncovering the UB. Locally I get with clang:

$ ./python -m test test_monitoring
Using random seed: 1062411673
0:00:00 load avg: 1.00 mem: 41.2 MiB Run 1 test sequentially in a single process
0:00:00 load avg: 1.00 mem: 41.2 MiB [1/1] test_monitoring
Python/generated_cases.c.h:8158:17: runtime error: applying non-zero offset 44 to null pointer
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior Python/generated_cases.c.h:8158:17 
Python/generated_cases.c.h:8050:13: runtime error: applying non-zero offset 2 to null pointer
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior Python/generated_cases.c.h:8050:13 
Python/generated_cases.c.h:13861:59: runtime error: applying non-zero offset to non-null pointer 0x000000000002 produced null pointer
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior Python/generated_cases.c.h:13861:59 
Python/generated_cases.c.h:13881:57: runtime error: applying non-zero offset to non-null pointer 0x000000000002 produced null pointer
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior Python/generated_cases.c.h:13881:57 
0:00:00 load avg: 1.00 mem: 43.0 MiB [1/1] test_monitoring passed

== Tests result: SUCCESS ==

1 test OK.

Total duration: 357 ms
Total tests: run=98
Total test files: run=1/1
Result: SUCCESS

The UB is reported, e.g. at:

INSTRUMENTED_JUMP(this_instr, next_instr + oparg, PY_MONITORING_EVENT_BRANCH_RIGHT);

Which calls INSTRUMENTED_JUMP:

// If a trace function sets a new f_lineno and
// *then* raises, we use the destination when searching
// for an exception handler, displaying the traceback, and so on
#define INSTRUMENTED_JUMP(src, dest, event) \
do { \
if (tstate->tracing) {\
next_instr = dest; \
} else { \
_PyFrame_SetStackPointer(frame, stack_pointer); \
next_instr = _Py_call_instrumentation_jump(this_instr, tstate, event, frame, src, dest); \
stack_pointer = _PyFrame_GetStackPointer(frame); \
if (next_instr == NULL) { \
next_instr = (dest)+1; \
JUMP_TO_LABEL(error); \
} \
} \
} while (0);

If _Py_call_instrumentation_jump raises it returns NULL (setting next_instr). But then on the error path, we do next_instr + oparg resulting in the UB.

CPython versions tested on:

CPython main branch

Operating systems tested on:

No response

Linked PRs

Metadata

Metadata

Labels

interpreter-core(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or error
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions