pyca/pyopenssl

Memory Leak with Async Code

Opened this issue · 5 comments

mhils commented

Hey folks,

I'm currently debugging a memory leak in mitmproxy which I think is rooted somewhere outside of our codebase. In short:

  1. We see a slow but unbounded (heap) memory increase in long-running mitmdump sessions.
  2. len(gc.get_objects()) is constant over time.
  3. When dumping the heap of a process that has accumulated a lot of memory, I see lots of certificate-related strings and lots of _lib.c1.
cat heap.bin | strings | sort | uniq -c | sort -r
  37667 _lib.c
  28694 B0@0
  11262 DigiCert Inc1
   8233 QuoVadis Limited1
   7636 c0a0
   7621 www.digicert.com1 0
   7160 digicert inc1
   6348 www.digicert.com1$0"
   6207 GlobalSign
   6206 GlobalSign1
   5598 Amazon1
   5509 Google Trust Services LLC1
   5508 US1"0 
   5331 Salford1
   5328 Greater Manchester1
   5070 Texas1
   5066 Houston1
   4404 h&(z[
   4331 globalsign1
   4227 Panama1
   4121 Arizona1
   4040 quovadis limited1
   4006 GlobalSign nv-sa1
   3854 Entrust, Inc.1(0&
   3853 See www.entrust.net/legal-terms1907
   3829 Illinois1
   3827 Chicago1!0
   3799 TrustCor Certificate Authority1
   3797 Panama City1$0"
   3796 TrustCor Systems S. de R.L.1'0%
   3624 Budapest1
   3606 houston1
   3601 DigiCert Inc
   3564 AffirmTrust1
   3495 Starfield Technologies, Inc.1200
   3490 salford1
   3489 www.digicert.com
   3459 google trust services llc1
   3449 globalsign
   3434 texas1
   3409 greater manchester1
   3405 .1.1
   3345   Dhimyotis1
   3332 US1!0
   3321 amazon1
   3315 GlobalSign0
   3183 us1"0 
   3139 130801120000Z
   2993 nykiad
   2827 Scottsdale1%0#
   2767 The USERTRUST Network1.0,
   2767 New Jersey1
   2767 Jersey City1
   2744 Root CA1
   2652 WISeKey1"0 
   2651 trustcor certificate authority1
   2650 panama city1$0"
   2650 OISTE Foundation Endorsed1(0&
   2647 trustcor systems s. de r.l.1'0%
   2636 US1 0
   2633 SecureTrust Corporation1
   2612 0000Z
   2610 chicago1!0
   2601   TAIWAN-CA1
   2576 arizona1
   2573 budapest1
   2571 SSL Corporation110/
   2552 COMODO CA Limited1+0)
   2552   Hong Kong1
   2547 DE1+0)
   2545 T-Systems Trust Center1%0#
   2544 "T-Systems Enterprise Services GmbH1
   2536 0L1 0
   2531 5959Z
   2511 see www.entrust.net/legal-terms1907
   2508 Trustwave Holdings, Inc.1:08
   2506 emSign PKI1
   2484 globalsign nv-sa1
   2483 illinois1
   2479 ;Hellenic Academic and Research Institutions Cert. Authority1@0>
   2473 180218183000Z
   2470 Hongkong Post1 0
   2462 160622000000Z
   2453 150526000000Z
   2452 panama1
   2452 PL1"0 
   2448 Unizeto Technologies S.A.1'0%
   2446 Buypass AS-9831633271 0
   2434 emSign PKI1%0#
   2388 PL1!0
   2387 Certum Certification Authority1
   2386 Asseco Data Systems S.A.1'0%
   2377 Athens1D0B
   2362 Microsoft Corporation1604
   2350 FNMT-RCM1
   2341 affirmtrust1
   2257 US1%0#
   2243 ertification Authority
   2234 entrust, inc.1(0&
   2172 .1&0$
   2168 0002 481463081000361
   2138 www.digicert.com1!0
   2137 im Teknolojileri ve Hizmetleri A.
   2121  Inc
   2104 www.digicert.com1+0)
   2086 The Go Daddy Group, Inc.110/
   2080 QuoVadis Limited
   2054 www.xrampsecurity.com1$0"
   2049 %bw+s
   2002 061110000000Z
   1910 Amazon
   1859 oiste foundation endorsed1(0&
   1858 wisekey1"0 
   1840 090901000000Z
   1830 scottsdale1%0#
   1796 Google Trust Services LLC
   1783 ssl corporation110/
   1776 root ca1
   1768 t-systems trust center1%0#
   1767 starfield technologies, inc.1200
   1765 G0E1
   1760 securetrust corporation1
   1753 certum certification authority1
   1749 jersey city1
   1748 the usertrust network1.0,
   1738 asseco data systems s.a.1'0%
   1738 Salford
   1738 Greater Manchester
   1736 "t-systems enterprise services gmbh1
   1731 .edu0
   1730 trustwave holdings, inc.1:08
   1729 ;hellenic academic and research institutions cert. authority1@0>
   1724   hong kong1
   1723   taiwan-ca1
   1719 unizeto technologies s.a.1'0%
   1718 hongkong post1 0
   1711 ra EBG Bili
   1711 comodo ca limited1+0)
   1697   dhimyotis1
   1695 380118235959Z0
   1695 .eu0
   1694 athens1D0B
   1694 .gr0
   1681 emsign pki1
   1677 cert.com
   1676 microsoft corporation1604
   1670 Certigna
   1667 buypass as-9831633271 0
   1665 Houston
   1664 emSign PKI
   [...]
./sample.py heap.bin (random chunks from the heap)
root@memtest ~# ./sample.py heap.bin  
=== 5b83400 ===                                                               
b'\r\x00\x00\x00\x17\x00\x00\x00\xa0.\xdd\x1f\x94U\x00\x00@\x00\x00\x00\x00\x0
0\x00\x00!\x00\x00\x00\x00\x00\x00\x00\x80\x15\xdd\x1f\x94U\x00\x00\x06\x00\x0
0\x00\x06\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00!\x00\x00\x00\x00\x00\x00
\x00\x01\x00\x00\x00\x02\x00\x00\x000\xff\xdc\x1f\x94U\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00!\x00\x00\x00\x00\x00\x00\x00\xd0\n\xdd\x1f\x94U\x00\x00\x01\x
00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00q\x00\x00\x00\x00\x0
0\x00\x000J1\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x120\x10\x06\x03U\x04\n\x13\tI
denTrust1\'0%\x06\x03U\x04\x03\x13\x1eIdenTrust Commercial Root CA 1\x00\x00\x
00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00A\x00\x00\x00\x00\x00\x00\x00s)\xc5\xccj\x19\xec\xecz\
xa7\xb0H\xb2\r\x1aX\xdf-7\xf4\x81Mc\xc7\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf
f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff!\xef\x9cF\x91U\x00\x
00!\x00\x00\x00\x00\x00\x00\x00EC\x00\xb4g\x7f\x00\x00\x90\x04\xdd\x1f\x94U\x0
0\x00\x00\x00\x00\x00\x00\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00
\x00\x00\x00\x00\x00\xf0e\xfc$\x94U\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x0
0\x00\x00\x00\x00\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00A\x00\x00\x00\x00\x0
0\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\
xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf
f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\
xc1\x00\x00\x00\x00\x00\x00\x00\x00\x830\xb2g\x7f\x00\x00P\x0f\xdd\x1f\x94U\x0
0\x00\x90\x0b\xdd\x1f\x94U\x00\x00`\x14\xdd\x1f\x94U\x00\x00\xcb\x02\x00\x00\x
01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00P\xff\xdc\x1f\x94U\x00\x00\x14\x
00\x00\x00\x00\x00\x00\x00 \x14\xdd\x1f\x94U\x00\x00\x00\x00\x00\x00\x00\x00\x
00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\x13\xd
d\x1f\x94U\x00\x00@\x13\xdd\x1f\x94U\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x
80\x16\xdd\x1f\x94U\x00\x00\x10\x00\xdd\x1f\x94U\x00\x00\x00\x00\x00\x00\x00\x
00\x00\x00\xe0\x0c\xdd\x1f\x94U\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0
0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
x00\x00\x00q\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00g\x7f\x00\x00`\x07\xdd
\x1f\x94U\x00\x00\x06\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
x00\xa0\x07\xdd\x1f\x94U\x00\x00\x06\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x
00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x
00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x11\x01\x00\x00\x00\x00
\x00\x00\x87\x0b\x8b\x80\x8a\x19\xb3\xf2[\x83M\\\xa3-\x8
b\x95!\x18B+N\xf2\x1d>P\xb90\x9d\xd6}\xef\xf1,H\xcb\xfa\xe0\xa6n \xfc\xa5h@\x8
2\xe9\xc6\xbb\xf1r\x02\x90\xbbD\x0c\xe5\xf7\xe7;R \xf8\xa4\xca\xeft\xaf7\x84@y
U\xe6V\xf0\xda\x92\xb2\xfc_<\x12)\xca\n\x1a\xbdG>\x90\xcb\xc9\xee8\x8er\x80\x1
b\xf0S\x8bw\x97p\x8f O\xab\xa2\xdax\xcbp(O\xa8\xe2!\xcd\xceF\x95\xd8kB;u\xf7\x
fc\x12\x8c{\xe6\x8aZ(\x7f\x00\xa5\xd5\xd7n\x90|\x82\xa2\xdf\x9c\x1cn\x18\xa9\x
cbU\xf8\xe5\x16iJb"h\xf3On\x98H\xdc\x94Eg>|\xe7R\xa0A\xc4 \xc8\xa0!\x93@!)\x92
\xdf\x0e\xce0\xa4~\xdbR\xf1\xff{ \x0c\xa6\xb3Co\x15\xc5\x16\xc0\xb6\x8638\x15k
o\xf6\xbf\x8d\xcf\xe1A\x82\x10M{\x16\xe0\x8f\xe6\xc5=\x04\xf5\xed\xff\x94b+|\x
1cU}\xff\xc1_2\xe6\x06*\xa57\x84>F\xd1\xf3x\x14\xf2\xd4\x80\xb5S\x86#\xbez\xc8
\x92>\x88;$\xa0S)\x98h\x1d\xbch\xed}I\xf4\xf10\xaf\xdd\xcc\x19\x81}\xd1f\xe1?\
xa3\xe5 #\xc0\x06\x0e\x829\x06\xf5\xceu\xba\xd3\x1a\x84\xc6\xbd\xd4\x88\xdfOxT
\x91n\xdf>\xe0\xe1B\xdd\x1e\\\xfeY\xdfb\\\xa5\x8c>6\xd72\xd0\xecJk\xeb\x05\x1d
|\xa5\x8f\x80\x19\x9bg\x8e!\x9b@\x97\x15%\xb7\x9b\xdf\x17\xb4\x8d\xa8\xe6\\\xa
f\xf8\xdd(\xaa\x81\x14\xb8~\x81{\x90\xd7U\xc4\xe5\xfb!7|\x96\xc3\xe5\x193c\xa7
U\xd4\xbf\x1dn\xdc0\xc1\xec\x13\xfe7o0\xa7\x85T\xd2!\x7f*\xbf;jF\x00zw\xa2,\xc
1-\x04\xcdN\xaa*Q\xb8\x9f*\xf6\x9f/*\xbb\xb9\xca^zu|\x06q\xc4lA\xc7F\xd6\xcb[\
xc5\x13zb\xbe\\\xe1\x96\xbdy5I{i\xd1\xd3\xd3\xf3\xc1\xdf\xf9\x7fR\x95\xcc\x9d\
x9b#\xcai7&\xb4\x93\xec\xec\x7f\xa1r\xfc\xe0\x87o\xaa\xd7\x19\xcd#\xf7\x80\xf3
K\x80\x8f\x8a\x16Q\xe6\xc1\rG$Eh\xedJ\xd9\xafk\x9f\x84\xd6,\xe4T\xcf.\xaf\x06\
x12\n5\x95>\xa82@\xb7\x001\xcfH\x8a\xc7\xe6J\n\xb9\x139\x08\xdc\x03E\x03\xe9\x
c0I=\xad\x14SDNS\xe1\x1d\x86\x9e.]|m\xa3\xee\xf0\xb2\xb8\xcdQ\x97\x07\xe3\xf56
\xe8\xe1{z\xb2\x98\xf8\xa5c1\x9a\x82\xd8\x10\xceB\xb0\x86\xca]548\xc5\x00\xbe\
xda\x18B\xd6`\x93\x16r\x9e\xba2Qw\xfa\x93\xbe\xc5\x9d\x7f\xc5\xd9\x9b\xb7\\;\x
03\x0c\x9b\xc2&@\x14/i08\x8b\xc2\xb8\x8d\xf6\xb3>\xef\x18\x82\x15\xe0\x1d\xfe\
xcfz-\xd0V\xd0\x8f\xb9j\x9e\xcd\x9ah\xb0\x08\xeeK\x0f\xfe0\xf4\xc8\x08\xc0\xa0
k"U\xe7\xda\xbd>\xc7\xb9R\xbc\xc9?\x81\xbeg\x9a\xc5\xe7\xd4 }\xa8\x81\xb0\xa4\
xca\xd3#\xbb\x8bb\nG_\x1a^&\xe8#7\x17\x17|\xb3\t(\xfd\xe9-jDS%\xef\xdf<\xe4p3\
xe6i\xf2\xe7*_\xf2\x18cqn\x9eFf\xe2\x03c\tJ\xd8\xb2\x1ci\xfc\xc0\xcc\x1bt\xad\
xd7\xc72N\xf6l\x8c@:\xaa\x14\x83"\x8c\xee\xed\x82\x93\xe3\x1e\x8b\x919lb\xe2\x
b6\xa48\xb6\x90\xe1\x1d\x82U\xb1t;3.y\xc3\xef\xfc\x154\xc1\x03P^\xe3\xf3\xb0\x
c9Y;\xac\xdd\xbe\x93\x9d\xc1z\xa8&\xde7\x079D\xf0Y((\xe1\xc71\x85Zy\xd01\x01\x
f6\xf8\xce\xb6\xa8\x81\xae\x1a%z\xff(\xa5\xe5\x0b\xe3\x13\x18\xc2h\xa5\xcc;{`+
\xbe-\xd22U\xfd\xff!oX\r/\x9d\x94J\xa5Uo\xba8T\xec\xbaP\x96\x81p\xb8\x82\xe8\x
d0r/y\xe3\xd2t#\xe0=\xf8\x82\xa5c\x89x\x1b\xfb\x14rI\xaf\x19\x04\x08[?\xcc\xc8
k\x08\xcbir\x08\x96\xf8\xeb%)\xab]\x1e\xa2\n\xc7\xbb\xbbe\xaaX\xb6E\x1c\xb8\x1
9'                                                                            
root@memtest ~# ./sample.py heap.bin                   
=== 1c219c00 ===                                                              
b'ERTrustRSAAddTrustCA.crt0%\x06\x08+\x06\x01\x05\x05\x070\x01\x86\x19http://o
csp.usertrust.com\x1d\x7f\xdb\xbd\x9f\x00\x00\x00\x00!\x02\x00\x00\x00\x00\x00
\x000\x82\x02\n\x02\x82\x02\x01\x00\xc2\xf8\xa9?\x1b\x89\xfc<<\x04]=\x906\xb0\
x91:y\xdf\xac\xaf\xe7\xa1\x88k1\xaf\xf0\x8b\xd0\x183\xb8\xdbEj4\xf4\x0
2\x80$(\n\x02\x15\x95^v*\r\x99:\x14[\xf6\xcb\xcbS\xbc\x13M\x01\x887\x94%\x1bB\
xbc"\xd8\x8e\xa3\x96^:\xd92\xdb>\xe8\xf0\x10e\xedt\xe1/\xa7|\xaf\'4\xbb)}\x9b\
xb6\xcf\t\xc8\xe5\xd3\n\xfc\x88eet\n\xdcs\x1c\\\xcd@\xb1\x1c\xd4\xb6\x84\x8cLP
\xcfh\x8e\xa8Y\xae\xc2\'N\x82\xa25\xdd\x14\xf4\x1f\xff\xb2w\xd5\x87/\xaan}$\'\
xe7\xc6\xcb&\xe6\xe5\xfeg\x07c\xd8E\r\xdd:Ye9Xz\x92\x99r=\x9c\x84^\x88!\xb8\xd
5\xf4,\xfc\xd9pROx\xb8\xbd<+\x8b\x95\x98\xf5\xb3\xd1h\xcf \x14~L\\_\xe7\x8b\xe
5\xf55\x81\x197\xd7\x11\x08\xb7f\xbe\xd3J\xce\x83W\x00:\xc3\x81\xf8\x17\xcb\x9
26]\xd1\xa3\xd8u\x1b\xe1\x8b\'\xeazHA\xfdE\x19\x06\xad\'\x99N\xc1pG\xdd\xb5\x9
f\x81S\x12\xe5\xb1\x8cH]1C\x17\xe3\x8c\xc6zc\x96K)0N\x84Nb\x19^<\xce\x97\x90\x
a5\x7f\x01\xeb\x9d\xe0\xf8\x8b\x89\xdd%\x98=\x92\xb6~\xef\xd9\xf1QQ}-&\xc8iYa\
xe0\xacj\xb8*6\x11\x04zP\xbd2\x84\xbe/\xdcr\xd5\xd7\x1d\x16G\xe4Gf ?\xf4\x96\x
c5\xaf\x8e\x01z\xa5\x0fzd\xf5\r\x18\x87\xd9\xae\x88\xd5\xfa\x84\xc1:\xc0i(-\xf
2\rhQ\xaa\xe3\xa5w\xc6\xa4\x90\x0e\xa17\x8b1#G\xc1\t\x08\xebn\xf7x\x9b\xd7\x82
\xfc\x84 \x99I\x19\xb6\x12F\xb1\xfbEU\x16\xa9\xa3e\xac\x9c\x07\x0f\xeak\xdc\x1
f.\x06r\xec\x86\x88\x12\xe4-\xdb_\x05/\xe4\xf0\x03\xd3&3\xe7\x80\xc2\xcdB\xa1\
x174\x0b\x02\x03\x01\x00\x01\x9b\x1f\x90+?%!,.y1\x00\x00\x00\x00\x00\x00\x00\x
b8\xd7,\xb2g\x7f\x00\x00\xff\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x
00\x00\x00\xa0\x98\x84#\x94U\x00\x00\x80\x00\x00\x00\x00\x00\x00\x001\x00\x00\
x00\x00\x00\x00\x00\xc0\x87\x84#\x94U\x00\x00p~F6\x94U\x00\x00\xe0\x81F6\x94U\
x00\x00\x00\x00\x00\x00\x00\x00\x00\x00O\xe4HB0c&\xcf1\x00\x00\x00\x00\x00\x00
\x00\x03\x00\x00\x00\x00\x00\x00\x00@\x8aF6\x94U\x00\x00\x00\x00\x00\x00\x04\x
00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\xb1\x17\xb5Y\xe9w\xca!\x00\x00\
x00\x00\x00\x00\x00\x10\xcb,\xb2g\x7f\x00\x00\x80\x8fF6\x94U\x00\x00_lib.c\x00
\x00!\x00\x00\x00\x00\x00\x00\x00\x0c\x01\x00\x00\x03\x00\x00\x00\xe0u\x84#\x9
4U\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00!\x00\x00\x00\x00\x00\x00\x00`\x7fF6
\x94U\x00\x00@\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x11\x0
2\x00\x00\x00\x00\x00\x00\xe3\x02\xa5r%\xb7\xa0\x83\xa1\xa3*\xf8\xc2\x06\xa8\x
98\xcf\xfd\x9d\xc7\x0b\xb1v\x0b\x9d\xa1z\xbd=\xe8\x936[\xaa\xe3\x9c\x04\xc0"\x
de\xfaY\xc4\xdb\x8f\x81k!\x07\x9aJ\x9e\xa2\xd0e\xdc\xaaf\xcbj\xfe{T\xb1\x9f10\
x1b\xdf\xa3j#\xa8\x0cy\xe9\x0en\xa6\x1c\x9dlvTyl\xd9\xa5\x07+\xf0{\xf3\xcb\x19
k\xc7\xec\x1c\x17\xf6\xf8\xec]|u\xbb\xfc\x15~\xa6S]\xe6\xfb}2\xb6\xc2o\xd8\x0c
qY1c)_\x8cF\xdc\x16\x91\xf6M\xa0tA\xc6\xdf\xc9q\'\xfa#\x8d \x82\xa7\xa4\x8ey\x
82\x98\x8a\xc5$~@M'                                                           
root@memtest ~# ./sample.py heap.bin                   
=== b7ef400 ===                                                               
b'-\x00\x00\x00\x04\x00\x00\x00\x80\xd8\xa3%\x94U\x00\x00\x80\x00\x00\x00\x00\
x00\x00\x00\xc1\x00\x00\x00\x00\x00\x00\x00`\x9f\xa3%\x94U\x00\x00\xe0\x9b\xa3
%\x94U\x00\x00 \x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00m\x8e\
xe1|\x91U\x00\x00`\xd4\xa3%\x94U\x00\x00@\x00\x00\x00\x00\x00\x00\x00 \x00\x00
\x00\x00\x00\x00\x00m\x89\xe1|\x91U\x00\x00ust CA\x00\x00`\x00\x00\x00\x00\x00
\x00\x000\x00\x00\x00\x00\x00\x00\x00\xcd\xbd\xe1|\x91U\x00\x00\x00\xe8\xa3%\x
94U\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9
0\x00\x00\x00\x00\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00\xdd\xc1\xe1|\x91U\x
00\x00`\xd3\xa3%\x94U\x00\x00 \xd4\xa3%\x94U\x00\x00\x00\x00\x00\x00\x00\x00\x
00\x00\x10\x11\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00}\xc1\xe1|\
x91U\x00\x00\x86#http://crl.securetrust.com/SGCA.crl\x00\x00\x00\xa0 \x00\x00\
x00\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00=\xb9\xf5t\x91U\x00\x00\x00\x00\x0
0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
x00\x00\xd0 \x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00]\xee,k\x91U\
x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x117\x
00\x00\x00\x00\x00\x00p\x03\x1f\x1d\x94U\x00\x00\xf0@6&\x94U\x00\x00\x00\x00\x
00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\xd7\xa3%\x94U\x00\x00\
xe0\xd6\xa3%\x94U\x00\x00 \x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x0
0\x00\xdd\x8c\xe1|\x91U\x00\x00\xf0\xd6\xa3%\x94U\x00\x00`\x00\x00\x00\x00\x00
\x00\x00@\x00\x00\x00\x00\x00\x00\x00\xad\xab\xe1|\x91U\x00\x00\x00\xd8\xa3%\x
94U\x00\x00\xe0\xd8\xa3%\x94U\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0
0\x00\x00\x81\x00\x00\x00\x00\x00\x00\x00\xc0j\xa3%\x94U\x00\x00p\x14\xa3%\x94
U\x00\x00 \x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00=\x8d\xe1|\
x91U\x00\x004055Z\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x0
0\x00\x00]\x8c\xe1|\x91U\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\
x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00]\x8f\xe1|\x91U\x00\x00p\xd5\xa3%\
x94U\x00\x00 \x01\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x00\x00\x00\x00\x8d\x98
\xe1|\x91U\x00\x00\x06\x0c\x02us1 0\x1e\x06\x03U\x04\n\x0c\x17securetrust corp
oration1\x190\x17\x06\x03U\x04\x03\x0c\x10secure global ca\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00q\x03\x00\x00\x00\x00\x00\x00`\x9a\xa3%\x9
4U\x00\x00p\x88\xa3%\x94U\x00\x00oration\x00A\x00\x00\x00\x00\x00\x00\x00\x00\
xd6\xa3%\x94U\x00\x00p\xd7\xa3%\x94U\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00!\
x00\x00\x00\x00\x00\x00\x00\xc0j\xa3%\x94U\x00\x00P\xb7\xa3%\x94U\x00\x00`\x00
\x00\x00\x00\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00M\x8e\xe1|\x91U\x00\x00\x
00\x00\x00\x00\x00\x00\x00\x00\xe0\xda\xa3%\x94U\x00\x00\x90\xd6\xa3%\x94U\x00
\x00J\x00\x00\x00\x00\x00\x00\x00A\x00\x00\x00\x00\x00\x00\x00\xc0j\xa3%\x94U\
x00\x00\x00\xd6\xa3%\x94U\x00\x00 \x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x0
0\x00\x00\x00\xbd\x8f\xe1|\x91U\x00\x00ust CA\x00\x00\xd0\x00\x00\x00\x00\x00\
x00\x00@\x00\x00\x00\x00\x00\x00\x00]\t\xe1|\x91U\x00\x00\x00\x00\x00\x00\x00\
x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0
0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
x00\x00\x00\x00\x81\x00\x00\x00\x00\x00\x00\x00'                              
root@memtest ~# ./sample.py heap.bin                   
=== 760f000 ===                                                               
b'\x05\x000A1\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x140\x12\x06\x03U\x04\n\x0c\x
0bAffirmTrust1\x1c0\x1a\x06\x03U\x04\x03\x0c\x13AffirmTrust Premium0\x1e\x17\r
100129141036Z\x17\r401231141036Z0A1\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x140\x1
2\x06\x03U\x04\n\x0c\x0bAffirmTrust1\x1c0\x1a\x06\x03U\x04\x03\x0c\x13AffirmTr
ust Premium0\x82\x02"0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x82\x02
\x0f\x000\x82\x02\n\x02\x82\x02\x01\x00\xc4\x12\xdf\xa9_\xfeA\xdd\xdd\xf5\x9f\
x8a\xe3\xf6\xac\xe1Q\xa7\xd1"\xc4\n\xa78Hl\xb3\
xf9\xff}\xab\x86W\xe3\xba\xd6\x85xw\xbaC\xeaH\x7f\xf6\xd8\xbe#m\x1e\xbf\xd16lX
\\\xf1\xee\xa4\x19T\x1a\xf5\x03\xd2v\xe6\xe1\x8c\xbd<\xb3\xd3HK\xe2\xc8\xf8\x7
f\x92\xa8vF\x9cBe>\xa4\x1e\xc1\x07\x03ZF-\xb8\x97\xf3\xb7\xd5\xb2U!\xef\xba\xd
cL\x00\x97\xfb\x14\x95\'3\xbf\xe8CGF\xd2\x08\x99\x16`;\x9a~\xd2\xe6\xed8\xea\x
ec\x01\x1e\x10\xe5\x0b\x03\xc9\
x9aB\x00l\xc5\x94~a\xc4\x8a\xdf\x7f\x82\x1a\x0bY\xc4Y2w\xb3\xbc`iV9\xfd\xb4\x0
6{,\xd6d6\xd9\xbdH\xed\x84\x1f~\xa5"\x8f*\xb8B\xf4\x82\xb7\xd4S\x90xN-\x1a\xfd
\x81oD\xd7;\x01t\x96B\xe0\x00\xe2.k\xea\xc5\xeer\xac\xbb\xbf\xfe\xea\xaa\xa8\x
f8\xdc\xf6\xb2y\x8a\xb6g\x02\x03\x01\x00\x01\xa3B0@0\x1d\x06\x03U\x1d\x0e\x04\
x16\x04\x14\x9d\xc0g\xa6\x0c"\xd9&\xf5E\xab\xa6eR\x11\'\xd8E\xacc0\x0f\x06\x03
U\x1d\x13\x01\x01\xff\x04\x050\x03\x01\x01\xff0\x0e\x06\x03U\x1d\x0f\x01\x01\x
ff\x04\x04\x03\x02\x01\x06\x9b\x1f\x94U\x00\x00\x11\x02\x00\x00\x00\x00\x00\x0
0\xb3WM\x10bN:\xe4\xac\xea\xb8\x1c\xaf2#\xc8\xb3IZQ\x9cv(\x8dy\xaaWF\x17\xd5\x
f5R\xf6\xb7D\xe8\x08D\xbf\x18\x84\xd2\x0b\x80\xcd\xc5\x12\xfd\x00U\x05a\x87A\x
dc\xb5$\x9e<\xc4\xd8\xc8\xfbp\x9e/x\x96\x83 6\xde|\x0fi\x13\x88\xa5u6\x98\x08\
xa6\xc6\xdf\xac\xce\xe3X\xd6\xb7>\xde\xba\xf3\xeb4@\xd8\xa2\x81\xf5x?/\xd5\xa5
\xfc\xd9\xa2\xd4^\x04\x0e\x17\xad\xfeA\xf0\xe5\xb2r\xfaD\x823B\xe8-X\xf7V\x8cb
?\xbaB\xb0\x9c\x0c\\~.e&\\SO\x00\xb2x~\xa1\r\x99-\x8d\xb8\x1d\x8e\xa2\xc4\xb0\
xfd`\xd00\xa4\x8e\xc8\x04b\xa9\xc4\xed5\xdez\x97\xed\x0e8^\x92/\x93p\xa5\xa9\x
9co\xa7}\x13\x1d~\xc6\x08H\xb1^g\xebQ\x08%\xe9\xe6%kR)\x91\x9c\xd29s\x08W\xde

All these strings appear somewhere in certifi's CA bundle, so I suspected this is somehow related to us calling context.load_verify_locations(certifi.where()). After spending quite some time on this I found python/cpython#84904, which surprisingly reproduces with pyOpenSSL instead of stdlib:

import os
import gc
import asyncio

from OpenSSL import SSL
import certifi
import psutil

ca_path = certifi.where()
proc = psutil.Process(os.getpid())


async def make_context(sleep: bool) -> None:
    ctx = SSL.Context(SSL.TLS_CLIENT_METHOD)
    ctx.load_verify_locations(ca_path)
    if sleep:
        await asyncio.sleep(1)


async def main(n: int, sleep: bool) -> None:
    await asyncio.wait([asyncio.create_task(make_context(sleep)) for _ in range(n)])


print("=== without sleep ===")
for _ in range(20):
    asyncio.run(main(200, False))
    gc.collect()
    print(f"{proc.memory_info().rss=:>10}")

print("=== with sleep ===")
for _ in range(20):
    asyncio.run(main(200, True))
    gc.collect()
    print(f"{proc.memory_info().rss=:>10}")
Ubuntu 22.04 Output
# python3.10 repro.py
=== without sleep ===
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
proc.memory_info().rss=  31494144
=== with sleep ===
proc.memory_info().rss= 181592064  # whoops
proc.memory_info().rss= 181862400  # but now it stays constant?
proc.memory_info().rss= 181862400
proc.memory_info().rss= 181862400
proc.memory_info().rss= 181862400
proc.memory_info().rss= 181862400
proc.memory_info().rss= 181862400
proc.memory_info().rss= 181862400
proc.memory_info().rss= 181862400
proc.memory_info().rss= 181862400
proc.memory_info().rss= 181501952
proc.memory_info().rss= 181501952
proc.memory_info().rss= 181501952
proc.memory_info().rss= 181501952
proc.memory_info().rss= 181501952
proc.memory_info().rss= 181501952
proc.memory_info().rss= 181501952
proc.memory_info().rss= 181501952
proc.memory_info().rss= 181501952
proc.memory_info().rss= 181501952
Windows 10 Output
# python3.10 repro.py
=== without sleep ===
proc.memory_info().rss=  28827648
proc.memory_info().rss=  29130752
proc.memory_info().rss=  29167616
proc.memory_info().rss=  28848128
proc.memory_info().rss=  29155328
proc.memory_info().rss=  29188096
proc.memory_info().rss=  29220864
proc.memory_info().rss=  29184000
proc.memory_info().rss=  29200384
proc.memory_info().rss=  29237248
proc.memory_info().rss=  29270016
proc.memory_info().rss=  29224960
proc.memory_info().rss=  29224960
proc.memory_info().rss=  29261824
proc.memory_info().rss=  29249536
proc.memory_info().rss=  29257728
proc.memory_info().rss=  29298688
proc.memory_info().rss=  29274112
proc.memory_info().rss=  29265920
proc.memory_info().rss=  29229056
=== with sleep ===
proc.memory_info().rss=  30277632  # much better here...
proc.memory_info().rss=  31203328
proc.memory_info().rss=  32108544
proc.memory_info().rss=  31698944
proc.memory_info().rss=  31838208
proc.memory_info().rss=  31657984
proc.memory_info().rss=  75530240  # surprise!
proc.memory_info().rss=  32440320  # and we're back...
proc.memory_info().rss=  77365248  # ... up again!
proc.memory_info().rss=  77135872
proc.memory_info().rss=  81215488
proc.memory_info().rss=  79491072
proc.memory_info().rss=  78475264
proc.memory_info().rss=  78393344
proc.memory_info().rss=  32808960
proc.memory_info().rss=  86007808
proc.memory_info().rss=  82329600
proc.memory_info().rss=  83742720
proc.memory_info().rss=  87388160
proc.memory_info().rss=  90755072
proc.memory_info().rss=  89395200
proc.memory_info().rss=  98418688
proc.memory_info().rss=  87658496
proc.memory_info().rss=  95277056
proc.memory_info().rss=  97841152
proc.memory_info().rss=  97341440
proc.memory_info().rss=  96702464
proc.memory_info().rss=  99598336
proc.memory_info().rss=  98127872
proc.memory_info().rss= 100098048
proc.memory_info().rss= 103292928
proc.memory_info().rss=  94601216
proc.memory_info().rss=  95272960
proc.memory_info().rss=  96559104
proc.memory_info().rss=  93630464
proc.memory_info().rss=  99307520
proc.memory_info().rss= 102895616
proc.memory_info().rss=  99205120
proc.memory_info().rss= 106471424
proc.memory_info().rss= 102260736
proc.memory_info().rss=  31555584  # back down! maybe all fine on Windows and just GC after all?
proc.memory_info().rss=  99848192
proc.memory_info().rss=  32423936
proc.memory_info().rss= 103653376
proc.memory_info().rss=  31727616
proc.memory_info().rss= 106827776
proc.memory_info().rss= 103124992
proc.memory_info().rss= 100532224
proc.memory_info().rss= 100294656
proc.memory_info().rss= 106164224

So yeah - I'm a bit at a loss what's going on here. Any ideas? I think that the call to load_verify_locations() may not be the actual suspect, I still see a memory increase when commenting out that line (just much less pronounced). For mitmproxy, it looks like OpenSSL 3 finally has the APIs we need to share contexts more broadly (which should alleviate the problem in our case), but independent of that it looks like something is weirdly wrong here.

Footnotes

  1. I've also no idea where _lib.c comes from. Maybe I'm missing something, but it looks like there's no such file in either cryptography, cffi, or OpenSSL.

You see this even with latest cryptography right? I ask because there was a memory leak they fixed in openssl 3.0.3, which we shipped in 37.0.2.

mhils commented

Ah yes, sorry - I forgot to specify version information:

Python: 3.10.4
cryptography: 37.0.2 (precompiled wheels)
pyOpenSSL: 22.0.0

Never the easy answer 😅

mhils commented

One more interesting observation using a slightly modified repro:

for ctxs in [10, 20, 30, 40, 50, 60, 70, 80, 90, 80, 70, 60, 50, 40, 30, 20, 10]:
    asyncio.run(main(ctxs, True))
    gc.collect()
    print(f"{ctxs=} {proc.memory_info().rss=:>10}")
ctxs=10 proc.memory_info().rss=  28692480
ctxs=20 proc.memory_info().rss=  36024320
ctxs=30 proc.memory_info().rss=  43335680
ctxs=40 proc.memory_info().rss=  50630656
ctxs=50 proc.memory_info().rss=  57946112
ctxs=60 proc.memory_info().rss=  65241088
ctxs=70 proc.memory_info().rss=  72556544
ctxs=80 proc.memory_info().rss=  79863808
ctxs=90 proc.memory_info().rss=  87158784
ctxs=80 proc.memory_info().rss=  87162880
ctxs=70 proc.memory_info().rss=  87171072
ctxs=60 proc.memory_info().rss=  87171072
ctxs=50 proc.memory_info().rss=  87171072
ctxs=40 proc.memory_info().rss=  87171072
ctxs=30 proc.memory_info().rss=  87171072
ctxs=20 proc.memory_info().rss=  87171072
ctxs=10 proc.memory_info().rss=  87171072

image

The relationship between the number of allocated contexts and the memory usage is perfectly linear, it just doesn't go down when reducing the number of contexts. For a regular memory leak, we'd expect it to be superlinear due to the increase in contexts per iteration. Seems like OpenSSL is able to reuse memory, but never lets go of it (?).

Edit: More fun stuff: It looks like calling ctypes.CDLL('libc.so.6').malloc_trim(0) releases back most the memory! I now see a much subtler increase over time...

What's special to asyncio code here? The certificate handling is exactly the same as the sync version, what changes with asyncio is that BIOs are used instead of sockets for the connection.

This should happen even on a sync test.