[reportlab-users] Reproducible crash of reportlab 3.5.50 on x86_64 with current Python3

Hans-Peter Jansen hpj at urpla.net
Wed Sep 23 07:15:07 EDT 2020


Am Dienstag, 22. September 2020, 20:38:36 CEST schrieb Hans-Peter Jansen:
> Hi,
> 
> while working on packaging the current version of reportlab on openSUSE, I
> stumbled upon a reproducible crash in the tests:
> 
> [    9s] + export
> PYTHONPATH=/home/abuild/rpmbuild/BUILDROOT/python-reportlab-3.5.50-0.x86_64
> /usr/lib64/python3.8/site-packages [    9s] +
> PYTHONPATH=/home/abuild/rpmbuild/BUILDROOT/python-reportlab-3.5.50-0.x86_64
> /usr/lib64/python3.8/site-packages [    9s] + python3 runAll.py
> [   11s] .............*** Error in `/usr/bin/python3': free(): invalid
> pointer: 0x0000562662d76b20 *** [   12s] F.........................***
> Error in `python3': free(): invalid pointer: 0x0000560d03b48d20 *** [  
> 12s] /var/tmp/rpm-tmp.FHfzwC: line 45: 24177 Aborted                 (core
> dumped) python3 runAll.py [   12s] error: Bad exit status from
> /var/tmp/rpm-tmp.FHfzwC (%check) [   12s]
> 
> 
> Interestingly, the crash didn't happen on i586 builds, although it's using
> the same compiler, python, etc.
> 
> This is reproduced on several targets Leap 15.1, 15.2 and Tumbleweed (a
> pretty current rolling release), and Python 3.8.5.

Some corrections. The TW x86-64 build seems to be fine as well. The Leap
builds with a different compiler fails. All builds are using the packaged
libart_lgpl, BTW.

In a local 15.2 build (using gcc 9.3.1), I was able to track down the 
issue a bit. It's in rl_accel.

[...]
# code object from '/home/abuild/rpmbuild/BUILD/reportlab-3.5.50/build/lib.linux-x86_64-3.8/reportlab/graphics/charts/__pycache__/utils3d.cpython-38.pyc'
import 'reportlab.graphics.charts.utils3d' # <_frozen_importlib_external.SourceFileLoader object at 0x7fffefcd5f40>
import 'reportlab.graphics.charts.piecharts' # <_frozen_importlib_external.SourceFileLoader object at 0x7fffefcafc10>
Built story contains 1824 flowables...
*** Error in `/usr/bin/python3': free(): invalid pointer: 0x000055555589d970 ***

Program received signal SIGABRT, Aborted.
0x00007ffff7836520 in raise () from /lib64/libc.so.6
(gdb) bt
#0  0x00007ffff7836520 in raise () from /lib64/libc.so.6
#1  0x00007ffff7837b01 in abort () from /lib64/libc.so.6
#2  0x00007ffff7879957 in __libc_message () from /lib64/libc.so.6
#3  0x00007ffff7880173 in malloc_printerr () from /lib64/libc.so.6
#4  0x00007ffff1632e88 in _fp_str (module=<optimized out>, args=[]) at src/rl_addons/rl_accel/_rl_accel.c:396
#5  0x00007ffff7409913 in cfunction_call_varargs (kwargs=<optimized out>, args=<optimized out>, func=<built-in method fp_str of module object at remote 0x7ffff183dcc0>) at Objects/call.c:763
#6  PyCFunction_Call (func=<built-in method fp_str of module object at remote 0x7ffff183dcc0>, args=<optimized out>, kwargs=<optimized out>) at Objects/call.c:778
#7  0x00007ffff73a256c in _PyObject_MakeTpCall (callable=<built-in method fp_str of module object at remote 0x7ffff183dcc0>, args=<optimized out>, nargs=<optimized out>, keywords=0x0)
    at Objects/call.c:159
#8  0x00007ffff7449707 in _PyObject_Vectorcall (kwnames=0x0, nargsf=<optimized out>, args=0x7fffefb641f0, callable=<optimized out>) at ./Include/cpython/abstract.h:128
#9  call_function (kwnames=0x0, oparg=<optimized out>, pp_stack=<synthetic pointer>, tstate=0x555555759490) at Python/ceval.c:4963
#10 _PyEval_EvalFrameDefault (f=<optimized out>, throwflag=<optimized out>) at Python/ceval.c:3500
#11 0x00007ffff7415186 in PyEval_EvalFrameEx (throwflag=0, 
    f=Frame 0x7fffefb64040, for file /home/abuild/rpmbuild/BUILD/reportlab-3.5.50/build/lib.linux-x86_64-3.8/reportlab/pdfgen/canvas.py, line 1779, in setDash (self=<Canvas(_initialFontName='Helvetica', _initialFontSize=12, _initialLeading=<float at remote 0x7ffff103ee30>, _filename='/home/abuild/rpmbuild/BUILD/reportlab-3.5.50/docs/reportlab-userguide.pdf', _doc=<PDFDocument(_ID=None, objectcounter=130, shadingCounter=0, inObject=None, pageCounter=98, invariant=0, compression=1, _pdfVersion=(1, 4), signature=<_hashlib.HASH at remote 0x7fffefc5f950>, _timeStamp=<TimeStamp(tzname='', t=<float at remote 0x7fffefc5f990>, lt=(2020, 9, 23, 9, 40, 52, 2, 267, 0), YMDhms=(2020, 9, 23, 9, 40, 52), dhh=0, dmm=0) at remote 0x7fffefc2d100>, idToObjectNumberAndVersion={'BasicFonts': (1, 0), 'F1': (2, 0), 'F2': (3, 0), 'F3': (4, 0), 'FormXob.2740c11ac32f9355ddf50eada5ea982f': (5, 0), 'Page1': (6, 0), 'Page2': (7, 0), 'F4': (8, 0), 'F5': (9, 0), 'Annot.NUMBER1': (10, 0), 'Page3': (11, 0), 'Page4': (12, 0), 'F6': (13, 0), 'F7': (...(truncated)) at Python/ceval.c:741
#12 _PyEval_EvalCodeWithName (_co=<optimized out>, globals=<optimized out>, locals=<optimized out>, args=<optimized out>, argcount=<optimized out>, kwnames=0x0, kwargs=0x555555cb0000, 
    kwcount=<optimized out>, kwstep=1, defs=0x7ffff10b07d8, defcount=2, kwdefs=0x0, closure=0x0, name='setDash', qualname='Canvas.setDash') at Python/ceval.c:4298
#13 0x00007ffff7415fb2 in _PyFunction_Vectorcall (func=<optimized out>, stack=0x555555cafff8, nargsf=<optimized out>, kwnames=<optimized out>) at Objects/call.c:441
#14 0x00007ffff744592c in _PyObject_Vectorcall (kwnames=0x0, nargsf=<optimized out>, args=0x555555cafff8, callable=<function at remote 0x7ffff10b9a60>) at ./Include/cpython/abstract.h:130
#15 call_function (kwnames=0x0, oparg=<optimized out>, pp_stack=<synthetic pointer>, tstate=0x555555759490) at Python/ceval.c:4963
#16 _PyEval_EvalFrameDefault (f=<optimized out>, throwflag=<optimized out>) at Python/ceval.c:3486
#17 0x00007ffff7415eda in function_code_fastcall (globals=<optimized out>, nargs=3, args=<optimized out>, co=<optimized out>) at Objects/call.c:289
#18 _PyFunction_Vectorcall (func=<optimized out>, stack=0x7fffef40ea90, nargsf=<optimized out>, kwnames=<optimized out>) at Objects/call.c:416
#19 0x00007ffff744592c in _PyObject_Vectorcall (kwnames=0x0, nargsf=<optimized out>, args=0x7fffef40ea90, callable=<function at remote 0x7ffff06594c0>) at ./Include/cpython/abstract.h:130
#20 call_function (kwnames=0x0, oparg=<optimized out>, pp_stack=<synthetic pointer>, tstate=0x555555759490) at Python/ceval.c:4963
#21 _PyEval_EvalFrameDefault (f=<optimized out>, throwflag=<optimized out>) at Python/ceval.c:3486
#22 0x00007ffff7415eda in function_code_fastcall (globals=<optimized out>, nargs=3, args=<optimized out>, co=<optimized out>) at Objects/call.c:289
#23 _PyFunction_Vectorcall (func=<optimized out>, stack=0x7fffef3ba3d0, nargsf=<optimized out>, kwnames=<optimized out>) at Objects/call.c:416
#24 0x00007ffff744592c in _PyObject_Vectorcall (kwnames=0x0, nargsf=<optimized out>, args=0x7fffef3ba3d0, callable=<function at remote 0x7ffff0658280>) at ./Include/cpython/abstract.h:130
#25 call_function (kwnames=0x0, oparg=<optimized out>, pp_stack=<synthetic pointer>, tstate=0x555555759490) at Python/ceval.c:4963
#26 _PyEval_EvalFrameDefault (f=<optimized out>, throwflag=<optimized out>) at Python/ceval.c:3486
#27 0x00007ffff7415186 in PyEval_EvalFrameEx (throwflag=0, 
    f=Frame 0x7fffef3ba230, for file /home/abuild/rpmbuild/BUILD/reportlab-3.5.50/build/lib.linux-x86_64-3.8/reportlab/graphics/renderbase.py, line 204, in draw (self=<_PDFRenderer(_stroke=1, _fill=0, _tracker=<StateTracker(_deltas=[{'transform': (1, 0, 0, 1, 0, 0), 'strokeColor': <Color(red=<float at remote 0x7ffff15b0c30>, green=<float at remote 0x7ffff15b0c90>, blue=<float at remote 0x7ffff15b0250>, alpha=1) at remote 0x7ffff154b640>, 'strokeWidth': 1, 'strokeLineCap': 0, 'strokeLineJoin': 0, 'strokeMiterLimit': 10, 'strokeDashArray': None, 'strokeOpacity': None, 'fillOpacity': None, 'fillOverprint': False, 'strokeOverprint': False, 'overprintMask': 0, 'fillColor': <...>, 'fillMode': 0, 'fontSize': 10, 'fontName': 'Times-Roman', 'textAnchor': 'start', 'ctm': (1, 0, 0, 1, 0, 0)}], _combined=[{...}, {'transform': (...), 'strokeColor': <...>, 'strokeWidth': 1, 'strokeLineCap': 0, 'strokeLineJoin': 0, 'strokeMiterLimit': 10, 'strokeDashArray': None, 'strokeOpacity': None, 'fillOpacity': None, 'fillOverprint': False,...(truncated)) at Python/ceval.c:741


Further investigation with a debug patch revealed:

Index: b/src/rl_addons/rl_accel/_rl_accel.c
===================================================================
--- a/src/rl_addons/rl_accel/_rl_accel.c
+++ b/src/rl_addons/rl_accel/_rl_accel.c
@@ -359,6 +359,7 @@ PyObject *_fp_str(PyObject *module, PyOb
 	char			*buf, *pB;
 
 	if((aL=PySequence_Length(args))>=0){
+		printf("_fp_str: %zu\n", aL);
 		if(aL==1){
 			retVal = PySequence_GetItem(args,0);
 			if((i=PySequence_Length(retVal))>=0){
@@ -369,6 +370,7 @@ PyObject *_fp_str(PyObject *module, PyOb
 			Py_DECREF(retVal);
 			}
 		buf=malloc(31*aL);
+		printf("_fp_str: buf[in]: %zu: %p\n", aL, buf);
 		pB = buf;
 		for(i=0;i<aL;i++){
 			retVal = PySequence_GetItem(args,i);
@@ -393,6 +395,7 @@ PyObject *_fp_str(PyObject *module, PyOb
 #else
 		retVal = PyBytes_FromString(buf);
 #endif
+		printf("_fp_str: buf[out]: %zu: %p\n", aL, buf);
 		free(buf);
 		return retVal;
 		}


resulting in:

_fp_str: 1
_fp_str: buf[in]: 1: 0x5555566d4670
_fp_str: buf[out]: 1: 0x5555566d4670
_fp_str: 1
_fp_str: buf[in]: 0: 0x555555ccb070
_fp_str: buf[out]: 0: 0x555555ccb070
*** Error in `/usr/bin/python3': free(): invalid pointer: 0x0000555555ccb070 ***

