Skip to content

Commit dff24c8

Browse files
tpamborkartben
authored andcommitted
twister: Fix race condition in try_making_symlink
Replaces the check-then-create pattern for symlinks with opportunistic creation. Instead of checking for existence before creating the symlink, the code now attempts to create it directly and gracefully handles the case where it already exists. Signed-off-by: Tim Pambor <[email protected]>
1 parent 4c1c954 commit dff24c8

File tree

1 file changed

+20
-11
lines changed

1 file changed

+20
-11
lines changed

scripts/pylib/twister/twisterlib/coverage.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,11 @@ def try_making_symlink(source: str, link: str):
518518
source (str): The path to the source file.
519519
link (str): The path where the symbolic link should be created.
520520
"""
521-
if os.path.exists(link):
521+
symlink_error = None
522+
523+
try:
524+
os.symlink(source, link)
525+
except FileExistsError:
522526
if os.path.islink(link):
523527
if os.readlink(link) == source:
524528
# Link is already set up
@@ -529,19 +533,24 @@ def try_making_symlink(source: str, link: str):
529533
# File contents are the same
530534
return
531535

532-
# link exists, but points to a different file, remove the link. We'll
533-
# try to create a new one below
534-
os.remove(link)
535-
536-
# Create the symlink
537-
try:
538-
os.symlink(source, link)
536+
# link exists, but points to a different file. We'll create a new link
537+
# and replace it atomically with the old one
538+
temp_filename = f"{link}.{os.urandom(8).hex()}"
539+
try:
540+
os.symlink(source, temp_filename)
541+
os.replace(temp_filename, link)
542+
except OSError as e:
543+
symlink_error = e
539544
except OSError as e:
545+
symlink_error = e
546+
547+
if symlink_error:
540548
logger.error(
541-
"Error creating symlink: %s, attempting to copy.", str(e)
549+
"Error creating symlink: %s, attempting to copy.", str(symlink_error)
542550
)
543-
shutil.copy(source, link)
544-
551+
temp_filename = f"{link}.{os.urandom(8).hex()}"
552+
shutil.copy(source, temp_filename)
553+
os.replace(temp_filename, link)
545554

546555
def choose_gcov_tool(options, is_system_gcov):
547556
gcov_tool = None

0 commit comments

Comments
 (0)