René's URL Explorer Experiment


Title: bpo-21872: fix lzma library decompresses data incompletely · Pull Request #14048 · python/cpython · GitHub

Open Graph Title: bpo-21872: fix lzma library decompresses data incompletely · Pull Request #14048 · python/cpython

X Title: bpo-21872: fix lzma library decompresses data incompletely · Pull Request #14048 · python/cpython

Description: Why this bug happens? lzma_stream structure is used for passing input and output buffers to liblzma library: typedef struct { const uint8_t *next_in; /* Pointer to the next input byte. */ size_t avail_in; /* Number of available input bytes in next_in. */ uint64_t total_in; /* Total number of bytes read by liblzma. */ uint8_t *next_out; /* Pointer to the next output position. */ size_t avail_out; /* Amount of free space in next_out. */ uint64_t total_out; /* Total number of bytes written by liblzma. */ ... lzma_internal *internal; /* Internal state is not visible to applications. */ ... } There is a possibility: when the input and output buffers are exhausted at the same time, lzma_stream's internal state may still hold a few bytes that are not output. When the last data chunk inputted, and this happened to happen, those bytes will never be output. I modified Jeffrey Kintscher's code and _lzmamodule.c to test all attached bad files in issue21872, here is the statistic: The first column is the number of missing bytes. The second column is number of occurrences. 2 bytes: 96 3 bytes: 72 11 bytes: 57 1 bytes: 55 6 bytes: 55 5 bytes: 52 0 bytes: 49 <- please note 10 bytes: 46 4 bytes: 42 9 bytes: 39 12 bytes: 36 7 bytes: 32 8 bytes: 26 14 bytes: 15 13 bytes: 14 15 bytes: 4 18 bytes: 1 27 bytes: 1 0 missing bytes means: although input and output buffers are exhausted at the same time, but internal state doesn't hold any bytes that can be output. Fix the bug To fix this bug, just let these missing bytes be output. There are two situations, need to be handled separately: when max_length < 0, the output buffer can grow unlimitedly. when max_length >= 0, the max length of output buffer is specified. max_length is a parameter of LZMADecompressor.decompress(data, max_length=-1) function. Commit 1, add test case with wrong behavior ISSUE_21872_DAT comes from: https://bugs.python.org/issue21872 attached file more_bad_lzma_files.zip uploaded by vnummela the smallest file 07_21h_ticks.bi5 in the .zip file The file size is 2,835 bytes. Commit 2, fix bug when max_length < 0 If max_length < 0, the output buffer can grow unlimitedly. Before this commit: for (;;) { lzret = lzma_code(lzs, LZMA_RUN); ... if (lzret == LZMA_STREAM_END) { // stream finished d->eof = 1; break; } else if (lzs->avail_in == 0) { // input buffer exhausted break; } else if (lzs->avail_out == 0) { // output buffer exhausted // when max_length < 0, output buffer can grow unlimitedly if (data_size == max_length) break; grow_output_buffer() } } When input buffer exhausted, lzs's internal state may still hold a few bytes. If no more input data, these bytes will never be output, and d->eof marker will never be set. Now let's first determine if the output buffer is exhausted. If the output buffer is exhausted, we grow the output buffer and loop again, then all decompressed data can be output. Commit 3, allow b"" as valid input data for decompress_buf() This commit is a prerequisite for Commit 4. This code doesn't allow empty bytes b"" as a valid input data for decompress_buf() function: if (lzs->avail_in == 0) return PyBytes_FromStringAndSize(NULL, 0); Above code was introduced in issue27517. After reading issue27517's context and changeset, we can follow the similar code for function compress(): lzret = lzma_code(lzs, LZMA_RUN); ... + if (lzret == LZMA_BUF_ERROR && lzs->avail_in == 0 && lzs->avail_out > 0) + lzret = LZMA_OK; /* That wasn't a real error */ Above code has the same effect for issue27517's problem. In addition it allows b"" as a valid input data. FYI, liblzma's document about return code LZMA_BUF_ERROR: LZMA_BUF_ERROR = 10, /* * brief No progress is possible * * This error code is returned when the coder cannot consume * any new input and produce any new output. The most common * reason for this error is that the input stream being * decoded is truncated or corrupt. * * This error is not fatal. Coding can be continued normally * by providing more input and/or more output space, if * possible. * * Typically the first call to lzma_code() that can do no * progress returns LZMA_OK instead of LZMA_BUF_ERROR. Only * the second consecutive call doing no progress will return * LZMA_BUF_ERROR. This is intentional. * * With zlib, Z_BUF_ERROR may be returned even if the * application is doing nothing wrong, so apps will need * to handle Z_BUF_ERROR specially. The above hack * guarantees that liblzma never returns LZMA_BUF_ERROR * to properly written applications unless the input file * is truncated or corrupt. This should simplify the * applications a little. */ Long story short: When pass zero-space input or/and output buffers to lzma_code(), return this error code at the second call to lzma_code(). This error is not fatal, we can ignore it. Commit 4, when max_length >= 0, let needs_input mechanism works This commit lets needs_input mechanism in function DecompressReader.read(size=-1) works. When (lzs->avail_in==0 && lzs->avail_out==0), lzs's internal state may still have a few bytes can be output. If no more input data, these bytes will never be output, and d->eof marker will never be set. Set needs_input = 0, then b"" will be passed as input data next time. So it has a chance to output these bytes. Some points for code review 1, Make sure DecompressReader.read(size=-1) function will not loop infinitely due to needs_input mechanism. 2, Make sure lzma.decompress(data, format=FORMAT_AUTO, memlimit=None, filters=None) function will not loop infinitely. 3, When max_length == 0 (almost impossible situation), LZMADecompressor.decompress(data, max_length=-1) function has expected behavior: >>> from _lzma import LZMADecompressor >>> d = LZMADecompressor() >>> d.decompress(b'', 0) b'' >>> d.decompress(b'', 0) Traceback (most recent call last): File "", line 1, in _lzma.LZMAError: Insufficient buffer space As expected, return LZMA_BUF_ERROR when the second call to lzma_code(). https://bugs.python.org/issue21872