Program received signal SIGABRT, Aborted.
0x00007ffff7836520 in raise () from /lib64/libc.so.6


Ah, aL is zero for some cases, more specifically for a case, where the sequence 
length is 1 initially, which turned into 0 for a retVal sequence length of 0,
which in turn results in buf=malloc(0), and modifications of buf there after.


Obviously, Leap versions are stricter in this regard..

Finally solved it with this patch:

Index: b/src/rl_addons/rl_accel/_rl_accel.c
===================================================================
--- a/src/rl_addons/rl_accel/_rl_accel.c
+++ b/src/rl_addons/rl_accel/_rl_accel.c
@@ -368,7 +368,11 @@ PyObject *_fp_str(PyObject *module, PyOb
 			else PyErr_Clear();
 			Py_DECREF(retVal);
 			}
-		buf=malloc(31*aL);
+		/* supply some security margin for zero buffers */
+		if(aL==0)
+		    buf=malloc(32);
+		else
+		    buf=malloc(31*aL);
 		pB = buf;
 		for(i=0;i<aL;i++){
 			retVal = PySequence_GetItem(args,i);

Pete
-------------- next part --------------
A non-text attachment was scrubbed...
Name: fix-rl_accel-crash.patch
Type: text/x-patch
Size: 531 bytes
Desc: not available
URL: <https://pairlist2.pair.net/pipermail/reportlab-users/attachments/20200923/59f6b8c3/attachment.bin>


More information about the reportlab-users mailing list