[Libguestfs] [PATCH libnbd 3/5] generator: Add attribute((nonnull)) annotations to non-NULL parameters

Richard W.M. Jones rjones at redhat.com
Tue Sep 27 14:46:19 UTC 2022


For API parameters that are pointers and must not be NULL, add the
appropriate GCC annotations.  These are only enabled in very recent
GCC (>= 12) because we have concerns with earlier versions, see for
example: https://bugzilla.redhat.com/show_bug.cgi?id=1041336
---
 generator/C.ml | 52 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 50 insertions(+), 2 deletions(-)

diff --git a/generator/C.ml b/generator/C.ml
index 013f81edf4..4f758e526f 100644
--- a/generator/C.ml
+++ b/generator/C.ml
@@ -107,6 +107,26 @@ let
   | UInt64 n -> [n]
   | UIntPtr n -> [n]
 
+let arg_attr_nonnull =
+  function
+  (* BytesIn/Out are passed using a non-null pointer, and size_t *)
+  | BytesIn _
+  | BytesOut _
+  | BytesPersistIn _
+  | BytesPersistOut _ -> [ true; false ]
+  (* sockaddr is also non-null pointer, and length *)
+  | SockAddrAndLen (n, len) -> [ true; false ]
+  (* strings should be marked as non-null *)
+  | Path _ | String _ -> [ true ]
+  (* list of strings should be marked as non-null *)
+  | StringList n -> [ true ]
+  (* other non-pointer types can never be null *)
+  | Bool _ | Closure _ | Enum _ | Fd _ | Flags _
+  | Int _ | Int64 _ | SizeT _
+  | UInt _ | UInt32 _ | UInt64 _ | UIntPtr _ -> [ false ]
+
+let optarg_attr_nonnull (OClosure _ | OFlags _) = [ false ]
+
 let rec print_arg_list ?(wrap = false) ?maxcol ?handle ?types ?(parens = true)
           ?closure_style args optargs =
   if parens then pr "(";
@@ -216,7 +236,17 @@ let
 let print_fndecl ?wrap ?closure_style name args optargs ret =
   pr "extern ";
   print_call ?wrap ?closure_style name args optargs ret;
-  pr ";\n"
+
+  (* Non-null attribute. *)
+  let nns =
+    [ [ true ] ] (* for struct nbd_handle pointer *)
+    @ List.map arg_attr_nonnull args
+    @ List.map optarg_attr_nonnull optargs in
+  let nns : bool list = List.flatten nns in
+  let nns = List.mapi (fun i b -> (i+1, b)) nns in
+  let nns = filter_map (fun (i, b) -> if b then Some i else None) nns in
+  let nns : string list = List.map string_of_int nns in
+  pr "\n    LIBNBD_ATTRIBUTE_NONNULL((%s));\n" (String.concat "," nns)
 
 let rec print_cbarg_list ?(wrap = false) ?maxcol ?types ?(parens = true)
           cbargs =
@@ -349,6 +379,17 @@ let
   pr "extern \"C\" {\n";
   pr "#endif\n";
   pr "\n";
+  pr "#if defined(__GNUC__)\n";
+  pr "#define LIBNBD_GCC_VERSION \\\n";
+  pr "    (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)\n";
+  pr "#endif\n";
+  pr "\n";
+  pr "#if defined(__GNUC__) && LIBNBD_GCC_VERSION >= 120000 /* gcc >= 12.0 */\n";
+  pr "#define LIBNBD_ATTRIBUTE_NONNULL(s) __attribute__((__nonnull__ s))\n";
+  pr "#else\n";
+  pr "#define LIBNBD_ATTRIBUTE_NONNULL(s)\n";
+  pr "#endif\n";
+  pr "\n";
   pr "struct nbd_handle;\n";
   pr "\n";
   List.iter (
@@ -382,7 +423,7 @@ let
   pr "extern struct nbd_handle *nbd_create (void);\n";
   pr "#define LIBNBD_HAVE_NBD_CREATE 1\n";
   pr "\n";
-  pr "extern void nbd_close (struct nbd_handle *h);\n";
+  pr "extern void nbd_close (struct nbd_handle *h); /* h can be NULL */\n";
   pr "#define LIBNBD_HAVE_NBD_CLOSE 1\n";
   pr "\n";
   pr "extern const char *nbd_get_error (void);\n";
@@ -773,6 +814,13 @@ let
   pr "#include \"libnbd.h\"\n";
   pr "#include \"internal.h\"\n";
   pr "\n";
+  pr "/* We check that some string parameters declared as nonnull are\n";
+  pr " * not NULL.  This is intentional because we do not know if the\n";
+  pr " * calling compiler checked the attributes.  So ignore those\n";
+  pr " * warnings here.\n";
+  pr " */\n";
+  pr "#pragma GCC diagnostic ignored \"-Wnonnull-compare\"\n";
+  pr "\n";
   List.iter print_wrapper handle_calls
 
 (* We generate a fragment of Makefile.am containing the list
-- 
2.37.0.rc2



More information about the Libguestfs mailing list