Open Graph Description: Why this bug happens? lzma_stream structure is used for passing input and output buffers to liblzma library: typedef struct { const uint8_t *next_in; /* Pointer to the next input byte. */ size_t ...

X Description: Why this bug happens? lzma_stream structure is used for passing input and output buffers to liblzma library: typedef struct { const uint8_t *next_in; /* Pointer to the next input byte. */ size_t ...

Opengraph URL: https://github.com/python/cpython/pull/14048

X: @github

direct link

Domain: github.com

route-pattern/:user_id/:repository/pull/:id/files(.:format)
route-controllerpull_requests
route-actionfiles
fetch-noncev2:6083b47f-1f69-9e52-c867-e4253a6c7309
current-catalog-service-hashae870bc5e265a340912cde392f23dad3671a0a881730ffdadd82f2f57d81641b
request-idA5FC:34224:14977A:1C9174:6A551818
html-safe-nonce3c9247c8a1fdbf928125800a184456c48c07b3f742cafd144af8f47f9dc82cba
visitor-payloadeyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJBNUZDOjM0MjI0OjE0OTc3QToxQzkxNzQ6NkE1NTE4MTgiLCJ2aXNpdG9yX2lkIjoiODg0OTM1NTE3MTEyNzY5NTM4NCIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9
visitor-hmac5796ed2dbda7fb6ab030c7279e897b446ee73243a62bbb710a65801d3a0074f5
hovercard-subject-tagpull_request:287843528
github-keyboard-shortcutsrepository,pull-request-list,pull-request-conversation,pull-request-files-changed,copilot
google-site-verificationApib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I
octolytics-urlhttps://collector.github.com/github/collect
analytics-location///pull_requests/show/files
fb:app_id1401488693436528
apple-itunes-appapp-id=1477376905, app-argument=https://github.com/python/cpython/pull/14048/files
twitter:imagehttps://avatars.githubusercontent.com/u/10137?s=400&v=4
twitter:cardsummary_large_image
og:imagehttps://avatars.githubusercontent.com/u/10137?s=400&v=4
og:image:altWhy this bug happens? lzma_stream structure is used for passing input and output buffers to liblzma library: typedef struct { const uint8_t *next_in; /* Pointer to the next input byte. */ size_t ...
og:site_nameGitHub
og:typeobject
hostnamegithub.com
expected-hostnamegithub.com
None682d273eacb2ac51680c6eb9c0b270f029f7ce74c32090f319083c34497e28a5
turbo-cache-controlno-preview
diff-viewunified
go-importgithub.com/python/cpython git https://github.com/python/cpython.git
octolytics-dimension-user_id1525981
octolytics-dimension-user_loginpython
octolytics-dimension-repository_id81598961
octolytics-dimension-repository_nwopython/cpython
octolytics-dimension-repository_publictrue
octolytics-dimension-repository_is_forkfalse
octolytics-dimension-repository_network_root_id81598961
octolytics-dimension-repository_network_root_nwopython/cpython
turbo-body-classeslogged-out env-production page-responsive full-width
disable-turbotrue
browser-stats-urlhttps://api.github.com/_private/browser/stats
browser-errors-urlhttps://api.github.com/_private/browser/errors
release3b6d37c6470adadff4194742daaab9a817cc4980
ui-targetfull
theme-color#1e2327
color-schemelight dark

Links:

Skip to contenthttps://github.com/python/cpython/pull/14048/files#start-of-content
https://github.com/
Sign in https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fpython%2Fcpython%2Fpull%2F14048%2Ffiles
GitHub CopilotWrite better code with AIhttps://github.com/features/copilot
GitHub Copilot appDirect agents from issue to mergehttps://github.com/features/ai/github-app
MCP RegistryNewIntegrate external toolshttps://github.com/mcp
ActionsAutomate any workflowhttps://github.com/features/actions
CodespacesInstant dev environmentshttps://github.com/features/codespaces
IssuesPlan and track workhttps://github.com/features/issues
Code ReviewManage code changeshttps://github.com/features/code-review
GitHub Advanced SecurityFind and fix vulnerabilitieshttps://github.com/security/advanced-security
Code securitySecure your code as you buildhttps://github.com/security/advanced-security/code-security
Secret protectionStop leaks before they starthttps://github.com/security/advanced-security/secret-protection
Why GitHubhttps://github.com/why-github
Documentationhttps://docs.github.com
Bloghttps://github.blog
Changeloghttps://github.blog/changelog
Marketplacehttps://github.com/marketplace
View all featureshttps://github.com/features
Enterpriseshttps://github.com/enterprise
Small and medium teamshttps://github.com/team
Startupshttps://github.com/enterprise/startups
Nonprofitshttps://github.com/solutions/industry/nonprofits
App Modernizationhttps://github.com/solutions/use-case/app-modernization
DevSecOpshttps://github.com/solutions/use-case/devsecops
DevOpshttps://github.com/solutions/use-case/devops
CI/CDhttps://github.com/solutions/use-case/ci-cd
View all use caseshttps://github.com/solutions/use-case
Healthcarehttps://github.com/solutions/industry/healthcare
Financial serviceshttps://github.com/solutions/industry/financial-services
Manufacturinghttps://github.com/solutions/industry/manufacturing
Governmenthttps://github.com/solutions/industry/government
View all industrieshttps://github.com/solutions/industry
View all solutionshttps://github.com/solutions
AIhttps://github.com/resources/articles?topic=ai
Software Developmenthttps://github.com/resources/articles?topic=software-development
DevOpshttps://github.com/resources/articles?topic=devops
Securityhttps://github.com/resources/articles?topic=security
View all topicshttps://github.com/resources/articles
Customer storieshttps://github.com/customer-stories
Events & webinarshttps://github.com/resources/events
Ebooks & reportshttps://github.com/resources/whitepapers
Business insightshttps://github.com/solutions/executive-insights
GitHub Skillshttps://skills.github.com
Documentationhttps://docs.github.com
Customer supporthttps://support.github.com
Community forumhttps://github.com/orgs/community/discussions
Trust centerhttps://github.com/trust-center
Partnershttps://github.com/partners
View all resourceshttps://github.com/resources
GitHub SponsorsFund open source developershttps://github.com/open-source/sponsors
Security Labhttps://securitylab.github.com
Maintainer Communityhttps://maintainers.github.com
Acceleratorhttps://github.com/open-source/accelerator
GitHub Starshttps://stars.github.com
Archive Programhttps://archiveprogram.github.com
Topicshttps://github.com/topics
Trendinghttps://github.com/trending
Collectionshttps://github.com/collections
Enterprise platformAI-powered developer platformhttps://github.com/enterprise
GitHub Advanced SecurityEnterprise-grade security featureshttps://github.com/security/advanced-security
Copilot for BusinessEnterprise-grade AI featureshttps://github.com/features/copilot/copilot-business
Premium SupportEnterprise-grade 24/7 supporthttps://github.com/enterprise/premium-support
Pricinghttps://github.com/pricing
Search syntax tipshttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
documentationhttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
Sign in https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fpython%2Fcpython%2Fpull%2F14048%2Ffiles
Sign up https://github.com/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fpull_requests%2Fshow%2Ffiles&source=header-repo&source_repo=python%2Fcpython
Reloadhttps://github.com/python/cpython/pull/14048/files
Reloadhttps://github.com/python/cpython/pull/14048/files
Reloadhttps://github.com/python/cpython/pull/14048/files
Please reload this pagehttps://github.com/python/cpython/pull/14048/files
python https://github.com/python
cpythonhttps://github.com/python/cpython
Please reload this pagehttps://github.com/python/cpython/pull/14048/files
Notifications https://github.com/login?return_to=%2Fpython%2Fcpython
Fork 35k https://github.com/login?return_to=%2Fpython%2Fcpython
Star 73.8k https://github.com/login?return_to=%2Fpython%2Fcpython
Code https://github.com/python/cpython
Issues 5k+ https://github.com/python/cpython/issues
Pull requests 2.3k https://github.com/python/cpython/pulls
Actions https://github.com/python/cpython/actions
Projects https://github.com/python/cpython/projects
Security and quality 0 https://github.com/python/cpython/security
Insights https://github.com/python/cpython/pulse
Code https://github.com/python/cpython
Issues https://github.com/python/cpython/issues
Pull requests https://github.com/python/cpython/pulls
Actions https://github.com/python/cpython/actions
Projects https://github.com/python/cpython/projects
Security and quality https://github.com/python/cpython/security
Insights https://github.com/python/cpython/pulse
Sign up for GitHub https://github.com/signup?return_to=%2Fpython%2Fcpython%2Fissues%2Fnew%2Fchoose
terms of servicehttps://docs.github.com/terms
privacy statementhttps://docs.github.com/privacy
Sign inhttps://github.com/login?return_to=%2Fpython%2Fcpython%2Fissues%2Fnew%2Fchoose
gpsheadhttps://github.com/gpshead
python:masterhttps://github.com/python/cpython/tree/master
Conversation 13 https://github.com/python/cpython/pull/14048
Commits 6 https://github.com/python/cpython/pull/14048/commits
Checks 0 https://github.com/python/cpython/pull/14048/checks
Files changed https://github.com/python/cpython/pull/14048/files
Please reload this pagehttps://github.com/python/cpython/pull/14048/files
bpo-21872: fix lzma library decompresses data incompletely https://github.com/python/cpython/pull/14048/files#top
Show all changes 6 commits https://github.com/python/cpython/pull/14048/files
1dbbfcf 1. add test case with wrong behavior wjssz Jun 12, 2019 https://github.com/python/cpython/pull/14048/commits/1dbbfcfce893b9cdb74758fcfae52da942a0b06e
ad5cdd1 2. fix bug when max_length == -1 wjssz Jun 12, 2019 https://github.com/python/cpython/pull/14048/commits/ad5cdd16ea4147131a3b9fcfc12cc21d2b059ec3
454b278 3. allow b"" as valid input data for decompress_buf() wjssz Jun 12, 2019 https://github.com/python/cpython/pull/14048/commits/454b278d6a671efe4cf340e81875f9f1a6b40816
594d525 4. when max_length >= 0, let needs_input mechanism works wjssz Jun 12, 2019 https://github.com/python/cpython/pull/14048/commits/594d525b5317c8ebf36cc1b43324bc1aa82cbb02
05951a6 add more asserts to test case wjssz Jun 14, 2019 https://github.com/python/cpython/pull/14048/commits/05951a674e32093d2dac43cdb6c7ce47072a0715
62ba236 update NEWS entry wjssz Jun 18, 2019 https://github.com/python/cpython/pull/14048/commits/62ba236f16bdc4cc05460597a6e32323b10fb435
Clear filters https://github.com/python/cpython/pull/14048/files
Please reload this pagehttps://github.com/python/cpython/pull/14048/files
Please reload this pagehttps://github.com/python/cpython/pull/14048/files
test_lzma.py https://github.com/python/cpython/pull/14048/files#diff-c0d354f43bb17a1ab769897c04ad70a9d5364b876cde66a0fa6ebf50f7db1fb6
2019-06-12-08-56-22.bpo-21872.V9QGGN.rst https://github.com/python/cpython/pull/14048/files#diff-32f673908facf94d46d58a01787d39b85e73a6e9b627aa4865288b25e35cc7e4
_lzmamodule.c https://github.com/python/cpython/pull/14048/files#diff-604739065f6d9a2f56bed1e9d1fd56b51e212e9acd630a92ccac9fe8390fa4d9
Lib/test/test_lzma.pyhttps://github.com/python/cpython/pull/14048/files#diff-c0d354f43bb17a1ab769897c04ad70a9d5364b876cde66a0fa6ebf50f7db1fb6
View file https://github.com/python/cpython/blob/62ba236f16bdc4cc05460597a6e32323b10fb435/Lib/test/test_lzma.py
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/python/cpython/pull/14048/{{ revealButtonHref }}
https://github.com/python/cpython/pull/14048/files#diff-c0d354f43bb17a1ab769897c04ad70a9d5364b876cde66a0fa6ebf50f7db1fb6
Please reload this pagehttps://github.com/python/cpython/pull/14048/files
Please reload this pagehttps://github.com/python/cpython/pull/14048/files
https://github.com/python/cpython/pull/14048/files#diff-c0d354f43bb17a1ab769897c04ad70a9d5364b876cde66a0fa6ebf50f7db1fb6
https://github.com/python/cpython/pull/14048/files#diff-c0d354f43bb17a1ab769897c04ad70a9d5364b876cde66a0fa6ebf50f7db1fb6
https://github.com/python/cpython/pull/14048/files#diff-c0d354f43bb17a1ab769897c04ad70a9d5364b876cde66a0fa6ebf50f7db1fb6
Misc/NEWS.d/next/Library/2019-06-12-08-56-22.bpo-21872.V9QGGN.rsthttps://github.com/python/cpython/pull/14048/files#diff-32f673908facf94d46d58a01787d39b85e73a6e9b627aa4865288b25e35cc7e4
View file https://github.com/python/cpython/blob/62ba236f16bdc4cc05460597a6e32323b10fb435/Misc/NEWS.d/next/Library/2019-06-12-08-56-22.bpo-21872.V9QGGN.rst
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/python/cpython/pull/14048/{{ revealButtonHref }}
Modules/_lzmamodule.chttps://github.com/python/cpython/pull/14048/files#diff-604739065f6d9a2f56bed1e9d1fd56b51e212e9acd630a92ccac9fe8390fa4d9
View file https://github.com/python/cpython/blob/62ba236f16bdc4cc05460597a6e32323b10fb435/Modules/_lzmamodule.c
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/python/cpython/pull/14048/{{ revealButtonHref }}
https://github.com/python/cpython/pull/14048/files#diff-604739065f6d9a2f56bed1e9d1fd56b51e212e9acd630a92ccac9fe8390fa4d9
https://github.com/python/cpython/pull/14048/files#diff-604739065f6d9a2f56bed1e9d1fd56b51e212e9acd630a92ccac9fe8390fa4d9
https://github.com/python/cpython/pull/14048/files#diff-604739065f6d9a2f56bed1e9d1fd56b51e212e9acd630a92ccac9fe8390fa4d9
https://github.com/python/cpython/pull/14048/files#diff-604739065f6d9a2f56bed1e9d1fd56b51e212e9acd630a92ccac9fe8390fa4d9
https://github.com/python/cpython/pull/14048/files#diff-604739065f6d9a2f56bed1e9d1fd56b51e212e9acd630a92ccac9fe8390fa4d9
https://github.com
Termshttps://docs.github.com/site-policy/github-terms/github-terms-of-service
Privacyhttps://docs.github.com/site-policy/privacy-policies/github-privacy-statement
Securityhttps://github.com/security
Statushttps://www.githubstatus.com/
Communityhttps://github.community/
Docshttps://docs.github.com/
Contacthttps://support.github.com?tags=dotcom-footer

Viewport: width=device-width


URLs of crawlers that visited me.