Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci: add open fds valgrind check #4851

Merged
merged 21 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ if (BUILD_TESTING)
--error-limit=no \
--num-callers=40 \
--undef-value-errors=no \
--track-fds=yes \
--log-fd=2 \
--suppressions=valgrind.suppressions")

Expand Down
65 changes: 65 additions & 0 deletions codebuild/bin/s2n_open_fds_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
jmayclin marked this conversation as resolved.
Show resolved Hide resolved
# SPDX-License-Identifier: Apache-2.0

# This script parses the LastDynamicAnalysis file generated by CTest Memcheck.
boquan-fang marked this conversation as resolved.
Show resolved Hide resolved
# It identifies any leaking file descriptors and triggers an error when detected.
# This enhances the capabilities of existing Valgrind checks.
# Output snippet for open file descriptors:
# FILE DESCRIPTORS: 6 open (3 std) at exit.
# ==6652== Open AF_INET socket 6: 127.0.0.1:36915 <-> unbound
# ==6652== at 0x498B2EB: socket (syscall-template.S:120)
# ==6652== by 0x16CD16: s2n_new_inet_socket_pair (s2n_self_talk_ktls_test.c:69)
# ==6652== by 0x15DBB2: main (s2n_self_talk_ktls_test.c:168)
# ==6652==
import os
jmayclin marked this conversation as resolved.
Show resolved Hide resolved
import sys

# Exit with error code 1 if leaking fds are detected.
ERROR_EXIT_CODE = 1
# This test is designed to be informational, so we only print five lines when a leak is detected.
NUM_OF_LINES_TO_PRINT = 5


def open_analysis_file(path):
for fl in os.listdir(path):
boquan-fang marked this conversation as resolved.
Show resolved Hide resolved
if "LastDynamicAnalysis" in fl:
file = open(os.path.join(path, fl), 'r')
return file


def read_analysis_file(file):
jmayclin marked this conversation as resolved.
Show resolved Hide resolved
exit_code = 0
jmayclin marked this conversation as resolved.
Show resolved Hide resolved
lines = file.readlines()
for i in range(len(lines)):
jmayclin marked this conversation as resolved.
Show resolved Hide resolved
if "FILE DESCRIPTORS:" in lines[i]:
line_elements = lines[i].split()
# The element after "FILE DESCRIPTORS:" is the number of fds that remain opened at exit.
open_fd_number = line_elements[line_elements.index("DESCRIPTORS:") + 1]
jmayclin marked this conversation as resolved.
Show resolved Hide resolved
# The element before "std)" is a open parenthesis followed by the number of std fds at exit.
# Hence, we remove the open parenthesis and only take the number.
std_fd_number = line_elements[line_elements.index("std)") - 1][1:]
# The only open fd we allowed other than std fds are the fd pointing to the LastDynamicAnalysis log file.
# Hence, the number of open fds should be exactly one more than the number of open std fds.
if int(open_fd_number) - int(std_fd_number) > 1:
print(lines[i], end=" ")
for j in range(NUM_OF_LINES_TO_PRINT):
print(lines[i + j + 1], end=" ")
boquan-fang marked this conversation as resolved.
Show resolved Hide resolved
exit_code = ERROR_EXIT_CODE
file.close()
return exit_code
jmayclin marked this conversation as resolved.
Show resolved Hide resolved


def print_banner():
print("############################################################################")
print("################# Test for Leaking File Descriptors ########################")
print("############################################################################")


def main():
jmayclin marked this conversation as resolved.
Show resolved Hide resolved
print_banner()
file = open_analysis_file(sys.argv[1])
return read_analysis_file(file)


if __name__ == '__main__':
sys.exit(main())
2 changes: 2 additions & 0 deletions codebuild/spec/buildspec_valgrind.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,5 @@ phases:
CTEST_OUTPUT_ON_FAILURE=1 \
cmake --build build/ --target test \
-- ARGS="--test-action memcheck"
- cd codebuild/bin
- python3 s2n_open_fds_test.py $CODEBUILD_SRC_DIR/build/Testing/Temporary
Loading