On Tue, Sep 27, 2022 at 03:46:19PM +0100, Richard W.M. Jones wrote: > 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(-)
ACK 1 and 2 regardless of the rest of the series. For this one... > > 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 ] It's a little bit odd to see UIntPtr called a 'non-pointer type' - but technically, it is an integer rather than a pointer. And the clincher is that even if it represents a pointer, for our purposes it is an opaque type, and the user can indeed pass in NULL (cast to uintptr_t) and we should not complain. So nothing wrong here other than maybe a confusing comment, although I don't have wording suggestions to help. > @@ -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) > I'm still getting used to OCaml's ability to rebind a variable as many iterations as we want, even with different typing! But this makes sense. > @@ -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"; Does disabling the warning actually force the compiler to emit the nonnull check, or can it still be optimized away in spite of us silencing the warning? Maybe we better off writing it so that for _this_ .c file, we pre-define LIBNBD_ATTRIBUTE_NONNULL() to be a no-op regardless of what the included .h files say. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://listman.redhat.com/mailman/listinfo/libguestfs