mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-17 16:47:50 +00:00
coredump: fix file handle leak in _gen_mem_chunk
Use ExitStack to ensure the conditionally-opened file for FILE_SHARED/FILE_PRIVATE VMAs is always closed, even if an exception occurs during seek or page iteration. Assisted-by: Claude Code (claude-opus-4-6) Signed-off-by: Adrian Reber <areber@redhat.com>
This commit is contained in:
parent
b0057d1873
commit
7e482031b6
1 changed files with 67 additions and 66 deletions
|
|
@ -32,6 +32,7 @@ import io
|
||||||
import sys
|
import sys
|
||||||
import ctypes
|
import ctypes
|
||||||
import platform
|
import platform
|
||||||
|
from contextlib import ExitStack
|
||||||
|
|
||||||
from pycriu import images
|
from pycriu import images
|
||||||
from . import elf
|
from . import elf
|
||||||
|
|
@ -872,86 +873,86 @@ class coredump_generator:
|
||||||
# current process.
|
# current process.
|
||||||
return b"\0" * size
|
return b"\0" * size
|
||||||
|
|
||||||
if vma["status"] & status["VMA_FILE_SHARED"] or \
|
# ExitStack ensures the file opened below (if any) is closed
|
||||||
vma["status"] & status["VMA_FILE_PRIVATE"]:
|
# when the block exits, even if an exception is raised.
|
||||||
# Open file before iterating vma pages
|
with ExitStack() as stack:
|
||||||
shmid = vma["shmid"]
|
if vma["status"] & status["VMA_FILE_SHARED"] or \
|
||||||
off = vma["pgoff"]
|
vma["status"] & status["VMA_FILE_PRIVATE"]:
|
||||||
|
# Open file before iterating vma pages
|
||||||
|
shmid = vma["shmid"]
|
||||||
|
off = vma["pgoff"]
|
||||||
|
|
||||||
files = self.reg_files
|
files = self.reg_files
|
||||||
fname = next(filter(lambda x: x["id"] == shmid, files))["name"]
|
fname = next(
|
||||||
|
filter(lambda x: x["id"] == shmid, files))["name"]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
f = open(fname, 'rb')
|
f = stack.enter_context(open(fname, 'rb'))
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
sys.exit('Required file %s not found.' % fname)
|
sys.exit('Required file %s not found.' % fname)
|
||||||
|
|
||||||
f.seek(off)
|
f.seek(off)
|
||||||
|
|
||||||
start = vma["start"]
|
start = vma["start"]
|
||||||
end = vma["start"] + size
|
end = vma["start"] + size
|
||||||
|
|
||||||
# Split requested memory chunk into pages, so it could be
|
# Split requested memory chunk into pages, so it could be
|
||||||
# pictured as:
|
# pictured as:
|
||||||
#
|
#
|
||||||
# "----" -- part of page with memory outside of our vma;
|
# "----" -- part of page with memory outside of our vma;
|
||||||
# "XXXX" -- memory from our vma;
|
# "XXXX" -- memory from our vma;
|
||||||
#
|
#
|
||||||
# Start page Pages in the middle End page
|
# Start page Pages in the middle End page
|
||||||
# [-----XXXXX]...[XXXXXXXXXX][XXXXXXXXXX]...[XXX-------]
|
# [-----XXXXX]...[XXXXXXXXXX][XXXXXXXXXX]...[XXX-------]
|
||||||
#
|
#
|
||||||
# Each page could be found in pages.img or in a standalone
|
# Each page could be found in pages.img or in a standalone
|
||||||
# file described by shmid field in vma entry and
|
# file described by shmid field in vma entry and
|
||||||
# corresponding entry in reg-files.img.
|
# corresponding entry in reg-files.img.
|
||||||
# For VMA_FILE_PRIVATE vma, unchanged pages are taken from
|
# For VMA_FILE_PRIVATE vma, unchanged pages are taken from
|
||||||
# a file, and changed ones -- from pages.img.
|
# a file, and changed ones -- from pages.img.
|
||||||
# Finally, if no page is found neither in pages.img nor
|
# Finally, if no page is found neither in pages.img nor
|
||||||
# in file, hole in inserted -- a page filled with zeroes.
|
# in file, hole in inserted -- a page filled with zeroes.
|
||||||
start_page = start // PAGESIZE
|
start_page = start // PAGESIZE
|
||||||
end_page = end // PAGESIZE
|
end_page = end // PAGESIZE
|
||||||
|
|
||||||
buf = b""
|
buf = b""
|
||||||
for page_no in range(start_page, end_page + 1):
|
for page_no in range(start_page, end_page + 1):
|
||||||
page = None
|
page = None
|
||||||
|
|
||||||
# Search for needed page in pages.img and reg-files.img
|
# Search for needed page in pages.img and reg-files.img
|
||||||
# and choose appropriate.
|
# and choose appropriate.
|
||||||
page_mem = self._get_page(pid, page_no)
|
page_mem = self._get_page(pid, page_no)
|
||||||
|
|
||||||
if f is not None:
|
if f is not None:
|
||||||
page = f.read(PAGESIZE)
|
page = f.read(PAGESIZE)
|
||||||
|
|
||||||
if page_mem is not None:
|
if page_mem is not None:
|
||||||
# Page from pages.img has higher priority
|
# Page from pages.img has higher priority
|
||||||
# than one from mapped file on disk.
|
# than one from mapped file on disk.
|
||||||
page = page_mem
|
page = page_mem
|
||||||
|
|
||||||
if page is None:
|
if page is None:
|
||||||
# Hole
|
# Hole
|
||||||
page = PAGESIZE * b"\0"
|
page = PAGESIZE * b"\0"
|
||||||
|
|
||||||
# If it is a start or end page, we need to read
|
# If it is a start or end page, we need to read
|
||||||
# only part of it.
|
# only part of it.
|
||||||
if page_no == start_page:
|
if page_no == start_page:
|
||||||
n_skip = start - page_no * PAGESIZE
|
n_skip = start - page_no * PAGESIZE
|
||||||
if start_page == end_page:
|
if start_page == end_page:
|
||||||
n_read = size
|
n_read = size
|
||||||
|
else:
|
||||||
|
n_read = PAGESIZE - n_skip
|
||||||
|
elif page_no == end_page:
|
||||||
|
n_skip = 0
|
||||||
|
n_read = end - page_no * PAGESIZE
|
||||||
else:
|
else:
|
||||||
n_read = PAGESIZE - n_skip
|
n_skip = 0
|
||||||
elif page_no == end_page:
|
n_read = PAGESIZE
|
||||||
n_skip = 0
|
|
||||||
n_read = end - page_no * PAGESIZE
|
|
||||||
else:
|
|
||||||
n_skip = 0
|
|
||||||
n_read = PAGESIZE
|
|
||||||
|
|
||||||
buf += page[n_skip:n_skip + n_read]
|
buf += page[n_skip:n_skip + n_read]
|
||||||
|
|
||||||
# Don't forget to close file.
|
return buf
|
||||||
if f is not None:
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
return buf
|
|
||||||
|
|
||||||
def _gen_cmdline(self, pid):
|
def _gen_cmdline(self, pid):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue