From nobody Thu Dec 18 13:56:14 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1656761788; cv=none; d=zohomail.com; s=zohoarc; b=XZVYhg22xkfzgEg86Fm7YN9KpZhh4oBrr3ZqmIbEsfxMQBNCFjiyYnubg39sPPUE1K1QSmRY0y2n2OlxgaMKrFN2CRPI4ItZtzTdjrkX1ae+jBlU9DddejVIgSVfOnWfX+jgR1Cl2qS40ADssblTFjs22eVveL1eHkNBf/PMZ0U= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1656761788; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=AVsjRvUFO7IRtcut4g0ir534oBEQ2f8ft4+r+hQg0BA=; b=LZXYKX9NN9sFKBNClpTLjrvr0IjejT2XLBWZaAQLcBC/VxNYkAq3MfDGXJAA1rqcJquUYAbBhDZ0PL+cIF0wovSa+kE6hjdEUAZ8c8+QD1tSgi7VcITnKoRAK8eZFX/iZByTaD0jjkjpCLyF4lkB76Me+xX9ArmmFd7zKUvxwIQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1656761788054250.98910313720535; Sat, 2 Jul 2022 04:36:28 -0700 (PDT) Received: from localhost ([::1]:34964 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1o7bQI-00061d-4x for importer@patchew.org; Sat, 02 Jul 2022 07:36:26 -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 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 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) 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= X-MC-Unique: iacSVY3DPBqkML1rw_IxMA-1 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 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1656761788635100001 Content-Type: text/plain; charset="utf-8" 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__ =3D lambda self: self.hash # so `Cursor`s can be dict keys + +# ------------------------------------------------------------------------= ---- # +# Usage + + +def parse_args() -> Namespace: + + available_checks =3D "\n".join(f" {name}" for (name, _) in CHECKS) + + parser =3D ArgumentParser( + formatter_class=3DRawDescriptionHelpFormatter, + epilog=3Df""" +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=3DPath) + + parser.add_argument( + "translation_units", + type=3DPath, + nargs=3D"*", + help=3D( + "Analyze only translation units whose root source file matches= or" + " is under one of the given paths." + ), + ) + + parser.add_argument( + "-c", + "--check", + metavar=3D"CHECK", + dest=3D"check_names", + choices=3D[name for (name, _) in CHECKS], + action=3D"append", + help=3D( + "Enable the given check. Can be given multiple times. If not g= iven," + " all checks are enabled." + ), + ) + + parser.add_argument( + "-j", + "--jobs", + dest=3D"threads", + type=3Dint, + help=3D( + "Number of threads to employ. Defaults to the number of logica= l" + " processors." + ), + ) + + parser.add_argument( + "--profile", + action=3D"store_true", + help=3D"Profile execution. Forces single-threaded execution.", + ) + + return parser.parse_args() + + +# ------------------------------------------------------------------------= ---- # +# Main + + +def main() -> NoReturn: + + args =3D parse_args() + + compile_commands =3D load_compilation_database(args) + contexts =3D get_translation_unit_contexts(args, compile_commands) + + analyze_translation_units(args, contexts) + + +def load_compilation_database(args: Namespace) -> Sequence[Mapping[str, st= r]]: + + # clang.cindex.CompilationDatabase.getCompileCommands() apparently pro= duces + # entries for files not listed in compile_commands.json in a best-effo= rt + # manner, which we don't want, so we parse the JSON ourselves instead. + + path =3D 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 =3D get_clang_system_include_paths() + check_names =3D args.check_names or [name for (name, _) in CHECKS] + + contexts =3D ( + TranslationUnitContext( + absolute_path=3Dstr(Path(cmd["directory"], cmd["file"]).resolv= e()), + compilation_working_dir=3Dcmd["directory"], + compilation_command=3Dcmd["command"], + system_include_paths=3Dsystem_include_paths, + check_names=3Dcheck_names, + ) + for cmd in compile_commands + ) + + if args.translation_units: + + allowed_prefixes =3D [ + # ensure path exists and is slash-terminated (even if it is a = file) + os.path.join(path.resolve(strict=3DTrue), "") + for path in args.translation_units + ] + + contexts =3D ( + ctx + for ctx in contexts + if any( + (ctx.absolute_path + "/").startswith(prefix) + for prefix in allowed_prefixes + ) + ) + + context_list =3D 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 incl= ude + # paths, so we ask clang what they are and include them ourselves. + + # TODO: Is there a less hacky way to do this? + + result =3D subprocess.run( + ["clang", "-E", "-", "-v"], + stdin=3Dsubprocess.DEVNULL, + stdout=3Dsubprocess.DEVNULL, + stderr=3Dsubprocess.PIPE, + universal_newlines=3DTrue, # decode stdout/stderr using default e= ncoding + check=3DTrue, + ) + + # Module `re` does not support repeated group captures. + pattern =3D ( + r"#include <...> search starts here:\n" + r"((?: \S*\n)+)" + r"End of search list." + ) + + match =3D 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=3Dargs.threads) as pool: + results =3D pool.map(analyze_translation_unit, contexts) + + else: + + import cProfile + import pstats + + profile =3D cProfile.Profile() + + try: + results =3D profile.runcall( + lambda: list(map(analyze_translation_unit, contexts)) + ) + finally: + stats =3D pstats.Stats(profile, stream=3Dsys.stderr) + stats.strip_dirs() + stats.sort_stats("tottime") + stats.print_stats() + + print( + f"\033[0;34mAnalyzed {len(contexts)}" + f" translation unit{'' if len(contexts) =3D=3D 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 =3D os.path.relpath(context.absolute_path) + + # load translation unit + + command =3D context.compilation_command.split() + + adjusted_command =3D [ + # 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 =3D os.getcwd() + os.chdir(context.compilation_working_dir) # for options like -I to wo= rk + + try: + tu =3D TranslationUnit.from_source(filename=3DNone, args=3Dadjuste= d_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 =3D False + + for diag in tu.diagnostics: + # consider only Fatal diagnostics, like missing includes + if diag.severity >=3D Diagnostic.Fatal: + found_problems =3D True + location =3D format_location(diag, default=3Drelative_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 =3D 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 =3D "(none)") -> str: + + location =3D obj.location + + if location.file is None: + return default + else: + abs_path =3D Path(location.file.name).resolve() + rel_path =3D os.path.relpath(abs_path) + return f"{rel_path}:{location.line}:{location.column}" + + +# ------------------------------------------------------------------------= ---- # +# Checks + +Checker =3D Callable[[TranslationUnit, str, Callable[[Cursor, str], None]]= , None] + +CHECKS: List[Tuple[str, Checker]] =3D [] + + +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 ev= er + uses. + + This check is best effort, but should never report false positives (po= sitive + 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 =3D=3D CursorKind.CALL_EXPR + and ancestors[-1].referenced =3D=3D 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 =3D=3D CursorKind.FOR_STMT: + [_init, cond, _adv] =3D ancestors[-2].get_children() + if ancestors[-1] =3D=3D 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 m= aybe + # uses their return value. Only includes static functions that don't r= eturn + # void and belong to the translation unit's root file (i.e, were not b= rought + # in by an #include). + funcs: Dict[Cursor, bool] =3D {} + + for [*ancestors, node] in all_paths(translation_unit.cursor): + + if ( + node.kind =3D=3D CursorKind.FUNCTION_DECL + and node.storage_class =3D=3D StorageClass.STATIC + and node.location.file.name =3D=3D translation_unit_path + and node.type.get_result().get_canonical().kind !=3D TypeKind.= VOID + ): + funcs.setdefault(node.canonical, False) + + if ( + node.kind =3D=3D CursorKind.DECL_REF_EXPR + and node.referenced.kind =3D=3D CursorKind.FUNCTION_DECL + and node.referenced.canonical in funcs + and function_occurrence_might_use_return_value(ancestors, node) + ): + funcs[node.referenced.canonical] =3D 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 =3D [] + + def aux(node: Cursor) -> Iterable[Sequence[Cursor]]: + nonlocal path + + if node.kind !=3D CursorKind.UNEXPOSED_EXPR: + path.append(node) + yield path + + for child in node.get_children(): + yield from aux(child) + + if node.kind !=3D CursorKind.UNEXPOSED_EXPR: + path.pop() + + return aux(root) + + +# ------------------------------------------------------------------------= ---- # +# Utilities handy for development + + +def print_node(node: Cursor) -> None: + + print(f"{format_location(node)}: kind =3D {node.kind.name}", end=3D"") + + if node.spelling: + print(f", name =3D {node.spelling}", end=3D"") + + if node.type is not None: + print(f", type =3D {node.type.get_canonical().spelling}", end=3D"") + + if node.referenced is not None: + print(f", referenced =3D {node.referenced.spelling}", end=3D"") + + print() + + +def print_tree( + node: Cursor, *, max_depth: Optional[int] =3D None, indentation_level:= int =3D 0 +) -> None: + + if max_depth is None or max_depth >=3D 0: + + print(" " * indentation_level, end=3D"") + print_node(node) + + for child in node.get_children(): + print_tree( + child, + max_depth=3DNone if max_depth is None else max_depth - 1, + indentation_level=3Dindentation_level + 1, + ) + + +# ------------------------------------------------------------------------= ---- # + +if __name__ =3D=3D "__main__": + main() + +# ------------------------------------------------------------------------= ---- # --=20 2.36.1 From nobody Thu Dec 18 13:56:14 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1656761878; cv=none; d=zohomail.com; s=zohoarc; b=FFpDZQQRsboqLXVBaoOfhYU0n3VnfsBRT/fNYOVAZOGL0dr5oX+eAVozeXniiudVo1vdAaGulscbNFuIWbgSuhkjPJ80BXWWbtoTHKZAtqLad5g1F2D6psJrhOhSFPBZ6OcU9BBaHEdhkfTIc5vJb3pmaM4UzOW6rftayaiW03M= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1656761878; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=BxfLSdJeaqScMeruvLuh/qoohWtLPXnBogvQe9zNGcM=; b=WxtHOfLWC1iAvp0oe04+3piENkKr6ydSUm/nFmTmBXRSrgsntMzmY4WyAjWJV8cVwUv+r5LhpDMdgC6Fk9p1FZy7rvBHz+dabQiMaYevO0L15JiYtccOf0qQyau8Oga0pBFtB4E02BED6Uf98ChJknFm+0e6Z8A/InRMPFQhx5A= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 16567618780491002.5633600875876; Sat, 2 Jul 2022 04:37:58 -0700 (PDT) Received: from localhost ([::1]:37550 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1o7bRk-0007mB-VP for importer@patchew.org; Sat, 02 Jul 2022 07:37:56 -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 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 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) 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= X-MC-Unique: VilpdHhqNECdBKGEMPyw3Q-1 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 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1656761878996100001 Content-Type: text/plain; charset="utf-8" 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 =3D (max_size < MAX_BLOCKSIZE) ? BDRV_SECTOR_SIZE @@ -1903,7 +1903,6 @@ static int allocate_first_block(int fd, size_t max_si= ze) size_t max_align =3D MAX(MAX_BLOCKSIZE, qemu_real_host_page_size()); void *buf; ssize_t n; - int ret; =20 buf =3D 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_s= ize) n =3D pwrite(fd, buf, write_size, 0); } while (n =3D=3D -1 && errno =3D=3D EINTR); =20 - ret =3D (n =3D=3D -1) ? -errno : 0; - qemu_vfree(buf); - return ret; } =20 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); } =20 -static bool coroutine_fn bdrv_wait_serialising_requests(BdrvTrackedRequest= *self) +static void coroutine_fn +bdrv_wait_serialising_requests(BdrvTrackedRequest *self) { BlockDriverState *bs =3D self->bs; - bool waited =3D false; =20 if (!qatomic_read(&bs->serialising_in_flight)) { - return false; + return; } =20 qemu_co_mutex_lock(&bs->reqs_lock); - waited =3D bdrv_wait_serialising_requests_locked(self); + bdrv_wait_serialising_requests_locked(self); qemu_co_mutex_unlock(&bs->reqs_lock); - - return waited; } =20 bool coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req, @@ -1689,10 +1687,10 @@ static bool bdrv_init_padding(BlockDriverState *bs, return true; } =20 -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 =3D child->bs; @@ -1715,7 +1713,7 @@ static int bdrv_padding_rmw_read(BdrvChild *child, ret =3D 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->ta= il); } =20 - return 0; + return; } =20 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; } =20 -static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb) +static void free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *t= b) { int ret; uint64_t *bitmap_table; =20 ret =3D bitmap_table_load(bs, tb, &bitmap_table); if (ret < 0) { - return ret; + return; } =20 clear_bitmap_table(bs, bitmap_table, tb->size); @@ -274,8 +274,6 @@ static int free_bitmap_clusters(BlockDriverState *bs, Q= cow2BitmapTable *tb) =20 tb->offset =3D 0; tb->size =3D 0; - - return 0; } =20 /* 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) } } =20 -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 *ac= b, qemu_coroutine_enter(co); } } - - /* return true if any rewrite is done else false */ - return count; } =20 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(BlockDriv= erState *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. Overr= ide - * 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 o= f 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, ui= nt16_t *cyls, } =20 *cyls =3D cyls_times_heads / *heads; - - return 0; } =20 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; } =20 -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); } =20 /* return the index for a given member */ @@ -2967,13 +2967,12 @@ DLOG(checkpoint()); return 0; } =20 -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); } =20 static int vvfat_write(BlockDriverState *bs, int64_t sector_num, --=20 2.36.1 From nobody Thu Dec 18 13:56:14 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1656762217; cv=none; d=zohomail.com; s=zohoarc; b=doUBsnEIxjCnr5t0k0z1GORMkjyqxDq9nKVOAl0ixWTmgnCVyhaV6sl9IKUHzlrOpZwbH0zgGoGbhbdp++OZ9MXdWmUPBlAl+THVjS0o29pRtyyBilcG6/xstqZB4b/swNP6YzpRvKe4W6uzxIQKvId7kmuyWsfGwZ55m/TViq4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1656762217; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=4RJMvRmvaUErr26isQn4HMpApGBcAGf31Hfvrw0Nv1E=; b=HEqezAFzxzuQhNE9wn6QTZVMJFz55qfEVLfnHKRFnGmtY+Cch2sNvDmqUbxRyAJDPyPhuHZYSG4nSfZXtqO/ymS2fs6fyDJ/1ze22R9oiruGZ/npLgyIagXmCfWOgMWMO3iNZkOcoVt+viLBJfoCPsaU77rI2/o194AtHGv8L8w= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1656762217634282.1428912340697; Sat, 2 Jul 2022 04:43:37 -0700 (PDT) Received: from localhost ([::1]:46074 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1o7bXE-0005NE-Iv for importer@patchew.org; Sat, 02 Jul 2022 07:43:36 -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 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 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) 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= X-MC-Unique: Irk5VbeEMAeXnJXriob9vg-1 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 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1656762219597100001 Content-Type: text/plain; charset="utf-8" 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) =20 typedef struct Coroutine Coroutine; =20 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") =20 =20 +@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 =3D=3D 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) !=3D 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 =3D=3D CursorKind.FUNCTION_DECL and n.is_definiti= on(), + ): + + caller_is_coroutine =3D is_coroutine_fn(caller) + + for [*_, call_parent, call] in filter( + lambda path: path[-1].kind =3D=3D CursorKind.CALL_EXPR, + all_paths(caller), + ): + + # We can get some "calls" that are actually things like top-le= vel + # macro invocations. + if call.referenced is None: + continue + + callee =3D 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 =20 @@ -464,6 +539,138 @@ def aux(node: Cursor) -> Iterable[Sequence[Cursor]]: return aux(root) =20 =20 +# 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 pa= rent + `parent` appears at a valid point in the AST. This is the case if `par= ent` + is: + + - A function declaration/definition, OR + - A field/variable/parameter declaration with a function pointer typ= e, OR + - A typedef of a function type or function pointer type. + """ + + if parent.kind =3D=3D CursorKind.FUNCTION_DECL: + return True + + canonical_type =3D parent.type.get_canonical() + + def parent_type_is_function() -> bool: + return canonical_type.kind =3D=3D TypeKind.FUNCTIONPROTO + + def parent_type_is_function_pointer() -> bool: + return ( + canonical_type.kind =3D=3D TypeKind.POINTER + and canonical_type.get_pointee().kind =3D=3D TypeKind.FUNCTION= PROTO + ) + + if parent.kind in [ + CursorKind.FIELD_DECL, + CursorKind.VAR_DECL, + CursorKind.PARM_DECL, + ]: + return parent_type_is_function_pointer() + + if parent.kind =3D=3D CursorKind.TYPEDEF_DECL: + return parent_type_is_function() or parent_type_is_function_pointe= r() + + 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 ri= ght + 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] =3D node.get_children() + + if call.kind !=3D 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_f= n`. + + This assumes valid usage of `coroutine_fn`. + """ + + while node.kind in [CursorKind.PAREN_EXPR, CursorKind.UNEXPOSED_EXPR]: + children =3D list(node.get_children()) + if len(children) =3D=3D 1: + node =3D children[0] + else: + break + + return node.kind =3D=3D 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 =3D=3D CursorKind.ANNOTATE_ATTR and node.spelling =3D= =3D annotation + + +# A "comma wrapper" is the pattern `((void)string_literal, expr)`. The `ex= pr` 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 !=3D CursorKind.BINARY_OPERATOR: + return False + + [left, _right] =3D node.get_children() + + if ( + left.kind !=3D CursorKind.CSTYLE_CAST_EXPR + or left.type.kind !=3D TypeKind.VOID + ): + return False + + [unexposed_expr] =3D left.get_children() + + if unexposed_expr.kind !=3D CursorKind.UNEXPOSED_EXPR: + return False + + [string_literal] =3D unexposed_expr.get_children() + + return ( + string_literal.kind =3D=3D CursorKind.STRING_LITERAL + and string_literal.spelling =3D=3D f'"{literal}"' + ) + + # ------------------------------------------------------------------------= ---- # # Utilities handy for development =20 --=20 2.36.1 From nobody Thu Dec 18 13:56:14 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1656761790; cv=none; d=zohomail.com; s=zohoarc; b=hDqzS+oB/s33P5F9TmExotzSdNiKWuYwMYTDnWARwhydA4R8dwY4AUjPHvV9ls/XzAshOp/0bljjyqtb2WFDXpNOWPq+hN7u9hcr4JJhhtxsPqB6/3A4zib8Art9vGTVskkEvjGgj1Mf2sQHczxjD08H8pjqG+/sNOGmsNwRBkU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1656761790; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=U019ymYOutfn4cZj9FQwzQdfQ9NuRH86JCzWCeQt3Cs=; b=hmGTAeg4TCDarr7HJgxIu+WuvWXSo+J00QAY8wWC1o8a8hzlffgpFT85sZwe7fR7/PsjvHhmeiO9cwtK8IlpYPO+P+6bni7RSRBFTbygAI1XGpPzfiSciWsoLeS+aOk8m0hGmIKUM3yrwuz33rWsmBP3ehpMS2wnYlSrwDt8kno= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1656761790399183.72895285698473; Sat, 2 Jul 2022 04:36:30 -0700 (PDT) Received: from localhost ([::1]:35224 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1o7bQK-0006CI-TC for importer@patchew.org; Sat, 02 Jul 2022 07:36:28 -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 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 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) 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= X-MC-Unique: aSky6CNZOwKvdcOooigZ7Q-1 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 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1656761792685100001 Content-Type: text/plain; charset="utf-8" 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 =3D rwco->iobuf; =20 assert(qiov->size =3D=3D acb->bytes); - rwco->ret =3D blk_co_do_preadv(rwco->blk, rwco->offset, acb->bytes, - qiov, rwco->flags); + rwco->ret =3D __allow_coroutine_fn_call( + blk_co_do_preadv(rwco->blk, rwco->offset, acb->bytes, qiov, + rwco->flags)); blk_aio_complete(acb); } =20 @@ -1682,7 +1683,8 @@ static void blk_aio_ioctl_entry(void *opaque) BlkAioEmAIOCB *acb =3D opaque; BlkRwCo *rwco =3D &acb->rwco; =20 - rwco->ret =3D blk_co_do_ioctl(rwco->blk, rwco->offset, rwco->iobuf); + rwco->ret =3D __allow_coroutine_fn_call( + blk_co_do_ioctl(rwco->blk, rwco->offset, rwco->iobuf)); =20 blk_aio_complete(acb); } @@ -1716,7 +1718,8 @@ static void blk_aio_pdiscard_entry(void *opaque) BlkAioEmAIOCB *acb =3D opaque; BlkRwCo *rwco =3D &acb->rwco; =20 - rwco->ret =3D blk_co_do_pdiscard(rwco->blk, rwco->offset, acb->bytes); + rwco->ret =3D __allow_coroutine_fn_call( + blk_co_do_pdiscard(rwco->blk, rwco->offset, acb->bytes)); blk_aio_complete(acb); } =20 @@ -1772,7 +1775,7 @@ static void blk_aio_flush_entry(void *opaque) BlkAioEmAIOCB *acb =3D opaque; BlkRwCo *rwco =3D &acb->rwco; =20 - rwco->ret =3D blk_co_do_flush(rwco->blk); + rwco->ret =3D __allow_coroutine_fn_call(blk_co_do_flush(rwco->blk)); blk_aio_complete(acb); } =20 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(BlockDriverStat= e *bs, return req; } =20 -static void cbw_snapshot_read_unlock(BlockDriverState *bs, BlockReq *req) +static coroutine_fn void +cbw_snapshot_read_unlock(BlockDriverState *bs, BlockReq *req) { BDRVCopyBeforeWriteState *s =3D bs->opaque; =20 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(BlockDriverStat= e *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 =3D { @@ -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, e= rrp); + return __allow_coroutine_fn_call( + bdrv_co_can_store_new_dirty_bitmap(bs, name, granularity, errp= )); } else { Coroutine *co; BdrvCanStoreNewDirtyBitmapCo s =3D { 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 st= atus, } } =20 -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 =3D (struct IscsiTask) { .co =3D 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 **err= p); 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; } =20 -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); =20 @@ -278,7 +278,7 @@ static bool qed_plug_allocating_write_reqs(BDRVQEDState= *s) return true; } =20 -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 *o= ptions, int flags, =20 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() =3D=3D qemu_get_aio_context(= )); qemu_coroutine_enter(qemu_coroutine_create(bdrv_qed_open_entry, &q= oc)); 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 *bu= f); /* Ensure contents are flushed to disk. */ int coroutine_fn bdrv_co_flush(BlockDriverState *bs); =20 -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 offse= t, 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 byt= es, int64_t *pnum); --=20 2.36.1 From nobody Thu Dec 18 13:56:14 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1656762184; cv=none; d=zohomail.com; s=zohoarc; b=mKQM5jbxfeMaC+nN++oLQVeHg16vr1looFFEVHDDIyNZ2Y4wwwD105JX0Puuw2QBfZC/ZzvAYNXxQGdPvS64Iu360UYDm5Iua0+HIBAqPpj/BdM5G8HmXahmYT7NENH2piHI7pTHeubrdQ9On2fkZnIg3wbbe4noLmfu9pUoygY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1656762184; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=J20t4lF9lHmYknS0yWn5MoQszWEEaQKBQdjeVtzgefw=; b=FUkwAoes3G75h2wAXwmge3/ndBUVF2Z4GkPQfPY5MI0d7f3vy96K0UlHFm9wuU1CFH3M3O5dgLNcjMKIWIaBVA1UQvJ6H62i0LLn4f3+HWtG8iqteNozcEs3R/MZpZmTao/noHs2msig0gh7ITtWokR2XpnUy/N/RRNYCpZKlRg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1656762184457100.47512358830693; Sat, 2 Jul 2022 04:43:04 -0700 (PDT) Received: from localhost ([::1]:44262 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1o7bWh-000447-0U for importer@patchew.org; Sat, 02 Jul 2022 07:43:03 -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 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 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) 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= X-MC-Unique: 7DuygAgEPyKkG5q3iRxabQ-1 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 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1656762185525100001 Content-Type: text/plain; charset="utf-8" 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, ) =20 Cursor.__hash__ =3D 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") =20 =20 +@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 a= t 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 =3D=3D CursorKind.VAR_DECL: + + children =3D [ + 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) =3D=3D 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 =3D=3D CursorKind.INIT_LIST_EXPR: + + for initializer in filter( + lambda n: n.kind =3D=3D CursorKind.UNEXPOSED_EXPR, + node.get_children(), + ): + + children =3D list(initializer.get_children()) + + if ( + len(children) =3D=3D 2 + and children[0].kind =3D=3D 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, "=3D"): + + [left, right] =3D 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 =20 @@ -555,6 +641,31 @@ def subtrees_matching( # Node predicates =20 =20 +def is_binary_operator(node: Cursor, operator: str) -> bool: + return ( + node.kind =3D=3D CursorKind.BINARY_OPERATOR + and get_binary_operator_spelling(node) =3D=3D operator + ) + + +def get_binary_operator_spelling(node: Cursor) -> Optional[str]: + + assert node.kind =3D=3D CursorKind.BINARY_OPERATOR + + [left, right] =3D node.get_children() + + op_range =3D SourceRange.from_locations(left.extent.end, right.extent.= start) + + tokens =3D 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, *_] =3D 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 pa= rent @@ -599,7 +710,13 @@ def is_valid_allow_coroutine_fn_call_usage(node: Curso= r) -> bool: `node` appears at a valid point in the AST. This is the case if its ri= ght operand is a call to: =20 - - 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 ty= pe, + 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. =20 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 =20 - return node.kind =3D=3D CursorKind.FUNCTION_DECL and is_annotated_with( - node, "coroutine_fn" - ) + if node.kind in [CursorKind.DECL_REF_EXPR, CursorKind.MEMBER_REF_EXPR]: + node =3D node.referenced + + # --- + + if node.kind =3D=3D 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 =3D=3D CursorKind.TYPEDEF_DECL: + return is_annotated_with(node, "coroutine_fn") + + return False =20 =20 def is_annotated_with(node: Cursor, annotation: str) -> bool: --=20 2.36.1 From nobody Thu Dec 18 13:56:14 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1656762157; cv=none; d=zohomail.com; s=zohoarc; b=hyehNM+6sh+UfdMclLSziqwpF5qxCG7g9s1dJmJ7YEq8I7FfaSnJL+sUITWxbpQF1DdetEmn7Wa+KwKCgXdxUyC2uAvJJQnDIoGY+bk96ClrLvxJ4oW6wEBR60teU0NvlyVL8w0oZ26bKP5R94qZdbW0E2vaQVvz9/ibe/LA/3Q= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1656762157; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=6dsFT66wWWePXhL01EUVk5ehyeBB76oxgUuM4U+Bn9I=; b=QuZSEfw5BBjwQ3Esm220Wzht/cAgV6PvYpmYiPoo3RRoUPpXzNR8UquhjOb3iTTIcSt2mocRW7zJqBl4irJqreNgy9aRTZe/ZbWd/T31rhXwlE+KdDtbEQtk4sd86KDusEb9opKh6KHc1JNDq2oJ/BC+dBopVQr0IlDtonCosco= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1656762157753688.0635699701909; Sat, 2 Jul 2022 04:42:37 -0700 (PDT) Received: from localhost ([::1]:43798 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1o7bWE-0003jR-SV for importer@patchew.org; Sat, 02 Jul 2022 07:42:35 -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 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 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) 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= X-MC-Unique: lxLR4XDgPc2hJy4jSRiatg-1 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 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1656762159506100001 Content-Type: text/plain; charset="utf-8" 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-com= mon.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); =20 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); }; =20 static inline bool block_driver_can_compress(BlockDriver *drv) --=20 2.36.1 From nobody Thu Dec 18 13:56:14 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1656762454; cv=none; d=zohomail.com; s=zohoarc; b=KeSAMhG9jkphvM97mlRDGYKjAqFKXEu0TF5mueE9HL1NeiEbIJIvYiI58S+Jlwoz4l1HVPofd6hccrIsSIgnEfxRpwuD8IOQQ1JZWCschHGxa13iCwrn4rk3BJBT3eqc/17jRqT9osXiujdPxusH8Y+HYsMEIDF1Hu6wbawIdNw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1656762454; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=qgAvujYqizfhFzEg/64loORf7tkDYZhXuaubHSCsHLM=; b=IgwEiyirNiavdQOh187Iz5BPRDf839PrYEZigw46VyFDWBgLPVgTkhmiKjaqWkWSORbioudj+y9c7JWIvrrn4ABIlLb957W2FTcJYUjSmtbbay5ozRClURDY+i7cY27c/xHYsoIfvxUN/AkXTxivLr2IkCZIQ1z2iLc/BoAL3C4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1656762454040530.8109911077709; Sat, 2 Jul 2022 04:47:34 -0700 (PDT) Received: from localhost ([::1]:51896 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1o7bb2-00015G-6R for importer@patchew.org; Sat, 02 Jul 2022 07:47:32 -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 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 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) 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= X-MC-Unique: I_GKM4V1NfeADn2PeqoCzQ-1 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 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1656762454883100001 Content-Type: text/plain; charset="utf-8" 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 =20 /* 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 =20 +/** + * 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") =20 + 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) -> Non= e: if is_coroutine_fn(node) !=3D is_coroutine_fn(node.canonical): log_annotation_disagreement("coroutine_fn") =20 + if is_no_coroutine_fn(node) !=3D is_no_coroutine_fn(node.canon= ical): + log_annotation_disagreement("no_coroutine_fn") + =20 @check("coroutine-calls") def check_coroutine_calls( @@ -516,6 +525,11 @@ def check_coroutine_calls( ): log(call, "non-coroutine_fn function calls coroutine_fn") =20 + # 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") + =20 @check("coroutine-pointers") def check_coroutine_pointers( @@ -704,6 +718,16 @@ def parent_type_is_function_pointer() -> bool: return False =20 =20 +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 =3D=3D 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 =20 =20 +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()) =20 --=20 2.36.1 From nobody Thu Dec 18 13:56:14 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1656762538; cv=none; d=zohomail.com; s=zohoarc; b=O8k/bFo62VJOxyXoE6Cz4tbKlaXGyljnSBPknOT4YvZFgvaMn/SMjJBi5vLW3asRCanOuj+bZdC8jwc9Hxj6n0mLuMoKi+mo6lWpTmS1kVvypqy5Ar94LFzgIY2GMzv07vZxNPTe4f11xddMVM4+7SeOZ5uJnXdl4j0lezlJVcA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1656762538; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=6ucg/IwUXXbiD7o0QoLNGNJZ5xaPheNGQ2/axa9ThQo=; b=Zu2rMDmGtIxL8ktlRyOTDOOo/toK7oirtfmMrTTVaMc7cPFxEhfxxUIukaO4rpATm6U2shrlz4O0FBzenMNy2QdoZxuMmpyXzXQd+oGKiwdscFu6xxFlgLAprTkuQJV+Uq7CqoRXDcjl+9Ex9ROsPlUDwaFhO0WUUXPFBw2mhwA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1656762538671559.1745339586042; Sat, 2 Jul 2022 04:48:58 -0700 (PDT) Received: from localhost ([::1]:53934 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1o7bcO-0002Xy-VN for importer@patchew.org; Sat, 02 Jul 2022 07:48:57 -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 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 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) 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= X-MC-Unique: XcNUMVLgPGiEUg1gD9Fgiw-1 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 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; 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+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1656762539467100001 Content-Type: text/plain; charset="utf-8" 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; =20 blk_inc_in_flight(blk); - ret =3D blk_do_pwritev_part(blk, offset, bytes, qiov, qiov_offset, fla= gs); + ret =3D blk_co_do_pwritev_part(blk, offset, bytes, qiov, qiov_offset, = flags); blk_dec_in_flight(blk); =20 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(BlockDriverStat= e *bs, int64_t offset, return 1; } =20 - ret =3D bdrv_common_block_status_above(bs, NULL, false, false, offset, - bytes, &pnum, NULL, NULL, NULL); + ret =3D bdrv_co_common_block_status_above(bs, NULL, false, false, offs= et, + bytes, &pnum, NULL, NULL, NULL= ); =20 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(); =20 - ret =3D bdrv_common_block_status_above(bs, bs, true, false, offset, - bytes, pnum ? pnum : &dummy, NULL, - NULL, NULL); + ret =3D bdrv_co_common_block_status_above(bs, bs, true, false, offset, + bytes, pnum ? pnum : &dummy, N= ULL, + 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(BlockDriverS= tate *bs, * In order to really repair the image, we must shrink it. * That means we have to pass exact=3Dtrue. */ - ret =3D bdrv_truncate(bs->file, res->image_end_offset, true, - PREALLOC_MODE_OFF, 0, &local_err); + ret =3D 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; } =20 - return bdrv_flush(bs->file->bs); + return bdrv_co_flush(bs->file->bs); } =20 /*********************************************************/ 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, } =20 if (flush) { - ret =3D bdrv_flush(s->bs); + ret =3D 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(BlockDriverSta= te *bs, QDict *options, } =20 /* From here on only known autoclear feature bits are valid */ - bdrv_flush(bs->file->bs); + bdrv_co_flush(bs->file->bs); } =20 s->l1_table =3D 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, int6= 4_t offset, int64_t bytes, return length; } length =3D QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE); - ret =3D bdrv_truncate(s->extents[i].file, length, false, - PREALLOC_MODE_OFF, 0, NULL); + ret =3D bdrv_co_truncate(s->extents[i].file, length, false, + PREALLOC_MODE_OFF, 0, NULL); if (ret < 0) { return ret; } --=20 2.36.1