From patchwork Sat Jul 2 11:33:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alberto Faria X-Patchwork-Id: 1651461 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=CwsZW5qp; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LZqjf72GTz9s07 for ; Sat, 2 Jul 2022 21:34:46 +1000 (AEST) Received: from localhost ([::1]:59184 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1o7bOe-0003Dn-OC for incoming@patchwork.ozlabs.org; Sat, 02 Jul 2022 07:34:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51790) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1o7bNk-0002uc-N4 for qemu-devel@nongnu.org; Sat, 02 Jul 2022 07:33:48 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:49709) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1o7bNh-0007V6-2v for qemu-devel@nongnu.org; Sat, 02 Jul 2022 07:33:47 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1656761624; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=AVsjRvUFO7IRtcut4g0ir534oBEQ2f8ft4+r+hQg0BA=; b=CwsZW5qpPUVMQl5+E+BCovhIdgU5B/iFRhwpZR+qBePSCisB2LG/XbjnuZujvsqXIcHhlJ KbEPtfU+l/Z0FpMrSbm4uuqmQyXaEX94+BriyNdS2j3JHrfRR0RdCP7pY2M/tFmC6M1JoS KICNBNryLIR2VaTd1Cv/UPO6tiMFRy4= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-172-iacSVY3DPBqkML1rw_IxMA-1; Sat, 02 Jul 2022 07:33:41 -0400 X-MC-Unique: iacSVY3DPBqkML1rw_IxMA-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id A36F82999B2C; Sat, 2 Jul 2022 11:33:40 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.39.194.114]) by smtp.corp.redhat.com (Postfix) with ESMTP id 606C5492C3B; Sat, 2 Jul 2022 11:33:37 +0000 (UTC) From: Alberto Faria To: qemu-devel@nongnu.org Cc: Paolo Bonzini , qemu-block@nongnu.org, "Denis V. Lunev" , Emanuele Giuseppe Esposito , Stefan Hajnoczi , Ronnie Sahlberg , Hanna Reitz , Stefano Garzarella , Kevin Wolf , Peter Xu , Alberto Garcia , John Snow , Eric Blake , Fam Zheng , Markus Armbruster , Vladimir Sementsov-Ogievskiy , Peter Lieven , Alberto Faria Subject: [RFC 1/8] Add an extensible static analyzer Date: Sat, 2 Jul 2022 12:33:24 +0100 Message-Id: <20220702113331.2003820-2-afaria@redhat.com> In-Reply-To: <20220702113331.2003820-1-afaria@redhat.com> References: <20220702113331.2003820-1-afaria@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Received-SPF: pass client-ip=170.10.133.124; envelope-from=afaria@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -21 X-Spam_score: -2.2 X-Spam_bar: -- X-Spam_report: (-2.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.082, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Add a static-analyzer.py script that uses libclang's Python bindings to provide a common framework on which arbitrary static analysis checks can be developed and run against QEMU's code base. As an example, a simple check is included that verifies that the return value of static, non-void functions is used by at least one caller. Signed-off-by: Alberto Faria --- static-analyzer.py | 509 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 509 insertions(+) create mode 100755 static-analyzer.py diff --git a/static-analyzer.py b/static-analyzer.py new file mode 100755 index 0000000000..010cc92212 --- /dev/null +++ b/static-analyzer.py @@ -0,0 +1,509 @@ +#!/usr/bin/env python3 +# ---------------------------------------------------------------------------- # + +from __future__ import annotations + +from dataclasses import dataclass +import json +import os +import os.path +import subprocess +import sys +import re +from argparse import ArgumentParser, Namespace, RawDescriptionHelpFormatter +from multiprocessing import Pool +from pathlib import Path +from typing import ( + Any, + Callable, + Dict, + Iterable, + List, + NoReturn, + Optional, + Mapping, + Sequence, + Tuple, +) + +# ---------------------------------------------------------------------------- # + +from clang.cindex import ( # type: ignore + Cursor, + CursorKind, + Diagnostic, + StorageClass, + TranslationUnit, + TranslationUnitLoadError, + TypeKind, +) + +Cursor.__hash__ = lambda self: self.hash # so `Cursor`s can be dict keys + +# ---------------------------------------------------------------------------- # +# Usage + + +def parse_args() -> Namespace: + + available_checks = "\n".join(f" {name}" for (name, _) in CHECKS) + + parser = ArgumentParser( + formatter_class=RawDescriptionHelpFormatter, + epilog=f""" +available checks: +{available_checks} + +exit codes: + 0 No problems found. + 1 Analyzer failure. + 2 Bad usage. + 3 Problems found in a translation unit. +""", + ) + + parser.add_argument("build_dir", type=Path) + + parser.add_argument( + "translation_units", + type=Path, + nargs="*", + help=( + "Analyze only translation units whose root source file matches or" + " is under one of the given paths." + ), + ) + + parser.add_argument( + "-c", + "--check", + metavar="CHECK", + dest="check_names", + choices=[name for (name, _) in CHECKS], + action="append", + help=( + "Enable the given check. Can be given multiple times. If not given," + " all checks are enabled." + ), + ) + + parser.add_argument( + "-j", + "--jobs", + dest="threads", + type=int, + help=( + "Number of threads to employ. Defaults to the number of logical" + " processors." + ), + ) + + parser.add_argument( + "--profile", + action="store_true", + help="Profile execution. Forces single-threaded execution.", + ) + + return parser.parse_args() + + +# ---------------------------------------------------------------------------- # +# Main + + +def main() -> NoReturn: + + args = parse_args() + + compile_commands = load_compilation_database(args) + contexts = get_translation_unit_contexts(args, compile_commands) + + analyze_translation_units(args, contexts) + + +def load_compilation_database(args: Namespace) -> Sequence[Mapping[str, str]]: + + # clang.cindex.CompilationDatabase.getCompileCommands() apparently produces + # entries for files not listed in compile_commands.json in a best-effort + # manner, which we don't want, so we parse the JSON ourselves instead. + + path = args.build_dir / "compile_commands.json" + + try: + with path.open("r") as f: + return json.load(f) + except FileNotFoundError: + fatal(f"{path} does not exist") + + +def get_translation_unit_contexts( + args: Namespace, compile_commands: Iterable[Mapping[str, str]] +) -> Sequence[TranslationUnitContext]: + + system_include_paths = get_clang_system_include_paths() + check_names = args.check_names or [name for (name, _) in CHECKS] + + contexts = ( + TranslationUnitContext( + absolute_path=str(Path(cmd["directory"], cmd["file"]).resolve()), + compilation_working_dir=cmd["directory"], + compilation_command=cmd["command"], + system_include_paths=system_include_paths, + check_names=check_names, + ) + for cmd in compile_commands + ) + + if args.translation_units: + + allowed_prefixes = [ + # ensure path exists and is slash-terminated (even if it is a file) + os.path.join(path.resolve(strict=True), "") + for path in args.translation_units + ] + + contexts = ( + ctx + for ctx in contexts + if any( + (ctx.absolute_path + "/").startswith(prefix) + for prefix in allowed_prefixes + ) + ) + + context_list = list(contexts) + + if not context_list: + fatal("No translation units to analyze") + + return context_list + + +def get_clang_system_include_paths() -> Sequence[str]: + + # libclang does not automatically include clang's standard system include + # paths, so we ask clang what they are and include them ourselves. + + # TODO: Is there a less hacky way to do this? + + result = subprocess.run( + ["clang", "-E", "-", "-v"], + stdin=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + stderr=subprocess.PIPE, + universal_newlines=True, # decode stdout/stderr using default encoding + check=True, + ) + + # Module `re` does not support repeated group captures. + pattern = ( + r"#include <...> search starts here:\n" + r"((?: \S*\n)+)" + r"End of search list." + ) + + match = re.search(pattern, result.stderr, re.MULTILINE) + assert match is not None + + return [line[1:] for line in match.group(1).splitlines()] + + +def fatal(message: str) -> NoReturn: + print(f"\033[0;31mERROR: {message}\033[0m") + sys.exit(1) + + +# ---------------------------------------------------------------------------- # +# Analysis + + +@dataclass +class TranslationUnitContext: + absolute_path: str + compilation_working_dir: str + compilation_command: str + system_include_paths: Sequence[str] + check_names: Sequence[str] + + +def analyze_translation_units( + args: Namespace, contexts: Sequence[TranslationUnitContext] +) -> NoReturn: + + results: List[bool] + + if not args.profile: + + with Pool(processes=args.threads) as pool: + results = pool.map(analyze_translation_unit, contexts) + + else: + + import cProfile + import pstats + + profile = cProfile.Profile() + + try: + results = profile.runcall( + lambda: list(map(analyze_translation_unit, contexts)) + ) + finally: + stats = pstats.Stats(profile, stream=sys.stderr) + stats.strip_dirs() + stats.sort_stats("tottime") + stats.print_stats() + + print( + f"\033[0;34mAnalyzed {len(contexts)}" + f" translation unit{'' if len(contexts) == 1 else 's'}.\033[0m" + ) + + sys.exit(0 if all(results) else 3) + + +def analyze_translation_unit(context: TranslationUnitContext) -> bool: + + # relative to script's original working directory + relative_path = os.path.relpath(context.absolute_path) + + # load translation unit + + command = context.compilation_command.split() + + adjusted_command = [ + # keep the original compilation command name + command[0], + # ignore unknown GCC warning options + "-Wno-unknown-warning-option", + # add clang system include paths + *( + arg + for path in context.system_include_paths + for arg in ("-isystem", path) + ), + # keep all other arguments but the last, which is the file name + *command[1:-1], + # replace relative path to get absolute location information + context.absolute_path, + ] + + original_cwd = os.getcwd() + os.chdir(context.compilation_working_dir) # for options like -I to work + + try: + tu = TranslationUnit.from_source(filename=None, args=adjusted_command) + except TranslationUnitLoadError as e: + raise RuntimeError(f"Failed to load {relative_path}") from e + + os.chdir(original_cwd) # to have proper relative paths in messages + + # check for fatal diagnostics + + found_problems = False + + for diag in tu.diagnostics: + # consider only Fatal diagnostics, like missing includes + if diag.severity >= Diagnostic.Fatal: + found_problems = True + location = format_location(diag, default=relative_path) + print( + f"\033[0;33m{location}: {diag.spelling}; this may lead to false" + f" positives and negatives\033[0m" + ) + + # analyze translation unit + + def log(node: Cursor, message: str) -> None: + nonlocal found_problems + found_problems = True + print(f"{format_location(node)}: {message}") + + try: + for (name, checker) in CHECKS: + if name in context.check_names: + checker(tu, context.absolute_path, log) + except Exception as e: + raise RuntimeError(f"Error analyzing {relative_path}") from e + + return not found_problems + + +# obj must have a location field/property that is a `SourceLocation`. +def format_location(obj: Any, *, default: str = "(none)") -> str: + + location = obj.location + + if location.file is None: + return default + else: + abs_path = Path(location.file.name).resolve() + rel_path = os.path.relpath(abs_path) + return f"{rel_path}:{location.line}:{location.column}" + + +# ---------------------------------------------------------------------------- # +# Checks + +Checker = Callable[[TranslationUnit, str, Callable[[Cursor, str], None]], None] + +CHECKS: List[Tuple[str, Checker]] = [] + + +def check(name: str) -> Callable[[Checker], Checker]: + def decorator(checker: Checker) -> Checker: + CHECKS.append((name, checker)) + return checker + + return decorator + + +@check("return-value-never-used") +def check_return_value_never_used( + translation_unit: TranslationUnit, + translation_unit_path: str, + log: Callable[[Cursor, str], None], +) -> None: + """ + Report static functions with a non-void return value that no caller ever + uses. + + This check is best effort, but should never report false positives (positive + being error). + """ + + def function_occurrence_might_use_return_value( + ancestors: Sequence[Cursor], node: Cursor + ) -> bool: + + if ancestors[-1].kind.is_statement(): + + return False + + elif ( + ancestors[-1].kind == CursorKind.CALL_EXPR + and ancestors[-1].referenced == node.referenced + ): + + if not ancestors[-2].kind.is_statement(): + return True + + if ancestors[-2].kind in [ + CursorKind.IF_STMT, + CursorKind.SWITCH_STMT, + CursorKind.WHILE_STMT, + CursorKind.DO_STMT, + CursorKind.RETURN_STMT, + ]: + return True + + if ancestors[-2].kind == CursorKind.FOR_STMT: + [_init, cond, _adv] = ancestors[-2].get_children() + if ancestors[-1] == cond: + return True + + return False + + else: + + # might be doing something with a pointer to the function + return True + + # Maps canonical function `Cursor`s to whether we found a place that maybe + # uses their return value. Only includes static functions that don't return + # void and belong to the translation unit's root file (i.e, were not brought + # in by an #include). + funcs: Dict[Cursor, bool] = {} + + for [*ancestors, node] in all_paths(translation_unit.cursor): + + if ( + node.kind == CursorKind.FUNCTION_DECL + and node.storage_class == StorageClass.STATIC + and node.location.file.name == translation_unit_path + and node.type.get_result().get_canonical().kind != TypeKind.VOID + ): + funcs.setdefault(node.canonical, False) + + if ( + node.kind == CursorKind.DECL_REF_EXPR + and node.referenced.kind == CursorKind.FUNCTION_DECL + and node.referenced.canonical in funcs + and function_occurrence_might_use_return_value(ancestors, node) + ): + funcs[node.referenced.canonical] = True + + # --- + + for (cursor, return_value_maybe_used) in funcs.items(): + if not return_value_maybe_used: + log(cursor, f"{cursor.spelling}() return value is never used") + + +# ---------------------------------------------------------------------------- # +# Traversal + +# Hides nodes of kind UNEXPOSED_EXPR. +def all_paths(root: Cursor) -> Iterable[Sequence[Cursor]]: + + path = [] + + def aux(node: Cursor) -> Iterable[Sequence[Cursor]]: + nonlocal path + + if node.kind != CursorKind.UNEXPOSED_EXPR: + path.append(node) + yield path + + for child in node.get_children(): + yield from aux(child) + + if node.kind != CursorKind.UNEXPOSED_EXPR: + path.pop() + + return aux(root) + + +# ---------------------------------------------------------------------------- # +# Utilities handy for development + + +def print_node(node: Cursor) -> None: + + print(f"{format_location(node)}: kind = {node.kind.name}", end="") + + if node.spelling: + print(f", name = {node.spelling}", end="") + + if node.type is not None: + print(f", type = {node.type.get_canonical().spelling}", end="") + + if node.referenced is not None: + print(f", referenced = {node.referenced.spelling}", end="") + + print() + + +def print_tree( + node: Cursor, *, max_depth: Optional[int] = None, indentation_level: int = 0 +) -> None: + + if max_depth is None or max_depth >= 0: + + print(" " * indentation_level, end="") + print_node(node) + + for child in node.get_children(): + print_tree( + child, + max_depth=None if max_depth is None else max_depth - 1, + indentation_level=indentation_level + 1, + ) + + +# ---------------------------------------------------------------------------- # + +if __name__ == "__main__": + main() + +# ---------------------------------------------------------------------------- # From patchwork Sat Jul 2 11:33:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alberto Faria X-Patchwork-Id: 1651463 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Z2NZel2K; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LZqlK50Vyz9s07 for ; Sat, 2 Jul 2022 21:36:13 +1000 (AEST) Received: from localhost ([::1]:33438 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1o7bQ3-0004up-H1 for incoming@patchwork.ozlabs.org; Sat, 02 Jul 2022 07:36:11 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51862) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1o7bNm-000338-Mf for qemu-devel@nongnu.org; Sat, 02 Jul 2022 07:33:50 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:36955) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1o7bNk-0007jR-Hu for qemu-devel@nongnu.org; Sat, 02 Jul 2022 07:33:50 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1656761627; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=BxfLSdJeaqScMeruvLuh/qoohWtLPXnBogvQe9zNGcM=; b=Z2NZel2KfcMlE5nBudPMToTU8tClVwmRNrjx+ymE7MAOrPG72i6rnn8AmaZeOtRPkWRHyU vnCGbWpBYnPohnXPrEKrqqXgtmMViOnymKJeCxZi0sD8Ob28fm1GxNZAOMKt6dz2nFxTOr 1Bz3pdKng2yfMpiHfZTDOSjFovBDaos= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-230-VilpdHhqNECdBKGEMPyw3Q-1; Sat, 02 Jul 2022 07:33:44 -0400 X-MC-Unique: VilpdHhqNECdBKGEMPyw3Q-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 2B0ED1C068E2; Sat, 2 Jul 2022 11:33:44 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.39.194.114]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0C2D9492C3B; Sat, 2 Jul 2022 11:33:40 +0000 (UTC) From: Alberto Faria To: qemu-devel@nongnu.org Cc: Paolo Bonzini , qemu-block@nongnu.org, "Denis V. Lunev" , Emanuele Giuseppe Esposito , Stefan Hajnoczi , Ronnie Sahlberg , Hanna Reitz , Stefano Garzarella , Kevin Wolf , Peter Xu , Alberto Garcia , John Snow , Eric Blake , Fam Zheng , Markus Armbruster , Vladimir Sementsov-Ogievskiy , Peter Lieven , Alberto Faria Subject: [RFC 2/8] Drop some unused static function return values Date: Sat, 2 Jul 2022 12:33:25 +0100 Message-Id: <20220702113331.2003820-3-afaria@redhat.com> In-Reply-To: <20220702113331.2003820-1-afaria@redhat.com> References: <20220702113331.2003820-1-afaria@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Received-SPF: pass client-ip=170.10.133.124; envelope-from=afaria@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -21 X-Spam_score: -2.2 X-Spam_bar: -- X-Spam_report: (-2.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.082, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Make some non-void static functions whose return values are ignored by all callers return void instead. These functions were found by the shiny new static-analyzer.py. Only a few of the reported cases were fixed. Signed-off-by: Alberto Faria --- block/file-posix.c | 6 +----- block/io.c | 24 +++++++++++------------- block/qcow2-bitmap.c | 6 ++---- block/quorum.c | 5 +---- block/vpc.c | 9 +++------ block/vvfat.c | 11 +++++------ 6 files changed, 23 insertions(+), 38 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index 48cd096624..a4641da7f9 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1895,7 +1895,7 @@ static int handle_aiocb_discard(void *opaque) * Returns: 0 on success, -errno on failure. Since this is an optimization, * caller may ignore failures. */ -static int allocate_first_block(int fd, size_t max_size) +static void allocate_first_block(int fd, size_t max_size) { size_t write_size = (max_size < MAX_BLOCKSIZE) ? BDRV_SECTOR_SIZE @@ -1903,7 +1903,6 @@ static int allocate_first_block(int fd, size_t max_size) size_t max_align = MAX(MAX_BLOCKSIZE, qemu_real_host_page_size()); void *buf; ssize_t n; - int ret; buf = qemu_memalign(max_align, write_size); memset(buf, 0, write_size); @@ -1912,10 +1911,7 @@ static int allocate_first_block(int fd, size_t max_size) n = pwrite(fd, buf, write_size, 0); } while (n == -1 && errno == EINTR); - ret = (n == -1) ? -errno : 0; - qemu_vfree(buf); - return ret; } static int handle_aiocb_truncate(void *opaque) diff --git a/block/io.c b/block/io.c index 1e9bf09a49..bbfe94503b 100644 --- a/block/io.c +++ b/block/io.c @@ -934,20 +934,18 @@ void bdrv_dec_in_flight(BlockDriverState *bs) bdrv_wakeup(bs); } -static bool coroutine_fn bdrv_wait_serialising_requests(BdrvTrackedRequest *self) +static void coroutine_fn +bdrv_wait_serialising_requests(BdrvTrackedRequest *self) { BlockDriverState *bs = self->bs; - bool waited = false; if (!qatomic_read(&bs->serialising_in_flight)) { - return false; + return; } qemu_co_mutex_lock(&bs->reqs_lock); - waited = bdrv_wait_serialising_requests_locked(self); + bdrv_wait_serialising_requests_locked(self); qemu_co_mutex_unlock(&bs->reqs_lock); - - return waited; } bool coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req, @@ -1689,10 +1687,10 @@ static bool bdrv_init_padding(BlockDriverState *bs, return true; } -static int bdrv_padding_rmw_read(BdrvChild *child, - BdrvTrackedRequest *req, - BdrvRequestPadding *pad, - bool zero_middle) +static void bdrv_padding_rmw_read(BdrvChild *child, + BdrvTrackedRequest *req, + BdrvRequestPadding *pad, + bool zero_middle) { QEMUIOVector local_qiov; BlockDriverState *bs = child->bs; @@ -1715,7 +1713,7 @@ static int bdrv_padding_rmw_read(BdrvChild *child, ret = bdrv_aligned_preadv(child, req, req->overlap_offset, bytes, align, &local_qiov, 0, 0); if (ret < 0) { - return ret; + return; } if (pad->head) { bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD); @@ -1738,7 +1736,7 @@ static int bdrv_padding_rmw_read(BdrvChild *child, req->overlap_offset + req->overlap_bytes - align, align, align, &local_qiov, 0, 0); if (ret < 0) { - return ret; + return; } bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL); } @@ -1748,7 +1746,7 @@ zero_mem: memset(pad->buf + pad->head, 0, pad->buf_len - pad->head - pad->tail); } - return 0; + return; } static void bdrv_padding_destroy(BdrvRequestPadding *pad) diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 8fb4731551..a4e9fe73d4 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -257,14 +257,14 @@ fail: return ret; } -static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb) +static void free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb) { int ret; uint64_t *bitmap_table; ret = bitmap_table_load(bs, tb, &bitmap_table); if (ret < 0) { - return ret; + return; } clear_bitmap_table(bs, bitmap_table, tb->size); @@ -274,8 +274,6 @@ static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb) tb->offset = 0; tb->size = 0; - - return 0; } /* load_bitmap_data diff --git a/block/quorum.c b/block/quorum.c index f33f30d36b..9c0fbd79be 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -293,7 +293,7 @@ static void quorum_rewrite_entry(void *opaque) } } -static bool quorum_rewrite_bad_versions(QuorumAIOCB *acb, +static void quorum_rewrite_bad_versions(QuorumAIOCB *acb, QuorumVoteValue *value) { QuorumVoteVersion *version; @@ -331,9 +331,6 @@ static bool quorum_rewrite_bad_versions(QuorumAIOCB *acb, qemu_coroutine_enter(co); } } - - /* return true if any rewrite is done else false */ - return count; } static void quorum_count_vote(QuorumVotes *votes, diff --git a/block/vpc.c b/block/vpc.c index 4d8f16e199..bd705cffb0 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -777,11 +777,10 @@ static int coroutine_fn vpc_co_block_status(BlockDriverState *bs, * Note that the geometry doesn't always exactly match total_sectors but * may round it down. * - * Returns 0 on success, -EFBIG if the size is larger than 2040 GiB. Override - * the hardware EIDE and ATA-2 limit of 16 heads (max disk size of 127 GB) - * and instead allow up to 255 heads. + * Override the hardware EIDE and ATA-2 limit of 16 heads (max disk size of 127 + * GB) and instead allow up to 255 heads. */ -static int calculate_geometry(int64_t total_sectors, uint16_t *cyls, +static void calculate_geometry(int64_t total_sectors, uint16_t *cyls, uint8_t *heads, uint8_t *secs_per_cyl) { uint32_t cyls_times_heads; @@ -815,8 +814,6 @@ static int calculate_geometry(int64_t total_sectors, uint16_t *cyls, } *cyls = cyls_times_heads / *heads; - - return 0; } static int create_dynamic_disk(BlockBackend *blk, VHDFooter *footer, diff --git a/block/vvfat.c b/block/vvfat.c index b2b58d93b8..fba7581427 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -154,9 +154,9 @@ static inline int array_remove_slice(array_t* array,int index, int count) return 0; } -static int array_remove(array_t* array,int index) +static void array_remove(array_t* array,int index) { - return array_remove_slice(array, index, 1); + array_remove_slice(array, index, 1); } /* return the index for a given member */ @@ -2967,13 +2967,12 @@ DLOG(checkpoint()); return 0; } -static int try_commit(BDRVVVFATState* s) +static void try_commit(BDRVVVFATState* s) { vvfat_close_current_file(s); DLOG(checkpoint()); - if(!is_consistent(s)) - return -1; - return do_commit(s); + if (is_consistent(s)) + do_commit(s); } static int vvfat_write(BlockDriverState *bs, int64_t sector_num, From patchwork Sat Jul 2 11:33:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alberto Faria X-Patchwork-Id: 1651466 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=TdN4w6bm; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LZqsW2dnGz9s07 for ; Sat, 2 Jul 2022 21:41:35 +1000 (AEST) Received: from localhost ([::1]:42038 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1o7bVF-0002WI-6o for incoming@patchwork.ozlabs.org; Sat, 02 Jul 2022 07:41:33 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51902) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1o7bNp-0003BG-UE for qemu-devel@nongnu.org; Sat, 02 Jul 2022 07:33:54 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]:44299) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1o7bNn-0007wo-Ut for qemu-devel@nongnu.org; Sat, 02 Jul 2022 07:33:53 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1656761631; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=4RJMvRmvaUErr26isQn4HMpApGBcAGf31Hfvrw0Nv1E=; b=TdN4w6bmtjOVbG2hFhzcd2Js0+9E4NHw9sX8pIBs3wQmm/NPWmlt5TDYZ6LdN89SWN+Aim zwBGd8kLuRSMDsfQzsJW9OTHR0WvvoIfHx/6WulEpsu5tsw3AdWXrOqHO0fVWszifOdHzL qtV1dYT9EKtPndn6OcNVrlxIvLVmkkU= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-97-Irk5VbeEMAeXnJXriob9vg-1; Sat, 02 Jul 2022 07:33:48 -0400 X-MC-Unique: Irk5VbeEMAeXnJXriob9vg-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id A4797380407C; Sat, 2 Jul 2022 11:33:47 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.39.194.114]) by smtp.corp.redhat.com (Postfix) with ESMTP id 84583492C3B; Sat, 2 Jul 2022 11:33:44 +0000 (UTC) From: Alberto Faria To: qemu-devel@nongnu.org Cc: Paolo Bonzini , qemu-block@nongnu.org, "Denis V. Lunev" , Emanuele Giuseppe Esposito , Stefan Hajnoczi , Ronnie Sahlberg , Hanna Reitz , Stefano Garzarella , Kevin Wolf , Peter Xu , Alberto Garcia , John Snow , Eric Blake , Fam Zheng , Markus Armbruster , Vladimir Sementsov-Ogievskiy , Peter Lieven , Alberto Faria Subject: [RFC 3/8] static-analyzer: Enforce coroutine_fn restrictions for direct calls Date: Sat, 2 Jul 2022 12:33:26 +0100 Message-Id: <20220702113331.2003820-4-afaria@redhat.com> In-Reply-To: <20220702113331.2003820-1-afaria@redhat.com> References: <20220702113331.2003820-1-afaria@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Received-SPF: pass client-ip=170.10.129.124; envelope-from=afaria@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -28 X-Spam_score: -2.9 X-Spam_bar: -- X-Spam_report: (-2.9 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.082, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Add a static-analyzer.py check ensuring that non-coroutine_fn functions don't perform direct calls to coroutine_fn functions. For the few cases where this must happen, introduce an __allow_coroutine_fn_call() macro that wraps offending calls and overrides the static analyzer. Signed-off-by: Alberto Faria --- include/qemu/coroutine.h | 13 +++ static-analyzer.py | 207 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 220 insertions(+) diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index 08c5bb3c76..40a4037525 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -42,7 +42,20 @@ * .... * } */ +#ifdef __clang__ +#define coroutine_fn __attribute__((__annotate__("coroutine_fn"))) +#else #define coroutine_fn +#endif + +/** + * This can wrap a call to a coroutine_fn from a non-coroutine_fn function and + * suppress the static analyzer's complaints. + * + * You don't want to use this. + */ +#define __allow_coroutine_fn_call(call) \ + ((void)"__allow_coroutine_fn_call", call) typedef struct Coroutine Coroutine; diff --git a/static-analyzer.py b/static-analyzer.py index 010cc92212..8abc552b82 100755 --- a/static-analyzer.py +++ b/static-analyzer.py @@ -440,6 +440,81 @@ def function_occurrence_might_use_return_value( log(cursor, f"{cursor.spelling}() return value is never used") +@check("coroutine-annotation-validity") +def check_coroutine_annotation_validity( + translation_unit: TranslationUnit, + translation_unit_path: str, + log: Callable[[Cursor, str], None], +) -> None: + + for [*ancestors, node] in all_paths(translation_unit.cursor): + + # validate annotation usage + + if is_annotation(node, "coroutine_fn") and ( + ancestors[-1] is None + or not is_valid_coroutine_fn_usage(ancestors[-1]) + ): + log(node, "invalid coroutine_fn usage") + + if is_comma_wrapper( + node, "__allow_coroutine_fn_call" + ) and not is_valid_allow_coroutine_fn_call_usage(node): + log(node, "invalid __allow_coroutine_fn_call usage") + + # reject re-declarations with inconsistent annotations + + if node.kind == CursorKind.FUNCTION_DECL: + + def log_annotation_disagreement(annotation: str) -> None: + log( + node, + f"{annotation} annotation disagreement with" + f" {format_location(node.canonical)}", + ) + + if is_coroutine_fn(node) != is_coroutine_fn(node.canonical): + log_annotation_disagreement("coroutine_fn") + + +@check("coroutine-calls") +def check_coroutine_calls( + translation_unit: TranslationUnit, + translation_unit_path: str, + log: Callable[[Cursor, str], None], +) -> None: + + for caller in subtrees_matching( + translation_unit.cursor, + lambda n: n.kind == CursorKind.FUNCTION_DECL and n.is_definition(), + ): + + caller_is_coroutine = is_coroutine_fn(caller) + + for [*_, call_parent, call] in filter( + lambda path: path[-1].kind == CursorKind.CALL_EXPR, + all_paths(caller), + ): + + # We can get some "calls" that are actually things like top-level + # macro invocations. + if call.referenced is None: + continue + + callee = call.referenced.canonical + + # reject calls from non-coroutine_fn to coroutine_fn + + if ( + not caller_is_coroutine + and is_coroutine_fn(callee) + and not is_comma_wrapper( + call_parent, "__allow_coroutine_fn_call" + ) + ): + log(call, "non-coroutine_fn function calls coroutine_fn") + + # ---------------------------------------------------------------------------- # # Traversal @@ -464,6 +539,138 @@ def aux(node: Cursor) -> Iterable[Sequence[Cursor]]: return aux(root) +# Doesn't traverse yielded subtrees. +def subtrees_matching( + root: Cursor, predicate: Callable[[Cursor], bool] +) -> Iterable[Cursor]: + + if predicate(root): + yield root + else: + for child in root.get_children(): + yield from subtrees_matching(child, predicate) + + +# ---------------------------------------------------------------------------- # +# Node predicates + + +def is_valid_coroutine_fn_usage(parent: Cursor) -> bool: + """ + Check if an occurrence of `coroutine_fn` represented by a node with parent + `parent` appears at a valid point in the AST. This is the case if `parent` + is: + + - A function declaration/definition, OR + - A field/variable/parameter declaration with a function pointer type, OR + - A typedef of a function type or function pointer type. + """ + + if parent.kind == CursorKind.FUNCTION_DECL: + return True + + canonical_type = parent.type.get_canonical() + + def parent_type_is_function() -> bool: + return canonical_type.kind == TypeKind.FUNCTIONPROTO + + def parent_type_is_function_pointer() -> bool: + return ( + canonical_type.kind == TypeKind.POINTER + and canonical_type.get_pointee().kind == TypeKind.FUNCTIONPROTO + ) + + if parent.kind in [ + CursorKind.FIELD_DECL, + CursorKind.VAR_DECL, + CursorKind.PARM_DECL, + ]: + return parent_type_is_function_pointer() + + if parent.kind == CursorKind.TYPEDEF_DECL: + return parent_type_is_function() or parent_type_is_function_pointer() + + return False + + +def is_valid_allow_coroutine_fn_call_usage(node: Cursor) -> bool: + """ + Check if an occurrence of `__allow_coroutine_fn_call()` represented by node + `node` appears at a valid point in the AST. This is the case if its right + operand is a call to: + + - A function declared with the `coroutine_fn` annotation. + + TODO: Ensure that `__allow_coroutine_fn_call()` is in the body of a + non-`coroutine_fn` function. + """ + + [_, call] = node.get_children() + + if call.kind != CursorKind.CALL_EXPR: + return False + + return is_coroutine_fn(call.referenced) + + +def is_coroutine_fn(node: Cursor) -> bool: + """ + Check whether the given `node` should be considered to be `coroutine_fn`. + + This assumes valid usage of `coroutine_fn`. + """ + + while node.kind in [CursorKind.PAREN_EXPR, CursorKind.UNEXPOSED_EXPR]: + children = list(node.get_children()) + if len(children) == 1: + node = children[0] + else: + break + + return node.kind == CursorKind.FUNCTION_DECL and is_annotated_with( + node, "coroutine_fn" + ) + + +def is_annotated_with(node: Cursor, annotation: str) -> bool: + return any(is_annotation(c, annotation) for c in node.get_children()) + + +def is_annotation(node: Cursor, annotation: str) -> bool: + return node.kind == CursorKind.ANNOTATE_ATTR and node.spelling == annotation + + +# A "comma wrapper" is the pattern `((void)string_literal, expr)`. The `expr` is +# said to be "comma wrapped". +def is_comma_wrapper(node: Cursor, literal: str) -> bool: + + # TODO: Do we need to check that the operator is `,`? Is there another + # operator that can combine void and an expr? + + if node.kind != CursorKind.BINARY_OPERATOR: + return False + + [left, _right] = node.get_children() + + if ( + left.kind != CursorKind.CSTYLE_CAST_EXPR + or left.type.kind != TypeKind.VOID + ): + return False + + [unexposed_expr] = left.get_children() + + if unexposed_expr.kind != CursorKind.UNEXPOSED_EXPR: + return False + + [string_literal] = unexposed_expr.get_children() + + return ( + string_literal.kind == CursorKind.STRING_LITERAL + and string_literal.spelling == f'"{literal}"' + ) + + # ---------------------------------------------------------------------------- # # Utilities handy for development From patchwork Sat Jul 2 11:33:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alberto Faria X-Patchwork-Id: 1651462 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=fseTmnBd; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LZqjm51JHz9s07 for ; Sat, 2 Jul 2022 21:34:52 +1000 (AEST) Received: from localhost ([::1]:59394 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1o7bOk-0003NB-G0 for incoming@patchwork.ozlabs.org; Sat, 02 Jul 2022 07:34:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51934) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1o7bNu-0003K3-9I for qemu-devel@nongnu.org; Sat, 02 Jul 2022 07:33:58 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]:54155) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1o7bNr-0007yT-HG for qemu-devel@nongnu.org; Sat, 02 Jul 2022 07:33:56 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1656761635; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=U019ymYOutfn4cZj9FQwzQdfQ9NuRH86JCzWCeQt3Cs=; b=fseTmnBdb7DJj8kU/4kWQjxoRTxHv+GqJbO0938H4YzCorPhFnuj4F8ZHdHyGlYeQ+eOlK YaPtwjAQ/yrYLf8LsEP3PqBlz+FTANUJ7K/N0ylHiiPKUg2dxJSkmtnOOH6mj6SsVqvcWa um6RJEjVaQN8HJHx/QV76fa0xQlOItw= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-259-aSky6CNZOwKvdcOooigZ7Q-1; Sat, 02 Jul 2022 07:33:51 -0400 X-MC-Unique: aSky6CNZOwKvdcOooigZ7Q-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 3432383395C; Sat, 2 Jul 2022 11:33:51 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.39.194.114]) by smtp.corp.redhat.com (Postfix) with ESMTP id 15C7D492C3B; Sat, 2 Jul 2022 11:33:47 +0000 (UTC) From: Alberto Faria To: qemu-devel@nongnu.org Cc: Paolo Bonzini , qemu-block@nongnu.org, "Denis V. Lunev" , Emanuele Giuseppe Esposito , Stefan Hajnoczi , Ronnie Sahlberg , Hanna Reitz , Stefano Garzarella , Kevin Wolf , Peter Xu , Alberto Garcia , John Snow , Eric Blake , Fam Zheng , Markus Armbruster , Vladimir Sementsov-Ogievskiy , Peter Lieven , Alberto Faria Subject: [RFC 4/8] Fix some direct calls from non-coroutine_fn to coroutine_fn Date: Sat, 2 Jul 2022 12:33:27 +0100 Message-Id: <20220702113331.2003820-5-afaria@redhat.com> In-Reply-To: <20220702113331.2003820-1-afaria@redhat.com> References: <20220702113331.2003820-1-afaria@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Received-SPF: pass client-ip=170.10.129.124; envelope-from=afaria@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -28 X-Spam_score: -2.9 X-Spam_bar: -- X-Spam_report: (-2.9 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.082, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" These problems were found by static-analyzer.py. Only a few of the reported cases were fixed. Signed-off-by: Alberto Faria --- block/block-backend.c | 13 ++++++++----- block/copy-before-write.c | 3 ++- block/dirty-bitmap.c | 6 ++++-- block/iscsi.c | 3 ++- block/qcow2.h | 14 +++++++------- block/qed.c | 6 +++--- include/block/block-io.h | 7 ++++--- 7 files changed, 30 insertions(+), 22 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c index f425b00793..5f2a912a59 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1537,8 +1537,9 @@ static void blk_aio_read_entry(void *opaque) QEMUIOVector *qiov = rwco->iobuf; assert(qiov->size == acb->bytes); - rwco->ret = blk_co_do_preadv(rwco->blk, rwco->offset, acb->bytes, - qiov, rwco->flags); + rwco->ret = __allow_coroutine_fn_call( + blk_co_do_preadv(rwco->blk, rwco->offset, acb->bytes, qiov, + rwco->flags)); blk_aio_complete(acb); } @@ -1682,7 +1683,8 @@ static void blk_aio_ioctl_entry(void *opaque) BlkAioEmAIOCB *acb = opaque; BlkRwCo *rwco = &acb->rwco; - rwco->ret = blk_co_do_ioctl(rwco->blk, rwco->offset, rwco->iobuf); + rwco->ret = __allow_coroutine_fn_call( + blk_co_do_ioctl(rwco->blk, rwco->offset, rwco->iobuf)); blk_aio_complete(acb); } @@ -1716,7 +1718,8 @@ static void blk_aio_pdiscard_entry(void *opaque) BlkAioEmAIOCB *acb = opaque; BlkRwCo *rwco = &acb->rwco; - rwco->ret = blk_co_do_pdiscard(rwco->blk, rwco->offset, acb->bytes); + rwco->ret = __allow_coroutine_fn_call( + blk_co_do_pdiscard(rwco->blk, rwco->offset, acb->bytes)); blk_aio_complete(acb); } @@ -1772,7 +1775,7 @@ static void blk_aio_flush_entry(void *opaque) BlkAioEmAIOCB *acb = opaque; BlkRwCo *rwco = &acb->rwco; - rwco->ret = blk_co_do_flush(rwco->blk); + rwco->ret = __allow_coroutine_fn_call(blk_co_do_flush(rwco->blk)); blk_aio_complete(acb); } diff --git a/block/copy-before-write.c b/block/copy-before-write.c index c24b8dd117..5096abbc08 100644 --- a/block/copy-before-write.c +++ b/block/copy-before-write.c @@ -240,7 +240,8 @@ static BlockReq *cbw_snapshot_read_lock(BlockDriverState *bs, return req; } -static void cbw_snapshot_read_unlock(BlockDriverState *bs, BlockReq *req) +static coroutine_fn void +cbw_snapshot_read_unlock(BlockDriverState *bs, BlockReq *req) { BDRVCopyBeforeWriteState *s = bs->opaque; diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c index bf3dc0512a..ccf46c0b1f 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -419,7 +419,8 @@ int bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name, Error **errp) { if (qemu_in_coroutine()) { - return bdrv_co_remove_persistent_dirty_bitmap(bs, name, errp); + return __allow_coroutine_fn_call( + bdrv_co_remove_persistent_dirty_bitmap(bs, name, errp)); } else { Coroutine *co; BdrvRemovePersistentDirtyBitmapCo s = { @@ -495,7 +496,8 @@ bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, { IO_CODE(); if (qemu_in_coroutine()) { - return bdrv_co_can_store_new_dirty_bitmap(bs, name, granularity, errp); + return __allow_coroutine_fn_call( + bdrv_co_can_store_new_dirty_bitmap(bs, name, granularity, errp)); } else { Coroutine *co; BdrvCanStoreNewDirtyBitmapCo s = { diff --git a/block/iscsi.c b/block/iscsi.c index d707d0b354..967438b4bd 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -290,7 +290,8 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status, } } -static void iscsi_co_init_iscsitask(IscsiLun *iscsilun, struct IscsiTask *iTask) +static void coroutine_fn +iscsi_co_init_iscsitask(IscsiLun *iscsilun, struct IscsiTask *iTask) { *iTask = (struct IscsiTask) { .co = qemu_coroutine_self(), diff --git a/block/qcow2.h b/block/qcow2.h index ba436a8d0d..e68d127d8e 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -990,13 +990,13 @@ int qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp); bool qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, bool release_stored, Error **errp); int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp); -bool qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs, - const char *name, - uint32_t granularity, - Error **errp); -int qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, - const char *name, - Error **errp); +bool coroutine_fn qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs, + const char *name, + uint32_t granularity, + Error **errp); +int coroutine_fn qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, + const char *name, + Error **errp); bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs); uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *bs, uint32_t cluster_size); diff --git a/block/qed.c b/block/qed.c index f34d9a3ac1..96f4cda83f 100644 --- a/block/qed.c +++ b/block/qed.c @@ -259,7 +259,7 @@ static CachedL2Table *qed_new_l2_table(BDRVQEDState *s) return l2_table; } -static bool qed_plug_allocating_write_reqs(BDRVQEDState *s) +static bool coroutine_fn qed_plug_allocating_write_reqs(BDRVQEDState *s) { qemu_co_mutex_lock(&s->table_lock); @@ -278,7 +278,7 @@ static bool qed_plug_allocating_write_reqs(BDRVQEDState *s) return true; } -static void qed_unplug_allocating_write_reqs(BDRVQEDState *s) +static void coroutine_fn qed_unplug_allocating_write_reqs(BDRVQEDState *s) { qemu_co_mutex_lock(&s->table_lock); assert(s->allocating_write_reqs_plugged); @@ -568,7 +568,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, bdrv_qed_init_state(bs); if (qemu_in_coroutine()) { - bdrv_qed_open_entry(&qoc); + __allow_coroutine_fn_call(bdrv_qed_open_entry(&qoc)); } else { assert(qemu_get_current_aio_context() == qemu_get_aio_context()); qemu_coroutine_enter(qemu_coroutine_create(bdrv_qed_open_entry, &qoc)); diff --git a/include/block/block-io.h b/include/block/block-io.h index 053a27141a..cefe3494fe 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -80,7 +80,8 @@ int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf); /* Ensure contents are flushed to disk. */ int coroutine_fn bdrv_co_flush(BlockDriverState *bs); -int bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes); +int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, + int64_t bytes); bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs); int bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, @@ -88,8 +89,8 @@ int bdrv_block_status(BlockDriverState *bs, int64_t offset, int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base, int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file); -int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes, - int64_t *pnum); +int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset, + int64_t bytes, int64_t *pnum); int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, bool include_base, int64_t offset, int64_t bytes, int64_t *pnum); From patchwork Sat Jul 2 11:33:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alberto Faria X-Patchwork-Id: 1651465 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=AbOaCMzo; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LZqrR4W2Wz9s07 for ; Sat, 2 Jul 2022 21:40:39 +1000 (AEST) Received: from localhost ([::1]:40218 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1o7bUK-0001AK-C6 for incoming@patchwork.ozlabs.org; Sat, 02 Jul 2022 07:40:36 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51988) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1o7bNz-0003MZ-45 for qemu-devel@nongnu.org; Sat, 02 Jul 2022 07:34:03 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:34262) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1o7bNs-0007yj-P3 for qemu-devel@nongnu.org; Sat, 02 Jul 2022 07:34:02 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1656761636; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=J20t4lF9lHmYknS0yWn5MoQszWEEaQKBQdjeVtzgefw=; b=AbOaCMzoPpOa7/8eFQ5nZxkN8jgvXCn2ws82Isa5xUskNVUVtoUSNiUbJgwHTZCHu8ZlJQ MQrmqpicsKdsMmMGWZ4DMJhc6zeZ+f3LjTqDpFi4NONubUPW8fiHiV43QmlRDeLfwzyJQc 7f7542+MGIay5UFtyxLunfKDZX9QaBI= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-364-7DuygAgEPyKkG5q3iRxabQ-1; Sat, 02 Jul 2022 07:33:55 -0400 X-MC-Unique: 7DuygAgEPyKkG5q3iRxabQ-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id AD0FB801231; Sat, 2 Jul 2022 11:33:54 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.39.194.114]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8AD82492C3B; Sat, 2 Jul 2022 11:33:51 +0000 (UTC) From: Alberto Faria To: qemu-devel@nongnu.org Cc: Paolo Bonzini , qemu-block@nongnu.org, "Denis V. Lunev" , Emanuele Giuseppe Esposito , Stefan Hajnoczi , Ronnie Sahlberg , Hanna Reitz , Stefano Garzarella , Kevin Wolf , Peter Xu , Alberto Garcia , John Snow , Eric Blake , Fam Zheng , Markus Armbruster , Vladimir Sementsov-Ogievskiy , Peter Lieven , Alberto Faria Subject: [RFC 5/8] static-analyzer: Enforce coroutine_fn restrictions on function pointers Date: Sat, 2 Jul 2022 12:33:28 +0100 Message-Id: <20220702113331.2003820-6-afaria@redhat.com> In-Reply-To: <20220702113331.2003820-1-afaria@redhat.com> References: <20220702113331.2003820-1-afaria@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Received-SPF: pass client-ip=170.10.133.124; envelope-from=afaria@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -21 X-Spam_score: -2.2 X-Spam_bar: -- X-Spam_report: (-2.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.082, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Extend static-analyzer.py to enforce coroutine_fn restrictions on function pointer operations. Invalid operations include assigning a coroutine_fn value to a non-coroutine_fn function pointer, and invoking a coroutine_fn function pointer from a non-coroutine_fn function. Signed-off-by: Alberto Faria --- static-analyzer.py | 147 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 143 insertions(+), 4 deletions(-) diff --git a/static-analyzer.py b/static-analyzer.py index 8abc552b82..485d054052 100755 --- a/static-analyzer.py +++ b/static-analyzer.py @@ -36,6 +36,8 @@ TranslationUnit, TranslationUnitLoadError, TypeKind, + SourceRange, + TokenGroup, ) Cursor.__hash__ = lambda self: self.hash # so `Cursor`s can be dict keys @@ -515,6 +517,90 @@ def check_coroutine_calls( log(call, "non-coroutine_fn function calls coroutine_fn") +@check("coroutine-pointers") +def check_coroutine_pointers( + translation_unit: TranslationUnit, + translation_unit_path: str, + log: Callable[[Cursor, str], None], +) -> None: + + # What we would really like is to associate annotation attributes with types + # directly, but that doesn't seem possible. Instead, we have to look at the + # relevant variable/field/parameter declarations, and follow typedefs. + + # This doesn't check all possible ways of assigning to a coroutine_fn + # field/variable/parameter. That would probably be too much work. + + # TODO: Check struct/union/array initialization. + # TODO: Check assignment to struct/union/array fields. + + for [*_, node] in all_paths(translation_unit.cursor): + + # check initialization of variables using coroutine_fn values + + if node.kind == CursorKind.VAR_DECL: + + children = [ + c + for c in node.get_children() + if c.kind + not in [ + CursorKind.ANNOTATE_ATTR, + CursorKind.INIT_LIST_EXPR, + CursorKind.TYPE_REF, + CursorKind.UNEXPOSED_ATTR, + ] + ] + + if ( + len(children) == 1 + and not is_coroutine_fn(node) + and is_coroutine_fn(children[0]) + ): + log(node, "assigning coroutine_fn to non-coroutine_fn") + + # check initialization of fields using coroutine_fn values + + # TODO: This only checks designator initializers. + + if node.kind == CursorKind.INIT_LIST_EXPR: + + for initializer in filter( + lambda n: n.kind == CursorKind.UNEXPOSED_EXPR, + node.get_children(), + ): + + children = list(initializer.get_children()) + + if ( + len(children) == 2 + and children[0].kind == CursorKind.MEMBER_REF + and not is_coroutine_fn(children[0].referenced) + and is_coroutine_fn(children[1]) + ): + log( + initializer, + "assigning coroutine_fn to non-coroutine_fn", + ) + + # check assignments of coroutine_fn values to variables or fields + + if is_binary_operator(node, "="): + + [left, right] = node.get_children() + + if ( + left.kind + in [ + CursorKind.DECL_REF_EXPR, + CursorKind.MEMBER_REF_EXPR, + ] + and not is_coroutine_fn(left.referenced) + and is_coroutine_fn(right) + ): + log(node, "assigning coroutine_fn to non-coroutine_fn") + + # ---------------------------------------------------------------------------- # # Traversal @@ -555,6 +641,31 @@ def subtrees_matching( # Node predicates +def is_binary_operator(node: Cursor, operator: str) -> bool: + return ( + node.kind == CursorKind.BINARY_OPERATOR + and get_binary_operator_spelling(node) == operator + ) + + +def get_binary_operator_spelling(node: Cursor) -> Optional[str]: + + assert node.kind == CursorKind.BINARY_OPERATOR + + [left, right] = node.get_children() + + op_range = SourceRange.from_locations(left.extent.end, right.extent.start) + + tokens = list(TokenGroup.get_tokens(node.translation_unit, op_range)) + if not tokens: + # Can occur when left and right children extents overlap due to + # misparsing. + return None + + [op_token, *_] = tokens + return op_token.spelling + + def is_valid_coroutine_fn_usage(parent: Cursor) -> bool: """ Check if an occurrence of `coroutine_fn` represented by a node with parent @@ -599,7 +710,13 @@ def is_valid_allow_coroutine_fn_call_usage(node: Cursor) -> bool: `node` appears at a valid point in the AST. This is the case if its right operand is a call to: - - A function declared with the `coroutine_fn` annotation. + - A function declared with the `coroutine_fn` annotation, OR + - A field/variable/parameter whose declaration has the `coroutine_fn` + annotation, and of function pointer type, OR + - [TODO] A field/variable/parameter of a typedef function pointer type, + and the typedef has the `coroutine_fn` annotation, OR + - [TODO] A field/variable/parameter of a pointer to typedef function type, + and the typedef has the `coroutine_fn` annotation. TODO: Ensure that `__allow_coroutine_fn_call()` is in the body of a non-`coroutine_fn` function. @@ -627,9 +744,31 @@ def is_coroutine_fn(node: Cursor) -> bool: else: break - return node.kind == CursorKind.FUNCTION_DECL and is_annotated_with( - node, "coroutine_fn" - ) + if node.kind in [CursorKind.DECL_REF_EXPR, CursorKind.MEMBER_REF_EXPR]: + node = node.referenced + + # --- + + if node.kind == CursorKind.FUNCTION_DECL: + return is_annotated_with(node, "coroutine_fn") + + if node.kind in [ + CursorKind.FIELD_DECL, + CursorKind.VAR_DECL, + CursorKind.PARM_DECL, + ]: + + if is_annotated_with(node, "coroutine_fn"): + return True + + # TODO: If type is typedef or pointer to typedef, follow typedef. + + return False + + if node.kind == CursorKind.TYPEDEF_DECL: + return is_annotated_with(node, "coroutine_fn") + + return False def is_annotated_with(node: Cursor, annotation: str) -> bool: From patchwork Sat Jul 2 11:33:29 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alberto Faria X-Patchwork-Id: 1651464 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=TOwUrw+a; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LZqqb2JbRz9s07 for ; Sat, 2 Jul 2022 21:39:53 +1000 (AEST) Received: from localhost ([::1]:39724 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1o7bTa-0000of-Hf for incoming@patchwork.ozlabs.org; Sat, 02 Jul 2022 07:39:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51968) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1o7bNx-0003ML-Oh for qemu-devel@nongnu.org; Sat, 02 Jul 2022 07:34:03 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:56487) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1o7bNw-0007z4-7g for qemu-devel@nongnu.org; Sat, 02 Jul 2022 07:34:01 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1656761639; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6dsFT66wWWePXhL01EUVk5ehyeBB76oxgUuM4U+Bn9I=; b=TOwUrw+asQs2csbDBriAjWcO77zntGeSVP0pWsc0iRhswne61Y/Vl6LgLg9OpQyMrfd/o9 r4xmdaerGv8iD1a0I5Opr+pCv5M8hhUmb3GpR2AUkKfKj7kCGZo7xgA9TzoFC4+9+BoFMZ DRLK4nFPwFSYwFq5T/e4XG+1EjEXJd0= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-482-lxLR4XDgPc2hJy4jSRiatg-1; Sat, 02 Jul 2022 07:33:58 -0400 X-MC-Unique: lxLR4XDgPc2hJy4jSRiatg-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 29CE185A580; Sat, 2 Jul 2022 11:33:58 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.39.194.114]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0CB23492C3B; Sat, 2 Jul 2022 11:33:54 +0000 (UTC) From: Alberto Faria To: qemu-devel@nongnu.org Cc: Paolo Bonzini , qemu-block@nongnu.org, "Denis V. Lunev" , Emanuele Giuseppe Esposito , Stefan Hajnoczi , Ronnie Sahlberg , Hanna Reitz , Stefano Garzarella , Kevin Wolf , Peter Xu , Alberto Garcia , John Snow , Eric Blake , Fam Zheng , Markus Armbruster , Vladimir Sementsov-Ogievskiy , Peter Lieven , Alberto Faria Subject: [RFC 6/8] Fix some coroutine_fn indirect calls and pointer assignments Date: Sat, 2 Jul 2022 12:33:29 +0100 Message-Id: <20220702113331.2003820-7-afaria@redhat.com> In-Reply-To: <20220702113331.2003820-1-afaria@redhat.com> References: <20220702113331.2003820-1-afaria@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Received-SPF: pass client-ip=170.10.133.124; envelope-from=afaria@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -21 X-Spam_score: -2.2 X-Spam_bar: -- X-Spam_report: (-2.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.082, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" These problems were found by static-analyzer.py. Only a few of the reported cases were fixed. Signed-off-by: Alberto Faria --- include/block/block_int-common.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 8947abab76..16c45d1262 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -731,13 +731,11 @@ struct BlockDriver { void coroutine_fn (*bdrv_co_drain_end)(BlockDriverState *bs); bool (*bdrv_supports_persistent_dirty_bitmap)(BlockDriverState *bs); - bool (*bdrv_co_can_store_new_dirty_bitmap)(BlockDriverState *bs, - const char *name, - uint32_t granularity, - Error **errp); - int (*bdrv_co_remove_persistent_dirty_bitmap)(BlockDriverState *bs, - const char *name, - Error **errp); + bool coroutine_fn (*bdrv_co_can_store_new_dirty_bitmap)( + BlockDriverState *bs, const char *name, uint32_t granularity, + Error **errp); + int coroutine_fn (*bdrv_co_remove_persistent_dirty_bitmap)( + BlockDriverState *bs, const char *name, Error **errp); }; static inline bool block_driver_can_compress(BlockDriver *drv) From patchwork Sat Jul 2 11:33:30 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alberto Faria X-Patchwork-Id: 1651467 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=FH2x2Ues; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LZqyf0Nwgz9s07 for ; Sat, 2 Jul 2022 21:46:00 +1000 (AEST) Received: from localhost ([::1]:48298 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1o7bZV-0006rg-8U for incoming@patchwork.ozlabs.org; Sat, 02 Jul 2022 07:45:57 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52072) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1o7bO3-0003RD-OI for qemu-devel@nongnu.org; Sat, 02 Jul 2022 07:34:07 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]:26839) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1o7bO1-0007zm-Ut for qemu-devel@nongnu.org; Sat, 02 Jul 2022 07:34:07 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1656761645; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qgAvujYqizfhFzEg/64loORf7tkDYZhXuaubHSCsHLM=; b=FH2x2UesCPQfh1wY/XuraaxZiJQ/A2G7MR3Za0gg49c0cbVcpAS0PmQRrJTTvQzjOrLuKh 6Ot5Wq26T+KVZ9YIgIbI0LJPQBk5gLu3w6m9bemey9uiCf/5p0ZVF/aBJv7ZHTmA0qvYQn iXLJe5yzKG5nQtleTZj1i7KMwCUkoWc= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-53-I_GKM4V1NfeADn2PeqoCzQ-1; Sat, 02 Jul 2022 07:34:02 -0400 X-MC-Unique: I_GKM4V1NfeADn2PeqoCzQ-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id BDE991C068E2; Sat, 2 Jul 2022 11:34:01 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.39.194.114]) by smtp.corp.redhat.com (Postfix) with ESMTP id 853A1492C3B; Sat, 2 Jul 2022 11:33:58 +0000 (UTC) From: Alberto Faria To: qemu-devel@nongnu.org Cc: Paolo Bonzini , qemu-block@nongnu.org, "Denis V. Lunev" , Emanuele Giuseppe Esposito , Stefan Hajnoczi , Ronnie Sahlberg , Hanna Reitz , Stefano Garzarella , Kevin Wolf , Peter Xu , Alberto Garcia , John Snow , Eric Blake , Fam Zheng , Markus Armbruster , Vladimir Sementsov-Ogievskiy , Peter Lieven , Alberto Faria Subject: [RFC 7/8] block: Add no_coroutine_fn marker Date: Sat, 2 Jul 2022 12:33:30 +0100 Message-Id: <20220702113331.2003820-8-afaria@redhat.com> In-Reply-To: <20220702113331.2003820-1-afaria@redhat.com> References: <20220702113331.2003820-1-afaria@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Received-SPF: pass client-ip=170.10.129.124; envelope-from=afaria@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -28 X-Spam_score: -2.9 X-Spam_bar: -- X-Spam_report: (-2.9 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.082, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" When applied to a function, it advertises that it should not be called from coroutine_fn functions. Make generated_co_wrapper evaluate to no_coroutine_fn, as coroutine_fn functions should instead directly call the coroutine_fn that backs the generated_co_wrapper. Extend static-analyzer.py's "coroutine-annotation-validity" and "coroutine-calls" checks to enforce no_coroutine_fn rules. Signed-off-by: Alberto Faria --- include/block/block-common.h | 2 +- include/qemu/coroutine.h | 12 ++++++++++++ static-analyzer.py | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/include/block/block-common.h b/include/block/block-common.h index fdb7306e78..4b60c8c6f2 100644 --- a/include/block/block-common.h +++ b/include/block/block-common.h @@ -42,7 +42,7 @@ * * Read more in docs/devel/block-coroutine-wrapper.rst */ -#define generated_co_wrapper +#define generated_co_wrapper no_coroutine_fn /* block.c */ typedef struct BlockDriver BlockDriver; diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index 40a4037525..11eea8cc79 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -48,6 +48,18 @@ #define coroutine_fn #endif +/** + * Mark a function that should never be called from a coroutine context + * + * This typically means that there is an analogous, coroutine_fn function that + * should be used instead. + */ +#ifdef __clang__ +#define no_coroutine_fn __attribute__((__annotate__("no_coroutine_fn"))) +#else +#define no_coroutine_fn +#endif + /** * This can wrap a call to a coroutine_fn from a non-coroutine_fn function and * suppress the static analyzer's complaints. diff --git a/static-analyzer.py b/static-analyzer.py index 485d054052..ad7ee1ccf5 100755 --- a/static-analyzer.py +++ b/static-analyzer.py @@ -459,6 +459,12 @@ def check_coroutine_annotation_validity( ): log(node, "invalid coroutine_fn usage") + if is_annotation(node, "no_coroutine_fn") and ( + ancestors[-1] is None + or not is_valid_no_coroutine_fn_usage(ancestors[-1]) + ): + log(node, "invalid no_coroutine_fn usage") + if is_comma_wrapper( node, "__allow_coroutine_fn_call" ) and not is_valid_allow_coroutine_fn_call_usage(node): @@ -478,6 +484,9 @@ def log_annotation_disagreement(annotation: str) -> None: if is_coroutine_fn(node) != is_coroutine_fn(node.canonical): log_annotation_disagreement("coroutine_fn") + if is_no_coroutine_fn(node) != is_no_coroutine_fn(node.canonical): + log_annotation_disagreement("no_coroutine_fn") + @check("coroutine-calls") def check_coroutine_calls( @@ -516,6 +525,11 @@ def check_coroutine_calls( ): log(call, "non-coroutine_fn function calls coroutine_fn") + # reject calls from coroutine_fn to no_coroutine_fn + + if caller_is_coroutine and is_no_coroutine_fn(callee): + log(call, f"coroutine_fn calls no_coroutine_fn function") + @check("coroutine-pointers") def check_coroutine_pointers( @@ -704,6 +718,16 @@ def parent_type_is_function_pointer() -> bool: return False +def is_valid_no_coroutine_fn_usage(parent: Cursor) -> bool: + """ + Checks if an occurrence of `no_coroutine_fn` represented by a node with + parent `parent` appears at a valid point in the AST. This is the case if the + parent is a function declaration/definition. + """ + + return parent.kind == CursorKind.FUNCTION_DECL + + def is_valid_allow_coroutine_fn_call_usage(node: Cursor) -> bool: """ Check if an occurrence of `__allow_coroutine_fn_call()` represented by node @@ -771,6 +795,17 @@ def is_coroutine_fn(node: Cursor) -> bool: return False +def is_no_coroutine_fn(node: Cursor) -> bool: + """ + Checks whether the given `node` should be considered to be + `no_coroutine_fn`. + + This assumes valid usage of `no_coroutine_fn`. + """ + + return is_annotated_with(node, "no_coroutine_fn") + + def is_annotated_with(node: Cursor, annotation: str) -> bool: return any(is_annotation(c, annotation) for c in node.get_children()) From patchwork Sat Jul 2 11:33:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alberto Faria X-Patchwork-Id: 1651468 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=hC0qKsbs; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LZr0j4Xfjz9s07 for ; Sat, 2 Jul 2022 21:47:49 +1000 (AEST) Received: from localhost ([::1]:51862 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1o7bbH-000149-7S for incoming@patchwork.ozlabs.org; Sat, 02 Jul 2022 07:47:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52124) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1o7bO7-0003W4-KY for qemu-devel@nongnu.org; Sat, 02 Jul 2022 07:34:12 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]:60601) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1o7bO5-00080i-LP for qemu-devel@nongnu.org; Sat, 02 Jul 2022 07:34:11 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1656761649; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6ucg/IwUXXbiD7o0QoLNGNJZ5xaPheNGQ2/axa9ThQo=; b=hC0qKsbsL+bG+PT0cmCyi8sja0NlUtXmZdVJo83wlQkhOfzW+Ymwy09hLPKF/hM3WCtHjr UCm8b27OW9CPB3wRjCZS8w/xTcdhra6Sl6zEApGpeAoCmtZIjKQ35YBZdpbdyocjUuoacR B05B2x2o/bIXCRAFG3V/cQUFUYHdRVs= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-529-XcNUMVLgPGiEUg1gD9Fgiw-1; Sat, 02 Jul 2022 07:34:05 -0400 X-MC-Unique: XcNUMVLgPGiEUg1gD9Fgiw-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 584FC1C068E2; Sat, 2 Jul 2022 11:34:05 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.39.194.114]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3161F492C3B; Sat, 2 Jul 2022 11:34:02 +0000 (UTC) From: Alberto Faria To: qemu-devel@nongnu.org Cc: Paolo Bonzini , qemu-block@nongnu.org, "Denis V. Lunev" , Emanuele Giuseppe Esposito , Stefan Hajnoczi , Ronnie Sahlberg , Hanna Reitz , Stefano Garzarella , Kevin Wolf , Peter Xu , Alberto Garcia , John Snow , Eric Blake , Fam Zheng , Markus Armbruster , Vladimir Sementsov-Ogievskiy , Peter Lieven , Alberto Faria Subject: [RFC 8/8] Avoid calls from coroutine_fn to no_coroutine_fn Date: Sat, 2 Jul 2022 12:33:31 +0100 Message-Id: <20220702113331.2003820-9-afaria@redhat.com> In-Reply-To: <20220702113331.2003820-1-afaria@redhat.com> References: <20220702113331.2003820-1-afaria@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Received-SPF: pass client-ip=170.10.129.124; envelope-from=afaria@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -28 X-Spam_score: -2.9 X-Spam_bar: -- X-Spam_report: (-2.9 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.082, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" These calls were found by static-analyzer.py. Signed-off-by: Alberto Faria --- block/block-backend.c | 2 +- block/io.c | 10 +++++----- block/parallels.c | 4 ++-- block/qcow2-refcount.c | 2 +- block/qed-table.c | 2 +- block/qed.c | 2 +- block/vmdk.c | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c index 5f2a912a59..8fa48576cd 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1395,7 +1395,7 @@ static int coroutine_fn blk_pwritev_part(BlockBackend *blk, int64_t offset, int ret; blk_inc_in_flight(blk); - ret = blk_do_pwritev_part(blk, offset, bytes, qiov, qiov_offset, flags); + ret = blk_co_do_pwritev_part(blk, offset, bytes, qiov, qiov_offset, flags); blk_dec_in_flight(blk); return ret; diff --git a/block/io.c b/block/io.c index bbfe94503b..832bccd31e 100644 --- a/block/io.c +++ b/block/io.c @@ -2781,8 +2781,8 @@ int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, return 1; } - ret = bdrv_common_block_status_above(bs, NULL, false, false, offset, - bytes, &pnum, NULL, NULL, NULL); + ret = bdrv_co_common_block_status_above(bs, NULL, false, false, offset, + bytes, &pnum, NULL, NULL, NULL); if (ret < 0) { return ret; @@ -2798,9 +2798,9 @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t dummy; IO_CODE(); - ret = bdrv_common_block_status_above(bs, bs, true, false, offset, - bytes, pnum ? pnum : &dummy, NULL, - NULL, NULL); + ret = bdrv_co_common_block_status_above(bs, bs, true, false, offset, + bytes, pnum ? pnum : &dummy, NULL, + NULL, NULL); if (ret < 0) { return ret; } diff --git a/block/parallels.c b/block/parallels.c index 8879b7027a..22c59a1ee2 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -503,8 +503,8 @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs, * In order to really repair the image, we must shrink it. * That means we have to pass exact=true. */ - ret = bdrv_truncate(bs->file, res->image_end_offset, true, - PREALLOC_MODE_OFF, 0, &local_err); + ret = bdrv_co_truncate(bs->file, res->image_end_offset, true, + PREALLOC_MODE_OFF, 0, &local_err); if (ret < 0) { error_report_err(local_err); res->check_errors++; diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index ed0ecfaa89..e30fd38e14 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -1233,7 +1233,7 @@ int coroutine_fn qcow2_flush_caches(BlockDriverState *bs) return ret; } - return bdrv_flush(bs->file->bs); + return bdrv_co_flush(bs->file->bs); } /*********************************************************/ diff --git a/block/qed-table.c b/block/qed-table.c index 1cc844b1a5..aa203f2627 100644 --- a/block/qed-table.c +++ b/block/qed-table.c @@ -100,7 +100,7 @@ static int coroutine_fn qed_write_table(BDRVQEDState *s, uint64_t offset, } if (flush) { - ret = bdrv_flush(s->bs); + ret = bdrv_co_flush(s->bs); if (ret < 0) { goto out; } diff --git a/block/qed.c b/block/qed.c index 96f4cda83f..dc9f065c02 100644 --- a/block/qed.c +++ b/block/qed.c @@ -490,7 +490,7 @@ static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options, } /* From here on only known autoclear feature bits are valid */ - bdrv_flush(bs->file->bs); + bdrv_co_flush(bs->file->bs); } s->l1_table = qed_alloc_table(s); diff --git a/block/vmdk.c b/block/vmdk.c index 38e5ab3806..5c94a2f27c 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -2150,8 +2150,8 @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes, return length; } length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE); - ret = bdrv_truncate(s->extents[i].file, length, false, - PREALLOC_MODE_OFF, 0, NULL); + ret = bdrv_co_truncate(s->extents[i].file, length, false, + PREALLOC_MODE_OFF, 0, NULL); if (ret < 0) { return ret; }