[PATCH 00/16] Farewell rpcgen

This series something I was hacking on a little while back in an attempt to make our RPC layer more maintainable. There are many aspects I'm unhappy about with current code * When serializing a message we have no clue how big it will be, but xdrmem_create wants a fixed size, so we have to keep trying to serialize in a loop making it bigger each time * We don't control memory allocation/free'ing directly so we can't do a virSecureErase on fields inside the RPC message struct that handle secrets. * The XDR API is generally unpleasant to use as it is outside our virNetMessage object. Ideally we would be reading/writing directly from/to the virNetMessage buffer with APIs on virNetMessage,instead of indirectly via a XDR object. * We want more from XDR than it actually gives us. Our XDR protocol files have annotations to express what we want our code generator todo, or for ACLs. The relationship between the structs and the message numbers is implicit. Essentially we've defined our own language indirectly via comments, and then parse this with regexes which is horrid. * The code rpcgen creates is poor quality which we have to post-process to fix bugs/problems. It also lacks support for modern features like g_auto. Anyway, in a fit of rage I looked at the XDR RFC and thought.. This language is trivial, why do we need to outsource to rpcgen and libtirpc instead of dealing with it directly. This small series moves in that direction. It creates an XDR language lexer and parser, and then a code generator which emits code that is (nearly) identical to what rpcgen would emit. This is sufficient to eliminate rpcgen usage and support g_auto. Since we're still using libtirpc at this stage we can be confident we're still doing the same thing on the wire. I've got some unit tests too with the rpcgen generation to validate stuff. The next step is to change the code generator so that instead of generating code for libtirpc APIs, it will instead directly speak virNetMessage APIs. That would give us full control over our RPC stack guaranteed to be platform portable instead of fighting slight differences in RPC libraries (eg xdr_quad vs xdr_int64 madness). I was going to wait until I had written such code before sending this series, but I've got diverted onto other more important tasks. So here at least is what I have so far. After that foundation is done, we are in a place where we can actually do more innovative things. For example we can directly extend the XDR protocol language if we like, turning our magic comments into properly parsable constructs. With this, we would be in a position to replace our Perl RPC client/server dispatch code generators with something that is more supportable in Python. The python code would work with properly represented objects and formal parsers and not regexes and anonymous complex perl data structures. Daniel P. Berrangé (16): rpcgen: drop type-puning workarounds build-aux: skip E203 and W503 flake8 checks build-aux: introduce 'black' tool for python formatting rpcgen: add an XDR protocol lexer rpcgen: add an XDR protocol abstract syntax tree rpcgen: add an XDR protocol parser rpcgen: define a visitor API for XDR protocol specs rpcgen: add a C code generator for XDR protocol specs rpcgen: add test case for XDR serialization rpcgen: define entrypoint for running new rpcgen impl build: switch over to new rpc generator code rpcgen: add g_auto function support rpc: use g_auto for client RPC return parameters admin: use g_auto for client RPC return parameters remote: use g_auto for client RPC return parameters rpc: add helpers for XDR type serialization build-aux/Makefile.in | 1 + build-aux/meson.build | 5 + build-aux/syntax-check.mk | 42 +- libvirt.spec.in | 2 +- meson.build | 13 +- scripts/meson.build | 2 + scripts/rpcgen/main.py | 90 ++ scripts/rpcgen/meson.build | 16 + scripts/rpcgen/rpcgen/ast.py | 270 ++++++ scripts/rpcgen/rpcgen/generator.py | 509 ++++++++++++ scripts/rpcgen/rpcgen/lexer.py | 213 +++++ scripts/rpcgen/rpcgen/meson.build | 7 + scripts/rpcgen/rpcgen/parser.py | 497 +++++++++++ scripts/rpcgen/rpcgen/visitor.py | 156 ++++ scripts/rpcgen/tests/demo.c | 495 +++++++++++ scripts/rpcgen/tests/demo.h | 264 ++++++ scripts/rpcgen/tests/demo.x | 127 +++ scripts/rpcgen/tests/meson.build | 20 + scripts/rpcgen/tests/simple.x | 35 + scripts/rpcgen/tests/test_demo.c | 782 ++++++++++++++++++ scripts/rpcgen/tests/test_demo_enum.bin | Bin 0 -> 4 bytes .../tests/test_demo_enum_fixed_array.bin | Bin 0 -> 52 bytes .../tests/test_demo_enum_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_enum_pointer_set.bin | Bin 0 -> 8 bytes .../rpcgen/tests/test_demo_enum_scalar.bin | Bin 0 -> 4 bytes .../test_demo_enum_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_enum_variable_array_set.bin | Bin 0 -> 16 bytes .../tests/test_demo_int_fixed_array.bin | Bin 0 -> 12 bytes .../tests/test_demo_int_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_int_pointer_set.bin | Bin 0 -> 8 bytes scripts/rpcgen/tests/test_demo_int_scalar.bin | Bin 0 -> 4 bytes .../test_demo_int_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_int_variable_array_set.bin | Bin 0 -> 16 bytes .../tests/test_demo_opaque_fixed_array.bin | Bin 0 -> 12 bytes .../test_demo_opaque_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_opaque_variable_array_set.bin | Bin 0 -> 8 bytes .../test_demo_string_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_string_variable_array_set.bin | Bin 0 -> 12 bytes scripts/rpcgen/tests/test_demo_struct.bin | Bin 0 -> 8 bytes .../tests/test_demo_struct_fixed_array.bin | Bin 0 -> 136 bytes .../tests/test_demo_struct_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_struct_pointer_set.bin | Bin 0 -> 12 bytes .../rpcgen/tests/test_demo_struct_scalar.bin | 1 + .../test_demo_struct_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_struct_variable_array_set.bin | Bin 0 -> 28 bytes .../tests/test_demo_test_struct_all_types.bin | Bin 0 -> 1752 bytes scripts/rpcgen/tests/test_demo_union_case.bin | Bin 0 -> 8 bytes .../rpcgen/tests/test_demo_union_default.bin | Bin 0 -> 8 bytes .../tests/test_demo_union_fixed_array.bin | Bin 0 -> 168 bytes .../tests/test_demo_union_no_default_case.bin | Bin 0 -> 8 bytes .../tests/test_demo_union_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_union_pointer_set.bin | Bin 0 -> 12 bytes .../rpcgen/tests/test_demo_union_scalar.bin | Bin 0 -> 8 bytes .../test_demo_union_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_union_variable_array_set.bin | Bin 0 -> 28 bytes .../test_demo_union_void_default_case.bin | Bin 0 -> 8 bytes .../test_demo_union_void_default_default.bin | 1 + scripts/rpcgen/tests/test_generator.py | 60 ++ scripts/rpcgen/tests/test_lexer.py | 116 +++ scripts/rpcgen/tests/test_parser.py | 91 ++ src/admin/admin_remote.c | 50 +- src/admin/meson.build | 8 +- src/locking/meson.build | 8 +- src/logging/meson.build | 8 +- src/lxc/meson.build | 12 +- src/remote/meson.build | 8 +- src/remote/remote_driver.c | 754 ++++++----------- src/rpc/gendispatch.pl | 60 +- src/rpc/genprotocol.pl | 144 ---- src/rpc/meson.build | 9 +- src/rpc/virnetmessage.c | 704 ++++++++++++++++ src/rpc/virnetmessage.h | 88 ++ 72 files changed, 4897 insertions(+), 771 deletions(-) create mode 100755 scripts/rpcgen/main.py create mode 100644 scripts/rpcgen/meson.build create mode 100644 scripts/rpcgen/rpcgen/ast.py create mode 100644 scripts/rpcgen/rpcgen/generator.py create mode 100644 scripts/rpcgen/rpcgen/lexer.py create mode 100644 scripts/rpcgen/rpcgen/meson.build create mode 100644 scripts/rpcgen/rpcgen/parser.py create mode 100644 scripts/rpcgen/rpcgen/visitor.py create mode 100644 scripts/rpcgen/tests/demo.c create mode 100644 scripts/rpcgen/tests/demo.h create mode 100644 scripts/rpcgen/tests/demo.x create mode 100644 scripts/rpcgen/tests/meson.build create mode 100644 scripts/rpcgen/tests/simple.x create mode 100644 scripts/rpcgen/tests/test_demo.c create mode 100644 scripts/rpcgen/tests/test_demo_enum.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_opaque_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_opaque_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_opaque_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_string_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_string_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_test_struct_all_types.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_case.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_default.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_no_default_case.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_void_default_case.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_void_default_default.bin create mode 100644 scripts/rpcgen/tests/test_generator.py create mode 100644 scripts/rpcgen/tests/test_lexer.py create mode 100644 scripts/rpcgen/tests/test_parser.py delete mode 100755 src/rpc/genprotocol.pl -- 2.39.1

The current RPC code is post-processed to introduce an intermediate variable, rather than casting directly to char ** at time of use. This is said to be a workaround for type-puning warnings that the compiler emitted. Neither GCC or CLang emit any warnings for the code in question today, across any of the architectures we test in CI. Thus it is presumed that somewhere in the 15 years since the workaround was done, the compilers have got smarter and do the right thing. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/rpc/genprotocol.pl | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/rpc/genprotocol.pl b/src/rpc/genprotocol.pl index f567260588..079627964f 100755 --- a/src/rpc/genprotocol.pl +++ b/src/rpc/genprotocol.pl @@ -92,29 +92,6 @@ while (<RPCGEN>) { @uses = grep /[^.>]\bi\b/, @function; @function = grep !/[^.>]\bi\b/, @function if @uses == 1; - # (char **)&objp->... gives: - # warning: dereferencing type-punned pointer will break - # strict-aliasing rules - # so rewrite it. - my %uses = (); - my $i = 0; - foreach (@function) { - $uses{$1} = $i++ if m/\(char \*\*\)\&(objp->[a-z_.]+_val)/i; - } - if (keys %uses >= 1) { - my $i = 1; - - foreach (sort(keys %uses)) { - $i = $uses{$_}; - unshift @function, - (" char **objp_cpp$i = (char **) (void *) &$_;\n"); - $i++; - } - @function = - map { s{\(char \*\*\)\&(objp->[a-z_.]+_val)} - {objp_cpp$uses{$1}}gi; $_ } @function; - } - # The code uses 'IXDR_PUT_{U_,}LONG' but it's wrong in two # ways: Firstly these functions are deprecated and don't # work on 64 bit platforms. Secondly the return value should -- 2.39.1

The flake8 check W503 does not want a line break before binary operator. This is contrary to the style that the 'black' formatting tool wants to use. Defer to 'black' as it is intended to be an opinionated formatting tool standardizing python code style, and thus not to be customized per project. The flake8 check E203 does not want whitespace before a ':'. This is, however, desirable when indexing array slices eg self.lookahead[skip : skip + 1] which is a format that 'black' produces. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- build-aux/syntax-check.mk | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/build-aux/syntax-check.mk b/build-aux/syntax-check.mk index 21f6b311ce..158f14e77e 100644 --- a/build-aux/syntax-check.mk +++ b/build-aux/syntax-check.mk @@ -568,15 +568,22 @@ sc_prohibit_python_without_env: # We're intentionally ignoring a few warnings # +# E302: whitespace before ':'. This is something that is +# desirable when indexing array slices and is used by the +# 'black' formatting tool +# # E501: Force breaking lines at < 80 characters results in # some really unnatural code formatting which harms # readability. # +# W503: line break before binary operator, because this +# is contrary to what 'black' formatting tool wants +# # W504: Knuth code style requires the operators "or" and "and" etc # to be at the start of line in a multi-line conditional. # This the opposite to what is normal libvirt practice. # -FLAKE8_IGNORE = E501,W504 +FLAKE8_IGNORE = E203,E501,W503,W504 sc_flake8: @if [ -n "$(FLAKE8)" ]; then \ -- 2.39.1

The 'black' tool is intended to be an opinionated formatting tool for python code. It is complementary to flake8 which validates coding bad practices, but (mostly) ignores code layout issues. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- build-aux/Makefile.in | 1 + build-aux/meson.build | 5 +++++ build-aux/syntax-check.mk | 18 ++++++++++++++++++ meson.build | 1 + 4 files changed, 25 insertions(+) diff --git a/build-aux/Makefile.in b/build-aux/Makefile.in index 7ee4680847..db44ee36a4 100644 --- a/build-aux/Makefile.in +++ b/build-aux/Makefile.in @@ -3,6 +3,7 @@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ FLAKE8 = @flake8_path@ +BLACK = @black_path@ RUNUTF8 = @runutf8@ PYTHON = @PYTHON3@ GREP = @GREP@ diff --git a/build-aux/meson.build b/build-aux/meson.build index 16d085505d..0330f2940c 100644 --- a/build-aux/meson.build +++ b/build-aux/meson.build @@ -2,6 +2,10 @@ flake8_path = '' if flake8_prog.found() flake8_path = flake8_prog.full_path() endif +black_path = '' +if black_prog.found() + black_path = black_prog.full_path() +endif if host_machine.system() == 'freebsd' or host_machine.system() == 'darwin' make_prog = find_program('gmake') @@ -32,6 +36,7 @@ syntax_check_conf = configuration_data({ 'top_srcdir': meson.project_source_root(), 'top_builddir': meson.project_build_root(), 'flake8_path': flake8_path, + 'black_path': black_path, 'runutf8': ' '.join(runutf8), 'PYTHON3': python3_prog.full_path(), 'GREP': grep_prog.full_path(), diff --git a/build-aux/syntax-check.mk b/build-aux/syntax-check.mk index 158f14e77e..6d82a4301a 100644 --- a/build-aux/syntax-check.mk +++ b/build-aux/syntax-check.mk @@ -595,6 +595,16 @@ sc_flake8: echo 'skipping test $@: flake8 not installed' 1>&2; \ fi +sc_black: + if [ -n "$(BLACK)" ]; then \ + DOT_PY=$$($(VC_LIST_EXCEPT) | $(GREP) '\.py$$'); \ + BANG_PY=$$($(VC_LIST_EXCEPT) | xargs grep -l '^#!/usr/bin/env python3$$'); \ + ALL_PY=$$(printf "%s\n%s" "$$DOT_PY" "$$BANG_PY" | sort -u); \ + echo "$$ALL_PY" | xargs $(BLACK) --check; \ + else \ + echo 'skipping test $@: black not installed' 1>&2; \ + fi + # mymain() in test files should use return, not exit, for nicer output sc_prohibit_exit_in_tests: @prohibit='\<exit *\(' \ @@ -1303,6 +1313,11 @@ syntax-check: sc_spacing-check \ echo "* flake8 not installed, sc_flake8 has been skipped *" >&2; \ echo "*****************************************************" >&2; \ fi + if [ -z "$(BLACK)" ]; then \ + echo "*****************************************************" >&2; \ + echo "* black not installed, sc_black has been skipped *" >&2; \ + echo "*****************************************************" >&2; \ + fi endif # Don't include duplicate header in the source (either *.c or *.h) @@ -1479,6 +1494,9 @@ exclude_file_name_regexp--sc_prohibit_select = \ ^build-aux/syntax-check\.mk|src/util/vireventglibwatch\.c|tests/meson\.build$$ +exclude_file_name_regexp--sc_black = \ + ^tools/|src/|tests/|ci/|run\.in|scripts/[^/]*\.py + ## -------------- ## ## Implementation ## ## -------------- ## diff --git a/meson.build b/meson.build index 319ed790f9..f63fed8cb5 100644 --- a/meson.build +++ b/meson.build @@ -769,6 +769,7 @@ endforeach optional_programs = [ 'augparse', + 'black', 'dmidecode', 'ebtables', 'flake8', -- 2.39.1

On Wed, Mar 08, 2023 at 11:39:00AM -0500, Daniel P. Berrangé wrote:
The 'black' tool is intended to be an opinionated formatting tool for python code. It is complementary to flake8 which validates coding bad practices, but (mostly) ignores code layout issues.
To expand on this, as you can see from the exclude file regex, in this series I've *not* applied 'black' to any of the existing python code. I've merely used it to ensure the newly written python introduced by this series has sane formatting. I've found it very refreshing to write this python code without having to worry about manually getting format "right", so even applying it only to this new code was worthwhile IMHO. I think it likely worth applying it to the existing python code in libvirt too, but I've not made any effort to do so yet and probably won't submit a series myself in the near future.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- build-aux/Makefile.in | 1 + build-aux/meson.build | 5 +++++ build-aux/syntax-check.mk | 18 ++++++++++++++++++ meson.build | 1 + 4 files changed, 25 insertions(+)
diff --git a/build-aux/Makefile.in b/build-aux/Makefile.in index 7ee4680847..db44ee36a4 100644 --- a/build-aux/Makefile.in +++ b/build-aux/Makefile.in @@ -3,6 +3,7 @@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ FLAKE8 = @flake8_path@ +BLACK = @black_path@ RUNUTF8 = @runutf8@ PYTHON = @PYTHON3@ GREP = @GREP@ diff --git a/build-aux/meson.build b/build-aux/meson.build index 16d085505d..0330f2940c 100644 --- a/build-aux/meson.build +++ b/build-aux/meson.build @@ -2,6 +2,10 @@ flake8_path = '' if flake8_prog.found() flake8_path = flake8_prog.full_path() endif +black_path = '' +if black_prog.found() + black_path = black_prog.full_path() +endif
if host_machine.system() == 'freebsd' or host_machine.system() == 'darwin' make_prog = find_program('gmake') @@ -32,6 +36,7 @@ syntax_check_conf = configuration_data({ 'top_srcdir': meson.project_source_root(), 'top_builddir': meson.project_build_root(), 'flake8_path': flake8_path, + 'black_path': black_path, 'runutf8': ' '.join(runutf8), 'PYTHON3': python3_prog.full_path(), 'GREP': grep_prog.full_path(), diff --git a/build-aux/syntax-check.mk b/build-aux/syntax-check.mk index 158f14e77e..6d82a4301a 100644 --- a/build-aux/syntax-check.mk +++ b/build-aux/syntax-check.mk @@ -595,6 +595,16 @@ sc_flake8: echo 'skipping test $@: flake8 not installed' 1>&2; \ fi
+sc_black: + if [ -n "$(BLACK)" ]; then \ + DOT_PY=$$($(VC_LIST_EXCEPT) | $(GREP) '\.py$$'); \ + BANG_PY=$$($(VC_LIST_EXCEPT) | xargs grep -l '^#!/usr/bin/env python3$$'); \ + ALL_PY=$$(printf "%s\n%s" "$$DOT_PY" "$$BANG_PY" | sort -u); \ + echo "$$ALL_PY" | xargs $(BLACK) --check; \ + else \ + echo 'skipping test $@: black not installed' 1>&2; \ + fi + # mymain() in test files should use return, not exit, for nicer output sc_prohibit_exit_in_tests: @prohibit='\<exit *\(' \ @@ -1303,6 +1313,11 @@ syntax-check: sc_spacing-check \ echo "* flake8 not installed, sc_flake8 has been skipped *" >&2; \ echo "*****************************************************" >&2; \ fi + if [ -z "$(BLACK)" ]; then \ + echo "*****************************************************" >&2; \ + echo "* black not installed, sc_black has been skipped *" >&2; \ + echo "*****************************************************" >&2; \ + fi endif
# Don't include duplicate header in the source (either *.c or *.h) @@ -1479,6 +1494,9 @@ exclude_file_name_regexp--sc_prohibit_select = \ ^build-aux/syntax-check\.mk|src/util/vireventglibwatch\.c|tests/meson\.build$$
+exclude_file_name_regexp--sc_black = \ + ^tools/|src/|tests/|ci/|run\.in|scripts/[^/]*\.py + ## -------------- ## ## Implementation ## ## -------------- ## diff --git a/meson.build b/meson.build index 319ed790f9..f63fed8cb5 100644 --- a/meson.build +++ b/meson.build @@ -769,6 +769,7 @@ endforeach
optional_programs = [ 'augparse', + 'black', 'dmidecode', 'ebtables', 'flake8', -- 2.39.1
With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

On 3/8/23 17:39, Daniel P. Berrangé wrote:
The 'black' tool is intended to be an opinionated formatting tool for python code. It is complementary to flake8 which validates coding bad practices, but (mostly) ignores code layout issues.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- build-aux/Makefile.in | 1 + build-aux/meson.build | 5 +++++ build-aux/syntax-check.mk | 18 ++++++++++++++++++ meson.build | 1 + 4 files changed, 25 insertions(+)
diff --git a/build-aux/Makefile.in b/build-aux/Makefile.in index 7ee4680847..db44ee36a4 100644 --- a/build-aux/Makefile.in +++ b/build-aux/Makefile.in @@ -3,6 +3,7 @@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ FLAKE8 = @flake8_path@ +BLACK = @black_path@ RUNUTF8 = @runutf8@ PYTHON = @PYTHON3@ GREP = @GREP@ diff --git a/build-aux/meson.build b/build-aux/meson.build index 16d085505d..0330f2940c 100644 --- a/build-aux/meson.build +++ b/build-aux/meson.build @@ -2,6 +2,10 @@ flake8_path = '' if flake8_prog.found() flake8_path = flake8_prog.full_path() endif +black_path = '' +if black_prog.found() + black_path = black_prog.full_path() +endif
if host_machine.system() == 'freebsd' or host_machine.system() == 'darwin' make_prog = find_program('gmake') @@ -32,6 +36,7 @@ syntax_check_conf = configuration_data({ 'top_srcdir': meson.project_source_root(), 'top_builddir': meson.project_build_root(), 'flake8_path': flake8_path, + 'black_path': black_path, 'runutf8': ' '.join(runutf8), 'PYTHON3': python3_prog.full_path(), 'GREP': grep_prog.full_path(), diff --git a/build-aux/syntax-check.mk b/build-aux/syntax-check.mk index 158f14e77e..6d82a4301a 100644 --- a/build-aux/syntax-check.mk +++ b/build-aux/syntax-check.mk @@ -595,6 +595,16 @@ sc_flake8: echo 'skipping test $@: flake8 not installed' 1>&2; \ fi
+sc_black: + if [ -n "$(BLACK)" ]; then \ + DOT_PY=$$($(VC_LIST_EXCEPT) | $(GREP) '\.py$$'); \ + BANG_PY=$$($(VC_LIST_EXCEPT) | xargs grep -l '^#!/usr/bin/env python3$$'); \ + ALL_PY=$$(printf "%s\n%s" "$$DOT_PY" "$$BANG_PY" | sort -u); \ + echo "$$ALL_PY" | xargs $(BLACK) --check; \
At this point, there's no file passed to $(BLACK) (because of exclude_file_... below) and thus it fails. It starts working after next patch when new python scripts are introduced. Nevertheless, it may still be worth running this as: echo "$$ALL_PY" | xargs --no-run-if-empty -- $(BLACK) --check; (the same could be done to flake8 from which you copied these lines)
+ else \ + echo 'skipping test $@: black not installed' 1>&2; \ + fi + # mymain() in test files should use return, not exit, for nicer output sc_prohibit_exit_in_tests: @prohibit='\<exit *\(' \ @@ -1303,6 +1313,11 @@ syntax-check: sc_spacing-check \ echo "* flake8 not installed, sc_flake8 has been skipped *" >&2; \ echo "*****************************************************" >&2; \ fi + if [ -z "$(BLACK)" ]; then \ + echo "*****************************************************" >&2; \ + echo "* black not installed, sc_black has been skipped *" >&2; \ + echo "*****************************************************" >&2; \ + fi endif
# Don't include duplicate header in the source (either *.c or *.h) @@ -1479,6 +1494,9 @@ exclude_file_name_regexp--sc_prohibit_select = \ ^build-aux/syntax-check\.mk|src/util/vireventglibwatch\.c|tests/meson\.build$$
+exclude_file_name_regexp--sc_black = \ + ^tools/|src/|tests/|ci/|run\.in|scripts/[^/]*\.py +
Michal

This adds a lexer capable of handling the XDR protocol files. The lexical rquirements are detailed in https://www.rfc-editor.org/rfc/rfc4506#section-6.2 pytest is introduced as a build dependancy for testing python code. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- libvirt.spec.in | 1 + meson.build | 1 + scripts/meson.build | 2 + scripts/rpcgen/meson.build | 11 ++ scripts/rpcgen/rpcgen/lexer.py | 213 +++++++++++++++++++++++++++++ scripts/rpcgen/tests/meson.build | 3 + scripts/rpcgen/tests/simple.x | 35 +++++ scripts/rpcgen/tests/test_lexer.py | 116 ++++++++++++++++ 8 files changed, 382 insertions(+) create mode 100644 scripts/rpcgen/meson.build create mode 100644 scripts/rpcgen/rpcgen/lexer.py create mode 100644 scripts/rpcgen/tests/meson.build create mode 100644 scripts/rpcgen/tests/simple.x create mode 100644 scripts/rpcgen/tests/test_lexer.py diff --git a/libvirt.spec.in b/libvirt.spec.in index e62534c31d..84d2f1c65a 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -274,6 +274,7 @@ BuildRequires: ninja-build BuildRequires: git BuildRequires: perl-interpreter BuildRequires: python3 +BuildRequires: python3-pytest %if %{with_libxl} BuildRequires: xen-devel %endif diff --git a/meson.build b/meson.build index f63fed8cb5..9f660c7604 100644 --- a/meson.build +++ b/meson.build @@ -783,6 +783,7 @@ optional_programs = [ 'ovs-vsctl', 'passt', 'pdwtags', + 'pytest', 'rmmod', 'scrub', 'tc', diff --git a/scripts/meson.build b/scripts/meson.build index 05b71184f1..b91a482d09 100644 --- a/scripts/meson.build +++ b/scripts/meson.build @@ -36,3 +36,5 @@ foreach name : scripts sname = name.split('.')[0].underscorify() set_variable('@0@_prog'.format(sname), find_program(name)) endforeach + +subdir('rpcgen') diff --git a/scripts/rpcgen/meson.build b/scripts/rpcgen/meson.build new file mode 100644 index 0000000000..52526bf812 --- /dev/null +++ b/scripts/rpcgen/meson.build @@ -0,0 +1,11 @@ +if pytest_prog.found() + subdir('tests') + + test( + 'rpcgen-pytest', + python3_prog, + args: [ '-mpytest' ] + rpcgen_tests, + env: runutf8, + workdir: meson.current_source_dir(), + ) +endif diff --git a/scripts/rpcgen/rpcgen/lexer.py b/scripts/rpcgen/rpcgen/lexer.py new file mode 100644 index 0000000000..989c2ae216 --- /dev/null +++ b/scripts/rpcgen/rpcgen/lexer.py @@ -0,0 +1,213 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +import abc + + +class XDRReader: + def __init__(self, fp): + self.fp = fp + self.lookahead = "" + self.lookbehind = "" + self.line = 1 + self.column = 0 + + def _read(self): + if len(self.lookahead) > 0: + c = self.lookahead[0:1] + self.lookahead = self.lookahead[1:] + return c + return self.fp.read(1) + + def peek(self, skip=0): + need = 1 + skip + if len(self.lookahead) < need: + self.lookahead = self.lookahead + self.fp.read(need - len(self.lookahead)) + if len(self.lookahead) < need: + return None + + return self.lookahead[skip : skip + 1] + + def last(self, skip=0): + if (skip + 1) > len(self.lookbehind): + return None + return self.lookbehind[skip] + + def next(self): + c = self._read() + line = self.line + column = self.column + if c == "\n": + self.line = self.line + 1 + self.column = 0 + else: + self.column = self.column + 1 + self.lookbehind = c + self.lookbehind + if len(self.lookbehind) > 2: + self.lookbehind = self.lookbehind[0:2] + return c, line, column + + +class XDRToken(abc.ABC): + def __init__(self, line, column, value): + self.line = line + self.column = column + self.value = value + + def __eq__(self, other): + return ( + type(self) == type(other) + and self.line == other.line + and self.column == other.column + and self.value == other.value + ) + + @classmethod + @abc.abstractmethod + def start(cls, reader): + pass + + @classmethod + @abc.abstractmethod + def end(cls, reader): + pass + + @classmethod + def consume(cls, reader): + c, line, col = reader.next() + buf = c + while True: + if cls.end(reader): + break + c, _, _ = reader.next() + buf = buf + c + return cls(line, col, buf) + + def __repr__(self): + return "%s{line=%d,col=%d,value={{{%s}}}}" % ( + self.__class__.__name__, + self.line, + self.column, + self.value, + ) + + +class XDRTokenComment(XDRToken): + @classmethod + def start(cls, reader): + return reader.peek() == "/" and reader.peek(skip=1) == "*" + + @classmethod + def end(cls, reader): + c1 = reader.last(skip=1) + c2 = reader.last() + if c1 == "*" and c2 == "/": + return True + + if reader.peek() is None: + raise Exception( + "EOF before closing comment starting at %d:%d" + % (reader.line, reader.column) + ) + + +class XDRTokenIdentifier(XDRToken): + @classmethod + def start(cls, reader): + c = reader.peek() + return c.isalpha() + + @classmethod + def end(cls, reader): + c = reader.peek() + if c is None: + return True + return not c.isalnum() and c != "_" + + +class XDRTokenPunctuation(XDRToken): + @classmethod + def start(cls, reader): + c = reader.peek() + return c in [";", "=", "{", "}", ",", "[", "]", "<", ">", "*", "(", ")", ":"] + + @classmethod + def end(cls, reader): + return True + + +class XDRTokenConstant(XDRToken): + @classmethod + def start(cls, reader): + c1 = reader.peek() + c2 = reader.peek(skip=1) + return c1.isdecimal() or (c1 == "-" and c2 is not None and c2.isdecimal()) + + @classmethod + def end(cls, reader): + c = reader.peek() + return ( + not c.isdecimal() + and not c == "." + and not c.lower() in ["x", "a", "b", "c", "d", "e", "f"] + ) + + +class XDRTokenCEscape(XDRToken): + @classmethod + def start(cls, reader): + return reader.column == 0 and reader.peek() == "%" + + @classmethod + def end(cls, reader): + return reader.peek() == "\n" + + +class XDRTokenSpace(XDRToken): + @classmethod + def start(cls, reader): + return reader.peek().isspace() + + @classmethod + def end(cls, reader): + c = reader.peek() + return c is None or not c.isspace() + + +class XDRLexer: + def __init__(self, fp): + self.reader = XDRReader(fp) + self.lookahead = [] + + def _token(self): + tokenTypes = [ + XDRTokenComment, + XDRTokenIdentifier, + XDRTokenCEscape, + XDRTokenPunctuation, + XDRTokenConstant, + XDRTokenSpace, + ] + while True: + if self.reader.peek() is None: + return None + + for tokenType in tokenTypes: + if tokenType.start(self.reader): + ret = tokenType.consume(self.reader) + if type(ret) not in [XDRTokenSpace, XDRTokenComment]: + return ret + + def next(self): + if len(self.lookahead) > 0: + token = self.lookahead[0] + self.lookahead = self.lookahead[1:] + return token + return self._token() + + def peek(self): + if len(self.lookahead) == 0: + token = self._token() + if token is None: + return None + self.lookahead.append(token) + return self.lookahead[0] diff --git a/scripts/rpcgen/tests/meson.build b/scripts/rpcgen/tests/meson.build new file mode 100644 index 0000000000..9162412d31 --- /dev/null +++ b/scripts/rpcgen/tests/meson.build @@ -0,0 +1,3 @@ +rpcgen_tests = files([ + 'test_lexer.py', +]) diff --git a/scripts/rpcgen/tests/simple.x b/scripts/rpcgen/tests/simple.x new file mode 100644 index 0000000000..91a1f2d234 --- /dev/null +++ b/scripts/rpcgen/tests/simple.x @@ -0,0 +1,35 @@ +/* Example from https://www.rfc-editor.org/rfc/rfc4506#section-7 */ + +const MAXUSERNAME = 32; /* max length of a user name */ +const MAXFILELEN = 65535; /* max length of a file */ +const MAXNAMELEN = 255; /* max length of a file name */ + +/* + * Types of files: + */ +enum filekind { + TEXT = 0, /* ascii data */ + DATA = 1, /* raw data */ + EXEC = 2 /* executable */ +}; + +/* + * File information, per kind of file: + */ +union filetype switch (filekind kind) { +case TEXT: + void; /* no extra information */ +case DATA: + string creator<MAXNAMELEN>; /* data creator */ +case EXEC: + string interpretor<MAXNAMELEN>; /* program interpretor */ +}; +/* + * A complete file: + */ +struct file { + string filename<MAXNAMELEN>; /* name of file */ + filetype type; /* info about file */ + string owner<MAXUSERNAME>; /* owner of file */ + opaque data<MAXFILELEN>; /* file data */ +}; diff --git a/scripts/rpcgen/tests/test_lexer.py b/scripts/rpcgen/tests/test_lexer.py new file mode 100644 index 0000000000..7cba98057f --- /dev/null +++ b/scripts/rpcgen/tests/test_lexer.py @@ -0,0 +1,116 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +from pathlib import Path + +from rpcgen.lexer import ( + XDRLexer, + XDRTokenIdentifier, + XDRTokenPunctuation, + XDRTokenConstant, +) + + +def test_lexer(): + p = Path(Path(__file__).parent, "simple.x") + with p.open("r") as fp: + lexer = XDRLexer(fp) + + tokens = [] + while True: + tok = lexer.next() + if tok is None: + break + tokens.append(tok) + + assert tokens == [ + XDRTokenIdentifier(line=3, column=0, value="const"), + XDRTokenIdentifier(line=3, column=6, value="MAXUSERNAME"), + XDRTokenPunctuation(line=3, column=18, value="="), + XDRTokenConstant(line=3, column=20, value="32"), + XDRTokenPunctuation(line=3, column=22, value=";"), + XDRTokenIdentifier(line=4, column=0, value="const"), + XDRTokenIdentifier(line=4, column=6, value="MAXFILELEN"), + XDRTokenPunctuation(line=4, column=17, value="="), + XDRTokenConstant(line=4, column=19, value="65535"), + XDRTokenPunctuation(line=4, column=24, value=";"), + XDRTokenIdentifier(line=5, column=0, value="const"), + XDRTokenIdentifier(line=5, column=6, value="MAXNAMELEN"), + XDRTokenPunctuation(line=5, column=17, value="="), + XDRTokenConstant(line=5, column=19, value="255"), + XDRTokenPunctuation(line=5, column=22, value=";"), + XDRTokenIdentifier(line=10, column=0, value="enum"), + XDRTokenIdentifier(line=10, column=5, value="filekind"), + XDRTokenPunctuation(line=10, column=14, value="{"), + XDRTokenIdentifier(line=11, column=3, value="TEXT"), + XDRTokenPunctuation(line=11, column=8, value="="), + XDRTokenConstant(line=11, column=10, value="0"), + XDRTokenPunctuation(line=11, column=11, value=","), + XDRTokenIdentifier(line=12, column=3, value="DATA"), + XDRTokenPunctuation(line=12, column=8, value="="), + XDRTokenConstant(line=12, column=10, value="1"), + XDRTokenPunctuation(line=12, column=11, value=","), + XDRTokenIdentifier(line=13, column=3, value="EXEC"), + XDRTokenPunctuation(line=13, column=8, value="="), + XDRTokenConstant(line=13, column=10, value="2"), + XDRTokenPunctuation(line=14, column=0, value="}"), + XDRTokenPunctuation(line=14, column=1, value=";"), + XDRTokenIdentifier(line=19, column=0, value="union"), + XDRTokenIdentifier(line=19, column=6, value="filetype"), + XDRTokenIdentifier(line=19, column=15, value="switch"), + XDRTokenPunctuation(line=19, column=22, value="("), + XDRTokenIdentifier(line=19, column=23, value="filekind"), + XDRTokenIdentifier(line=19, column=32, value="kind"), + XDRTokenPunctuation(line=19, column=36, value=")"), + XDRTokenPunctuation(line=19, column=38, value="{"), + XDRTokenIdentifier(line=20, column=0, value="case"), + XDRTokenIdentifier(line=20, column=5, value="TEXT"), + XDRTokenPunctuation(line=20, column=9, value=":"), + XDRTokenIdentifier(line=21, column=3, value="void"), + XDRTokenPunctuation(line=21, column=7, value=";"), + XDRTokenIdentifier(line=22, column=0, value="case"), + XDRTokenIdentifier(line=22, column=5, value="DATA"), + XDRTokenPunctuation(line=22, column=9, value=":"), + XDRTokenIdentifier(line=23, column=3, value="string"), + XDRTokenIdentifier(line=23, column=10, value="creator"), + XDRTokenPunctuation(line=23, column=17, value="<"), + XDRTokenIdentifier(line=23, column=18, value="MAXNAMELEN"), + XDRTokenPunctuation(line=23, column=28, value=">"), + XDRTokenPunctuation(line=23, column=29, value=";"), + XDRTokenIdentifier(line=24, column=0, value="case"), + XDRTokenIdentifier(line=24, column=5, value="EXEC"), + XDRTokenPunctuation(line=24, column=9, value=":"), + XDRTokenIdentifier(line=25, column=3, value="string"), + XDRTokenIdentifier(line=25, column=10, value="interpretor"), + XDRTokenPunctuation(line=25, column=21, value="<"), + XDRTokenIdentifier(line=25, column=22, value="MAXNAMELEN"), + XDRTokenPunctuation(line=25, column=32, value=">"), + XDRTokenPunctuation(line=25, column=33, value=";"), + XDRTokenPunctuation(line=26, column=0, value="}"), + XDRTokenPunctuation(line=26, column=1, value=";"), + XDRTokenIdentifier(line=30, column=0, value="struct"), + XDRTokenIdentifier(line=30, column=7, value="file"), + XDRTokenPunctuation(line=30, column=12, value="{"), + XDRTokenIdentifier(line=31, column=3, value="string"), + XDRTokenIdentifier(line=31, column=10, value="filename"), + XDRTokenPunctuation(line=31, column=18, value="<"), + XDRTokenIdentifier(line=31, column=19, value="MAXNAMELEN"), + XDRTokenPunctuation(line=31, column=29, value=">"), + XDRTokenPunctuation(line=31, column=30, value=";"), + XDRTokenIdentifier(line=32, column=3, value="filetype"), + XDRTokenIdentifier(line=32, column=12, value="type"), + XDRTokenPunctuation(line=32, column=16, value=";"), + XDRTokenIdentifier(line=33, column=3, value="string"), + XDRTokenIdentifier(line=33, column=10, value="owner"), + XDRTokenPunctuation(line=33, column=15, value="<"), + XDRTokenIdentifier(line=33, column=16, value="MAXUSERNAME"), + XDRTokenPunctuation(line=33, column=27, value=">"), + XDRTokenPunctuation(line=33, column=28, value=";"), + XDRTokenIdentifier(line=34, column=3, value="opaque"), + XDRTokenIdentifier(line=34, column=10, value="data"), + XDRTokenPunctuation(line=34, column=14, value="<"), + XDRTokenIdentifier(line=34, column=15, value="MAXFILELEN"), + XDRTokenPunctuation(line=34, column=25, value=">"), + XDRTokenPunctuation(line=34, column=26, value=";"), + XDRTokenPunctuation(line=35, column=0, value="}"), + XDRTokenPunctuation(line=35, column=1, value=";"), + ] -- 2.39.1

This introduces classes needed to form an abstract syntax tree representing the XDR protocol language. The syntax requirements are detailed in https://www.rfc-editor.org/rfc/rfc4506#section-6.3 Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- scripts/rpcgen/rpcgen/ast.py | 270 +++++++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 scripts/rpcgen/rpcgen/ast.py diff --git a/scripts/rpcgen/rpcgen/ast.py b/scripts/rpcgen/rpcgen/ast.py new file mode 100644 index 0000000000..3e3e089713 --- /dev/null +++ b/scripts/rpcgen/rpcgen/ast.py @@ -0,0 +1,270 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +import abc + + +class XDRSpecification: + def __init__(self): + self.definitions = [] + + def __repr__(self): + return "\n".join([repr(a) for a in self.definitions]) + + +class XDRDefinition(abc.ABC): + pass + + +class XDRDefinitionConstant(XDRDefinition): + def __init__(self, name, value): + self.name = name + self.value = value + + def __repr__(self): + return "const:{name=%s,value=%s}" % (self.name, self.value) + + +class XDRDefinitionTypedef(XDRDefinition): + def __init__(self, decl): + self.decl = decl + + def __repr__(self): + return "typedef:{decl=%s}" % (self.decl) + + +class XDRDefinitionEnum(XDRDefinition): + def __init__(self, name, body): + self.name = name + self.body = body + + def __repr__(self): + return "enum:{name=%s,body=%s}" % (self.name, self.body) + + +class XDRDefinitionStruct(XDRDefinition): + def __init__(self, name, body): + self.name = name + self.body = body + + def __repr__(self): + return "struct:{name=%s,body=%s}" % (self.name, self.body) + + +class XDRDefinitionUnion(XDRDefinition): + def __init__(self, name, body): + self.name = name + self.body = body + + def __repr__(self): + return "union:{name=%s,body=%s}" % (self.name, self.body) + + +class XDRDefinitionCEscape(XDRDefinition): + def __init__(self, code): + self.code = code + + def __repr__(self): + return "c-escape:{code=%s}" % (self.code) + + +class XDRDeclaration(abc.ABC): + def __init__(self, typ, identifier): + self.typ = typ + self.identifier = identifier + + +class XDRDeclarationScalar(XDRDeclaration): + def __repr__(self): + return "scalar:{type=%s,identifier=%s}" % (self.typ, self.identifier) + + +class XDRDeclarationPointer(XDRDeclaration): + def __repr__(self): + return "pointer:{type=%s,identifier=%s}" % (self.typ, self.identifier) + + +class XDRDeclarationFixedArray(XDRDeclaration): + def __init__(self, typ, identifier, length): + super().__init__(typ, identifier) + self.length = length + + def __repr__(self): + return "fixed-array:{type=%s,identifier=%s,length=%s}" % ( + self.typ, + self.identifier, + self.length, + ) + + +class XDRDeclarationVariableArray(XDRDeclaration): + def __init__(self, typ, identifier, maxlength): + super().__init__(typ, identifier) + self.maxlength = maxlength + + def __repr__(self): + return "variable-array:{type=%s,identifier=%s,maxlength=%s}" % ( + self.typ, + self.identifier, + self.maxlength, + ) + + +class XDRType(abc.ABC): + def __repr__(self): + name = self.__class__.__name__ + return name[7:].lower() + + def is_scalar(self): + return False + + +class XDRTypeScalar(XDRType): + def is_scalar(self): + return True + + +class XDRTypeVoid(XDRTypeScalar): + pass + + +class XDRTypeChar(XDRTypeScalar): + pass + + +class XDRTypeUnsignedChar(XDRTypeScalar): + pass + + +class XDRTypeShort(XDRTypeScalar): + pass + + +class XDRTypeUnsignedShort(XDRTypeScalar): + pass + + +class XDRTypeInt(XDRTypeScalar): + pass + + +class XDRTypeUnsignedInt(XDRTypeScalar): + pass + + +class XDRTypeHyper(XDRTypeScalar): + pass + + +class XDRTypeUnsignedHyper(XDRTypeScalar): + pass + + +class XDRTypeFloat(XDRTypeScalar): + pass + + +class XDRTypeDouble(XDRTypeScalar): + pass + + +class XDRTypeBool(XDRTypeScalar): + pass + + +class XDRTypeOpaque(XDRType): + pass + + +class XDRTypeString(XDRType): + pass + + +class XDRTypeCustom(XDRType): + def __init__(self, identifier, definition): + self.identifier = identifier + self.definition = definition + + def is_scalar(self): + if type(self.definition) == XDRDefinitionEnum: + return True + if type(self.definition) == XDRDefinitionTypedef: + return self.definition.decl.typ.is_scalar() + return False + + def __repr__(self): + return "custom{identifier=%s,definition=%s}" % ( + self.identifier, + self.definition, + ) + + +class XDREnumValue: + def __init__(self, name, value): + self.name = name + self.value = value + + def __repr__(self): + return "%s=%s" % (self.name, self.value) + + +class XDREnumBody: + def __init__(self, values): + self.values = values + + def __repr__(self): + return "enum-body{values=[" + ",".join([str(a) for a in self.values]) + "]}" + + +class XDRTypeEnum(XDRTypeScalar): + def __init__(self, body): + self.body = body + + def __repr__(self): + return "enum{%s}" % self.body + + +class XDRStructBody: + def __init__(self, fields): + self.fields = fields + + def __repr__(self): + return "struct-body{fields=[" + ",".join([str(a) for a in self.fields]) + "]}" + + +class XDRTypeStruct(XDRType): + def __init__(self, body): + self.body = body + + def __repr__(self): + return "struct{%s}" % self.body + + +class XDRUnionCase: + def __init__(self, value, decl): + self.value = value + self.decl = decl + + def __repr__(self): + return "%s=%s" % (self.value, self.decl) + + +class XDRUnionBody: + def __init__(self, discriminator, cases, default): + self.discriminator = discriminator + self.cases = cases + self.default = default + + def __repr__(self): + return ( + "union-body{discriminator=%s,cases=[" + + ",".join([str(a) for a in self.cases]) + + "],default=%s}" + ) % (self.discriminator, self.default) + + +class XDRTypeUnion(XDRType): + def __init__(self, body): + self.body = body + + def __repr__(self): + return "union{%s}" % self.body -- 2.39.1

This adds a parser capable of handling the XDR protocol files. The parsing grammar requirements are detailed in https://www.rfc-editor.org/rfc/rfc4506#section-6.3 Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- scripts/rpcgen/rpcgen/parser.py | 497 ++++++++++++++++++++++++++++ scripts/rpcgen/tests/meson.build | 1 + scripts/rpcgen/tests/test_parser.py | 91 +++++ 3 files changed, 589 insertions(+) create mode 100644 scripts/rpcgen/rpcgen/parser.py create mode 100644 scripts/rpcgen/tests/test_parser.py diff --git a/scripts/rpcgen/rpcgen/parser.py b/scripts/rpcgen/rpcgen/parser.py new file mode 100644 index 0000000000..7efbe5468e --- /dev/null +++ b/scripts/rpcgen/rpcgen/parser.py @@ -0,0 +1,497 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +from .lexer import ( + XDRLexer, + XDRTokenPunctuation, + XDRTokenIdentifier, + XDRTokenCEscape, + XDRTokenConstant, +) +from .ast import ( + XDRSpecification, + XDRDefinitionConstant, + XDRDefinitionTypedef, + XDRDefinitionEnum, + XDRDefinitionStruct, + XDRDefinitionUnion, + XDRDefinitionCEscape, + XDRDeclarationScalar, + XDRDeclarationPointer, + XDRDeclarationFixedArray, + XDRDeclarationVariableArray, + XDRTypeVoid, + XDRTypeChar, + XDRTypeUnsignedChar, + XDRTypeShort, + XDRTypeUnsignedShort, + XDRTypeInt, + XDRTypeUnsignedInt, + XDRTypeHyper, + XDRTypeUnsignedHyper, + XDRTypeFloat, + XDRTypeDouble, + XDRTypeBool, + XDRTypeOpaque, + XDRTypeString, + XDRTypeCustom, + XDREnumValue, + XDREnumBody, + XDRTypeEnum, + XDRStructBody, + XDRTypeStruct, + XDRUnionCase, + XDRUnionBody, + XDRTypeUnion, +) + + +# We are parsing (approximately the following grammar +# from RFC 4506 #6.3: +# +# declaration: +# type-specifier identifier +# | type-specifier identifier "[" value "]" +# | type-specifier identifier "<" [ value ] ">" +# | "opaque" identifier "[" value "]" +# | "opaque" identifier "<" [ value ] ">" +# | "string" identifier "<" [ value ] ">" +# | type-specifier "*" identifier +# | "void" +# +# value: +# constant +# | identifier +# +# constant: +# decimal-constant | hexadecimal-constant | octal-constant +# +# type-specifier: +# [ "unsigned" ] "int" +# | [ "unsigned" ] "hyper" +# | "float" +# | "double" +# | "quadruple" /* We're skipping this one */ +# | "bool" +# | enum-type-spec +# | struct-type-spec +# | union-type-spec +# | identifier +# +# enum-type-spec: +# "enum" enum-body +# +# enum-body: +# "{" +# ( identifier "=" value ) +# ( "," identifier "=" value )* +# "}" +# +# struct-type-spec: +# "struct" struct-body +# +# struct-body: +# "{" +# ( declaration ";" ) +# ( declaration ";" )* +# "}" +# +# union-type-spec: +# "union" union-body +# +# union-body: +# "switch" "(" declaration ")" "{" +# case-spec +# case-spec * +# [ "default" ":" declaration ";" ] +# "}" +# +# case-spec: +# ( "case" value ":") +# ( "case" value ":") * +# declaration ";" +# +# constant-def: +# "const" identifier "=" constant ";" +# +# type-def: +# "typedef" declaration ";" +# | "enum" identifier enum-body ";" +# | "struct" identifier struct-body ";" +# | "union" identifier union-body ";" +# +# definition: +# type-def +# | constant-def +# +# specification: +# definition * +# +# Notable divergance: +# +# - In 'type-decl' we allow 'char' and 'short' +# in signed and unsigned variants +# +# - In 'definition' we allow '%...' as escape C code +# to passthrough to the header output +# +# - In 'enum-type-spec' we allow a bare enum name +# instead of enum body +# +# - In 'struct-type-spec' we allow a bare struct name +# instead of struct body +# +# - In 'union-type-spec' we allow a bare union name +# instead of union body +# +class XDRParser: + def __init__(self, fp): + self.lexer = XDRLexer(fp) + self.typedefs = {} + + def parse(self): + spec = XDRSpecification() + while True: + definition = self.parse_definition() + if definition is None: + break + spec.definitions.append(definition) + return spec + + def parse_definition(self): + token = self.lexer.next() + if token is None: + return None + + if type(token) == XDRTokenCEscape: + return XDRDefinitionCEscape(token.value[1:]) + + if type(token) != XDRTokenIdentifier: + raise Exception("Expected identifier, but got %s" % token) + + defs = { + "const": XDRDefinitionConstant, + "typedef": XDRDefinitionTypedef, + "enum": XDRDefinitionEnum, + "struct": XDRDefinitionStruct, + "union": XDRDefinitionUnion, + } + + if token.value not in defs: + raise Exception("Unexpected identifier %s" % token) + + funcname = "parse_definition_" + token.value + func = getattr(self, funcname) + assert func is not None + + definition = func() + + semi = self.lexer.next() + if type(semi) != XDRTokenPunctuation or semi.value != ";": + raise Exception("Expected ';', but got %s" % semi) + + return definition + + def parse_definition_const(self): + ident = self.lexer.next() + if type(ident) != XDRTokenIdentifier: + raise Exception("Expected identifier, but got %s" % ident) + + assign = self.lexer.next() + if type(assign) != XDRTokenPunctuation or assign.value != "=": + raise Exception("Expected '=', but got %s" % assign) + + const = self.lexer.next() + if type(const) not in [XDRTokenConstant, XDRTokenIdentifier]: + raise Exception("Expected constant, but got %s" % const) + + return XDRDefinitionConstant(ident.value, const.value) + + def parse_definition_typedef(self): + decl = self.parse_declaration() + if decl.identifier in self.typedefs: + raise Exception("Type '%s' already defined" % decl.identifier) + + definition = XDRDefinitionTypedef(decl) + self.typedefs[decl.identifier] = definition + return definition + + def parse_definition_enum(self): + name = self.lexer.next() + if type(name) != XDRTokenIdentifier: + raise Exception("Expected identifier, but got %s" % name) + + body = self.parse_enum_body() + + if name.value in self.typedefs: + raise Exception("Type '%s' already defined" % name.value) + + definition = XDRDefinitionEnum(name.value, body) + self.typedefs[name.value] = definition + return definition + + def parse_definition_struct(self): + name = self.lexer.next() + if type(name) != XDRTokenIdentifier: + raise Exception("Expected identifier, but got %s" % name) + + body = self.parse_struct_body() + + if name.value in self.typedefs: + raise Exception("Type '%s' already defined" % name.value) + + definition = XDRDefinitionStruct(name.value, body) + self.typedefs[name.value] = definition + return definition + + def parse_definition_union(self): + name = self.lexer.next() + if type(name) != XDRTokenIdentifier: + raise Exception("Expected identifier, but got %s" % name) + + body = self.parse_union_body() + + if name.value in self.typedefs: + raise Exception("Type '%s' already defined" % name.value) + + definition = XDRDefinitionUnion(name.value, body) + self.typedefs[name.value] = definition + return definition + + def parse_declaration(self): + typ = self.parse_type() + + if type(typ) == XDRTypeVoid: + return XDRDeclarationScalar(typ, None) + + ident = self.lexer.next() + + pointer = False + if type(ident) == XDRTokenPunctuation: + if ident.value != "*": + raise Exception("Expected '*' or identifer, but got %s" % ident) + if type(typ) == XDRTypeString or type(typ) == XDRTypeOpaque: + raise Exception("Pointer invalid for 'string' and 'opaque' types") + + pointer = True + ident = self.lexer.next() + + bracket = self.lexer.peek() + if type(bracket) == XDRTokenPunctuation: + if bracket.value == "[": + _ = self.lexer.next() + value = self.lexer.next() + if type(value) not in [XDRTokenConstant, XDRTokenIdentifier]: + raise Exception("Expected constant, but got %s" % value) + + close = self.lexer.next() + if type(close) != XDRTokenPunctuation or close.value != "]": + raise Exception("Expected ']', but got %s" % value) + + if type(typ) == XDRTypeString: + raise Exception("Fixed array invalid for 'string' type") + return XDRDeclarationFixedArray(typ, ident.value, value.value) + elif bracket.value == "<": + _ = self.lexer.next() + maybeValue = self.lexer.peek() + value = None + if type(maybeValue) in [XDRTokenConstant, XDRTokenIdentifier]: + value = self.lexer.next().value + + close = self.lexer.next() + if type(close) != XDRTokenPunctuation or close.value != ">": + raise Exception("Expected '>', but got %s" % close) + + return XDRDeclarationVariableArray(typ, ident.value, value) + + if pointer: + return XDRDeclarationPointer(typ, ident.value) + else: + return XDRDeclarationScalar(typ, ident.value) + + def parse_type(self): + typ = self.lexer.next() + if type(typ) != XDRTokenIdentifier: + raise Exception("Expected identifier, but got %s" % typ) + + if typ.value == "unsigned": + typ = self.lexer.peek() + if type(typ) != XDRTokenIdentifier: + raise Exception("Expected identifier, but got %s" % typ) + + if typ.value == "char": + _ = self.lexer.next() + return XDRTypeUnsignedChar() + elif typ.value == "short": + _ = self.lexer.next() + return XDRTypeUnsignedShort() + elif typ.value == "int": + _ = self.lexer.next() + return XDRTypeUnsignedInt() + elif typ.value == "hyper": + _ = self.lexer.next() + return XDRTypeUnsignedHyper() + else: + # Bare 'unsigned' isn't allowed by 'type-specifier' + # grammer in RFC 1014, but rpcgen allows it + return XDRTypeUnsignedInt() + + if typ.value == "void": + return XDRTypeVoid() + elif typ.value == "char": + return XDRTypeChar() + elif typ.value == "short": + return XDRTypeShort() + elif typ.value == "int": + return XDRTypeInt() + elif typ.value == "hyper": + return XDRTypeHyper() + elif typ.value == "float": + return XDRTypeFloat() + elif typ.value == "double": + return XDRTypeDouble() + elif typ.value == "bool": + return XDRTypeBool() + elif typ.value == "enum": + return self.parse_type_enum() + elif typ.value == "struct": + return self.parse_type_struct() + elif typ.value == "union": + return self.parse_type_union() + elif typ.value == "opaque": + return XDRTypeOpaque() + elif typ.value == "string": + return XDRTypeString() + else: + return XDRTypeCustom(typ.value, self.typedefs.get(typ.value, None)) + + def parse_enum_body(self): + body = self.lexer.next() + if type(body) != XDRTokenPunctuation or body.value != "{": + raise Exception("Expected '{', but got %s" % body) + + values = [] + while True: + ident = self.lexer.next() + if type(ident) != XDRTokenIdentifier: + raise Exception("Expected identifier, but got %s" % ident) + + equal = self.lexer.next() + if type(equal) != XDRTokenPunctuation or equal.value != "=": + raise Exception("Expected '=', but got %s" % ident) + + value = self.lexer.next() + if type(value) != XDRTokenConstant: + raise Exception("Expected constant, but got %s" % ident) + + separator = self.lexer.next() + if type(separator) != XDRTokenPunctuation and separator.value not in [ + "}", + ",", + ]: + raise Exception("Expected '}' or ',', but got %s" % separator) + + values.append(XDREnumValue(ident.value, value.value)) + + if separator.value == "}": + break + + return XDREnumBody(values) + + def parse_type_enum(self): + body = self.parse_enum_body() + return XDRTypeEnum(body) + + def parse_struct_body(self): + body = self.lexer.next() + if type(body) != XDRTokenPunctuation or body.value != "{": + raise Exception("Expected '{', but got %s" % body) + + fields = [] + while True: + field = self.parse_declaration() + fields.append(field) + + separator = self.lexer.next() + if type(separator) != XDRTokenPunctuation and separator.value != ";": + raise Exception("Expected ';', but got %s" % separator) + + end = self.lexer.peek() + if type(end) == XDRTokenPunctuation and end.value == "}": + break + + # discard the '}' we peeked at to end the loop + _ = self.lexer.next() + return XDRStructBody(fields) + + def parse_type_struct(self): + body = self.parse_struct_body() + return XDRTypeStruct(body) + + def parse_union_body(self): + ident = self.lexer.next() + if type(ident) != XDRTokenIdentifier or ident.value != "switch": + raise Exception("Expected 'switch', but got %s" % ident) + + bracket = self.lexer.next() + if type(bracket) != XDRTokenPunctuation or bracket.value != "(": + raise Exception("Expected '(', but got %s" % bracket) + + discriminator = self.parse_declaration() + + bracket = self.lexer.next() + if type(bracket) != XDRTokenPunctuation or bracket.value != ")": + raise Exception("Expected ')', but got %s" % bracket) + + bracket = self.lexer.next() + if type(bracket) != XDRTokenPunctuation or bracket.value != "{": + raise Exception("Expected '{', but got %s" % bracket) + + default = None + cases = [] + while True: + ident = self.lexer.next() + if type(ident) != XDRTokenIdentifier or ident.value not in [ + "default", + "case", + ]: + raise Exception("Expected 'default' or 'case', but got %s" % ident) + + value = None + if ident.value == "case": + value = self.lexer.next() + if type(value) not in [XDRTokenConstant, XDRTokenIdentifier]: + raise Exception("Expected constant, but got %s" % value) + + sep = self.lexer.next() + if type(sep) != XDRTokenPunctuation or sep.value != ":": + raise Exception("Expected ':', but got %s" % value) + + decl = self.parse_declaration() + + case = XDRUnionCase(value.value, decl) + cases.append(case) + else: + if default is not None: + raise Exception("Duplicate 'default' clause") + + sep = self.lexer.next() + if type(sep) != XDRTokenPunctuation or sep.value != ":": + raise Exception("Expected ':', but got %s" % value) + + default = self.parse_declaration() + + separator = self.lexer.next() + if type(separator) != XDRTokenPunctuation and separator.value != ";": + raise Exception("Expected ';', but got %s" % bracket) + + end = self.lexer.peek() + if type(end) == XDRTokenPunctuation and end.value == "}": + break + + # discard the '}' we peeked at to end the loop + _ = self.lexer.next() + return XDRUnionBody(discriminator, cases, default) + + def parse_type_union(self): + body = self.parse_union_body() + return XDRTypeUnion(body) diff --git a/scripts/rpcgen/tests/meson.build b/scripts/rpcgen/tests/meson.build index 9162412d31..4b1ea308ce 100644 --- a/scripts/rpcgen/tests/meson.build +++ b/scripts/rpcgen/tests/meson.build @@ -1,3 +1,4 @@ rpcgen_tests = files([ 'test_lexer.py', + 'test_parser.py', ]) diff --git a/scripts/rpcgen/tests/test_parser.py b/scripts/rpcgen/tests/test_parser.py new file mode 100644 index 0000000000..8527b8d6e2 --- /dev/null +++ b/scripts/rpcgen/tests/test_parser.py @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +from pathlib import Path + +from rpcgen.ast import ( + XDRSpecification, + XDRDefinitionConstant, + XDRDefinitionEnum, + XDRDefinitionUnion, + XDRDefinitionStruct, + XDRDeclarationScalar, + XDRDeclarationVariableArray, + XDREnumValue, + XDREnumBody, + XDRStructBody, + XDRUnionCase, + XDRUnionBody, + XDRTypeCustom, + XDRTypeVoid, + XDRTypeString, + XDRTypeOpaque, +) +from rpcgen.parser import XDRParser + + +def test_parser(): + p = Path(Path(__file__).parent, "simple.x") + with p.open("r") as fp: + parser = XDRParser(fp) + + got = parser.parse() + + enum = XDRDefinitionEnum( + "filekind", + XDREnumBody( + [ + XDREnumValue("TEXT", "0"), + XDREnumValue("DATA", "1"), + XDREnumValue("EXEC", "2"), + ], + ), + ) + + union = XDRDefinitionUnion( + "filetype", + XDRUnionBody( + XDRDeclarationScalar(XDRTypeCustom("filekind", enum), "kind"), + [ + XDRUnionCase("TEXT", XDRDeclarationScalar(XDRTypeVoid(), None)), + XDRUnionCase( + "DATA", + XDRDeclarationVariableArray( + XDRTypeString(), "creator", "MAXNAMELEN" + ), + ), + XDRUnionCase( + "EXEC", + XDRDeclarationVariableArray( + XDRTypeString(), "interpretor", "MAXNAMELEN" + ), + ), + ], + None, + ), + ) + + struct = XDRDefinitionStruct( + "file", + XDRStructBody( + [ + XDRDeclarationVariableArray(XDRTypeString(), "filename", "MAXNAMELEN"), + XDRDeclarationScalar(XDRTypeCustom("filetype", union), "type"), + XDRDeclarationVariableArray(XDRTypeString(), "owner", "MAXUSERNAME"), + XDRDeclarationVariableArray(XDRTypeOpaque(), "data", "MAXFILELEN"), + ] + ), + ) + + want = XDRSpecification() + want.definitions.extend( + [ + XDRDefinitionConstant("MAXUSERNAME", "32"), + XDRDefinitionConstant("MAXFILELEN", "65535"), + XDRDefinitionConstant("MAXNAMELEN", "255"), + enum, + union, + struct, + ] + ) + + assert str(got) == str(want) -- 2.39.1

The visitor API defines an interface for visiting each element in the XDR protocol spec abstract syntax tree. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- scripts/rpcgen/rpcgen/visitor.py | 156 +++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 scripts/rpcgen/rpcgen/visitor.py diff --git a/scripts/rpcgen/rpcgen/visitor.py b/scripts/rpcgen/rpcgen/visitor.py new file mode 100644 index 0000000000..e1b2d907c1 --- /dev/null +++ b/scripts/rpcgen/rpcgen/visitor.py @@ -0,0 +1,156 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +import abc + +from .ast import ( + XDRSpecification, + XDRDefinition, + XDRDeclaration, + XDRType, + XDREnumValue, + XDREnumBody, + XDRStructBody, + XDRUnionCase, + XDRUnionBody, +) + + +class XDRVisitor(abc.ABC): + def __init__(self, spec): + self.spec = spec + + def visit(self, indent="", context=""): + return self.visit_object(self.spec, indent="", context=context) + + def visit_object(self, obj, indent="", context=""): + if isinstance(obj, XDRSpecification): + funcname = "visit_specification" + elif isinstance(obj, XDRDefinition): + funcname = "visit_definition_" + type(obj).__name__[13:].lower() + elif isinstance(obj, XDRDeclaration): + funcname = "visit_declaration_" + type(obj).__name__[14:].lower() + elif isinstance(obj, XDRType): + funcname = "visit_type_" + type(obj).__name__[7:].lower() + elif isinstance(obj, XDREnumValue): + funcname = "visit_enum_value" + elif isinstance(obj, XDREnumBody): + funcname = "visit_enum_body" + elif isinstance(obj, XDRStructBody): + funcname = "visit_struct_body" + elif isinstance(obj, XDRUnionCase): + funcname = "visit_union_case" + elif isinstance(obj, XDRUnionBody): + funcname = "visit_union_body" + else: + raise Exception("Unhandled %s" % obj.__class__.__name__) + + func = getattr(self, funcname) + assert func is not None + return func(obj, indent, context) + + def visit_specification(self, obj, indent, context): + code = [] + for definition in self.spec.definitions: + defcode = self.visit_object(definition, indent, context) + if defcode is not None: + code.append(defcode) + return "\n".join(code) + + def visit_definition_cescape(self, obj, indent, context): + pass + + def visit_definition_constant(self, obj, indent, context): + pass + + def visit_definition_enum(self, obj, indent, context): + pass + + def visit_definition_struct(self, obj, indent, context): + pass + + def visit_definition_union(self, obj, indent, context): + pass + + def visit_definition_typedef(self, obj, indent, context): + pass + + def visit_declaration_scalar(self, obj, indent, context): + pass + + def visit_declaration_pointer(self, obj, indent, context): + pass + + def visit_declaration_fixedarray(self, obj, indent, context): + pass + + def visit_declaration_variablearray(self, obj, indent, context): + pass + + def visit_type_custom(self, obj, indent, context): + pass + + def visit_type_opaque(self, obj, indent, context): + pass + + def visit_type_string(self, obj, indent, context): + pass + + def visit_type_void(self, obj, indent, context): + pass + + def visit_type_char(self, obj, indent, context): + pass + + def visit_type_unsignedchar(self, obj, indent, context): + pass + + def visit_type_short(self, obj, indent, context): + pass + + def visit_type_unsignedshort(self, obj, indent, context): + pass + + def visit_type_int(self, obj, indent, context): + pass + + def visit_type_unsignedint(self, obj, indent, context): + pass + + def visit_type_hyper(self, obj, indent, context): + pass + + def visit_type_unsignedhyper(self, obj, indent, context): + pass + + def visit_type_bool(self, obj, indent, context): + pass + + def visit_type_float(self, obj, indent, context): + pass + + def visit_type_double(self, obj, indent, context): + pass + + def visit_type_enum(self, obj, indent, context): + pass + + def visit_type_struct(self, obj, indent, context): + pass + + def visit_type_union(self, obj, indent, context): + pass + + def visit_enum_value(self, obj, indent, context): + pass + + def visit_enum_body(self, obj, indent, context): + pass + + def visit_struct_body(self, obj, indent, context): + pass + + def visit_union_case(self, obj, indent, context): + pass + + def visit_union_body(self, obj, indent, context): + pass -- 2.39.1

This implements a C code generator that emits code that is (almost) identical to the classic 'rpcgen' program. The key differences are: - Skip inlining of calls for struct fields - Skip K&R style function prototypes in headers - Use int64_t instead of quad_t for OS portability - Saner whitespace / indentation The tests/demo.c and tests/demo.h files were created using the traditional 'rpcgen' program, and then editted to cut out the leading boilerplate, and the differences mentioned above. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- build-aux/syntax-check.mk | 4 +- scripts/rpcgen/rpcgen/generator.py | 467 +++++++++++++++++++++++++ scripts/rpcgen/tests/demo.c | 351 +++++++++++++++++++ scripts/rpcgen/tests/demo.h | 216 ++++++++++++ scripts/rpcgen/tests/demo.x | 128 +++++++ scripts/rpcgen/tests/meson.build | 1 + scripts/rpcgen/tests/test_generator.py | 55 +++ 7 files changed, 1221 insertions(+), 1 deletion(-) create mode 100644 scripts/rpcgen/rpcgen/generator.py create mode 100644 scripts/rpcgen/tests/demo.c create mode 100644 scripts/rpcgen/tests/demo.h create mode 100644 scripts/rpcgen/tests/demo.x create mode 100644 scripts/rpcgen/tests/test_generator.py diff --git a/build-aux/syntax-check.mk b/build-aux/syntax-check.mk index 6d82a4301a..375fad188b 100644 --- a/build-aux/syntax-check.mk +++ b/build-aux/syntax-check.mk @@ -1429,7 +1429,7 @@ exclude_file_name_regexp--sc_prohibit_xmlURI = ^src/util/viruri\.c$$ exclude_file_name_regexp--sc_prohibit_return_as_function = \.py$$ exclude_file_name_regexp--sc_require_config_h = \ - ^(examples/|tools/virsh-edit\.c$$|tests/virmockstathelpers.c) + ^(examples/c/.*/.*\.c|tools/virsh-edit\.c|tests/virmockstathelpers\.c|scripts/rpcgen/tests/demo\.c)$$ exclude_file_name_regexp--sc_require_config_h_first = \ ^(examples/|tools/virsh-edit\.c$$|tests/virmockstathelpers.c) @@ -1493,6 +1493,8 @@ exclude_file_name_regexp--sc_prohibit_strcmp = \ exclude_file_name_regexp--sc_prohibit_select = \ ^build-aux/syntax-check\.mk|src/util/vireventglibwatch\.c|tests/meson\.build$$ +exclude_file_name_regexp--sc_header-ifdef = \ + ^scripts/rpcgen/tests/demo\.[ch]$$ exclude_file_name_regexp--sc_black = \ ^tools/|src/|tests/|ci/|run\.in|scripts/[^/]*\.py diff --git a/scripts/rpcgen/rpcgen/generator.py b/scripts/rpcgen/rpcgen/generator.py new file mode 100644 index 0000000000..110cd12c5e --- /dev/null +++ b/scripts/rpcgen/rpcgen/generator.py @@ -0,0 +1,467 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +from .visitor import XDRVisitor +from .parser import ( + XDRTypeString, + XDRTypeVoid, + XDRTypeOpaque, + XDRTypeCustom, + XDRDefinitionTypedef, + XDRDeclarationFixedArray, + XDRDeclarationVariableArray, + XDRDeclarationPointer, +) + + +class XDRTypeDeclarationGenerator(XDRVisitor): + def visit_definition_cescape(self, obj, indent, context): + return obj.code + "\n" + + def visit_definition_constant(self, obj, indent, context): + return "#%sdefine %s %s\n" % (indent, obj.name, obj.value) + + def visit_definition_enum(self, obj, indent, context): + code = "%senum %s %s;\n" % ( + indent, + obj.name, + self.visit_object(obj.body, indent), + ) + "%stypedef enum %s %s;\n" % (indent, obj.name, obj.name) + return code + + def visit_definition_struct(self, obj, indent, context): + code = "%sstruct %s %s;\n" % ( + indent, + obj.name, + self.visit_object(obj.body, indent), + ) + "%stypedef struct %s %s;\n" % (indent, obj.name, obj.name) + return code + + def visit_definition_union(self, obj, indent, context): + code = "%sstruct %s %s;\n" % ( + indent, + obj.name, + self.visit_object(obj.body, indent, obj.name), + ) + "%stypedef struct %s %s;\n" % (indent, obj.name, obj.name) + return code + + def visit_definition_typedef(self, obj, indent, context): + return "%stypedef %s;\n" % (indent, self.visit_object(obj.decl, indent)) + + def visit_declaration_scalar(self, obj, indent, context): + return "%s %s" % (self.visit_object(obj.typ, indent), obj.identifier) + + def visit_declaration_pointer(self, obj, indent, context): + return "%s *%s" % (self.visit_object(obj.typ, indent), obj.identifier) + + def visit_declaration_fixedarray(self, obj, indent, context): + return "%s %s[%s]" % ( + self.visit_object(obj.typ, indent), + obj.identifier, + obj.length, + ) + + def visit_declaration_variablearray(self, obj, indent, context): + if type(obj.typ) == XDRTypeString: + return "%schar *%s" % (indent, obj.identifier) + else: + code = ( + "%sstruct {\n" % indent + + "%s u_int %s_len;\n" % (indent, obj.identifier) + + "%s %s *%s_val;\n" + % (indent, self.visit_object(obj.typ, ""), obj.identifier) + + "%s} %s" % (indent, obj.identifier) + ) + return code + + def visit_type_custom(self, obj, indent, context): + return "%s%s" % (indent, obj.identifier) + + def visit_type_opaque(self, obj, indent, context): + return "%schar" % indent + + def visit_type_string(self, obj, indent, context): + return "%sstring" % indent + + def visit_type_void(self, obj, indent, context): + return "%svoid" % indent + + def visit_type_char(self, obj, indent, context): + return "%schar" % indent + + def visit_type_unsignedchar(self, obj, indent, context): + return "%su_char" % indent + + def visit_type_short(self, obj, indent, context): + return "%sshort" % indent + + def visit_type_unsignedshort(self, obj, indent, context): + return "%su_short" % indent + + def visit_type_int(self, obj, indent, context): + return "%sint" % indent + + def visit_type_unsignedint(self, obj, indent, context): + return "%su_int" % indent + + def visit_type_hyper(self, obj, indent, context): + return "%sint64_t" % indent + + def visit_type_unsignedhyper(self, obj, indent, context): + return "%suint64_t" % indent + + def visit_type_bool(self, obj, indent, context): + return "%sbool_t" % indent + + def visit_type_float(self, obj, indent, context): + return "%sfloat" % indent + + def visit_type_double(self, obj, indent, context): + return "%sdouble" % indent + + def visit_type_enum(self, obj, indent, context): + return "%senum %s" % (indent, self.visit_object(obj.body.body, indent)) + + def visit_type_struct(self, obj, indent, context): + return "%sstruct %s" % (indent, self.visit_object(obj.body, indent)) + + def visit_type_union(self, obj, indent, context): + return "%sstruct %s" % (indent, self.visit_object(obj.body, indent)) + + def visit_enum_value(self, obj, indent, context): + return "%s%s = %s" % (indent, obj.name, obj.value) + + def visit_enum_body(self, obj, indent, context): + code = "{\n" + for value in obj.values: + code = code + self.visit_object(value, indent + " ") + ",\n" + code = code + "%s}" % indent + return code + + def visit_struct_body(self, obj, indent, context): + code = "{\n" + for value in obj.fields: + code = code + self.visit_object(value, indent + " ") + ";\n" + code = code + "%s}" % indent + return code + + def visit_union_case(self, obj, indent, context): + return self.visit_object(obj.decl, indent) + + def visit_union_body(self, obj, indent, context): + prefix = context + if prefix != "": + prefix = prefix + "_" + + code = ( + "%s{\n" % indent + + "%s %s;\n" % (indent, self.visit_object(obj.discriminator)) + + "%s union {\n" % indent + ) + for value in obj.cases: + if type(value.decl.typ) == XDRTypeVoid: + continue + code = code + self.visit_object(value, indent + " ") + ";\n" + if obj.default is not None and type(obj.default.typ) != XDRTypeVoid: + code = code + self.visit_object(obj.default, indent + " ") + ";\n" + code = code + "%s } %su;\n" % (indent, prefix) + "%s}" % indent + return code + + +class XDRMarshallDeclarationGenerator(XDRVisitor): + def visit_definition_enum(self, obj, indent, context): + return "%sextern bool_t xdr_%s(XDR *, %s*);\n" % (indent, obj.name, obj.name) + + def visit_definition_union(self, obj, indent, context): + return "%sextern bool_t xdr_%s(XDR *, %s*);\n" % (indent, obj.name, obj.name) + + def visit_definition_struct(self, obj, indent, context): + return "%sextern bool_t xdr_%s(XDR *, %s*);\n" % (indent, obj.name, obj.name) + + def visit_definition_typedef(self, obj, indent, context): + if isinstance(obj.decl, XDRDeclarationFixedArray): + return "%sextern bool_t xdr_%s(XDR *, %s);\n" % ( + indent, + obj.decl.identifier, + obj.decl.identifier, + ) + else: + return "%sextern bool_t xdr_%s(XDR *, %s*);\n" % ( + indent, + obj.decl.identifier, + obj.decl.identifier, + ) + + +class XDRMarshallImplementationGenerator(XDRVisitor): + def visit_definition_enum(self, obj, indent, context): + code = ( + "%sbool_t\n" % indent + + "%sxdr_%s(XDR *xdrs, %s *objp)\n" % (indent, obj.name, obj.name) + + "%s{\n" % indent + + "%s if (!xdr_enum(xdrs, (enum_t *)objp))\n" % indent + + "%s return FALSE;\n" % indent + + "%s return TRUE;\n" % indent + + "%s}\n" % indent + ) + return code + + def generate_type_call(self, decl, field, typename, embedded=False, indent=""): + if type(decl.typ) == XDRTypeVoid: + return "" + if type(decl) == XDRDeclarationFixedArray: + if type(decl.typ) == XDRTypeOpaque: + code = "%s if (!xdr_%s(xdrs, %s, %s))\n" % ( + indent, + self.visit_object(decl.typ, context="func"), + field, + decl.length, + ) + else: + code = "%s if (!xdr_vector(xdrs, (char *)%s, %s,\n" % ( + indent, + field, + decl.length, + ) + "%s sizeof(%s), (xdrproc_t)xdr_%s))\n" % ( + indent, + self.visit_object(decl.typ), + self.visit_object(decl.typ, context="func"), + ) + elif type(decl) == XDRDeclarationVariableArray: + fieldRef = "." + pointerStr = "" + if embedded: + pointerStr = "&" + else: + fieldRef = "->" + + if type(decl.typ) == XDRTypeString: + code = "%s if (!xdr_%s(xdrs, %s%s, %s))\n" % ( + indent, + self.visit_object(decl.typ, context="func"), + pointerStr, + field, + decl.maxlength, + ) + elif type(decl.typ) == XDRTypeOpaque: + code = "%s if (!xdr_bytes(xdrs, (char **)&%s%s%s_val, " % ( + indent, + field, + fieldRef, + typename, + ) + "(u_int *) &%s%s%s_len, %s))\n" % ( + field, + fieldRef, + typename, + decl.maxlength, + ) + else: + code = ( + "%s if (!xdr_array(xdrs, (char **)&%s%s%s_val, " + % (indent, field, fieldRef, typename) + + "(u_int *) &%s%s%s_len, %s,\n" + % (field, fieldRef, typename, decl.maxlength) + + "%s sizeof(%s), (xdrproc_t)xdr_%s))\n" + % ( + indent, + self.visit_object(decl.typ), + self.visit_object(decl.typ, context="func"), + ) + ) + elif type(decl) == XDRDeclarationPointer: + pointerStr = "" + if embedded: + pointerStr = "&" + + code = "%s if (!xdr_pointer(xdrs, (char **)%s%s, " % ( + indent, + pointerStr, + field, + ) + "sizeof(%s), (xdrproc_t)xdr_%s))\n" % ( + self.visit_object(decl.typ, context="func"), + self.visit_object(decl.typ, context="func"), + ) + else: + pointerStr = "" + isFixedArray = ( + type(decl.typ) == XDRTypeCustom + and type(decl.typ.definition) == XDRDefinitionTypedef + and type(decl.typ.definition.decl) == XDRDeclarationFixedArray + ) + + if embedded and not isFixedArray: + pointerStr = "&" + + code = "%s if (!xdr_%s(xdrs, %s%s))\n" % ( + indent, + self.visit_object(decl.typ, context="func"), + pointerStr, + field, + ) + + code = code + "%s return FALSE;\n" % indent + return code + + def visit_definition_union(self, obj, indent, context): + code = ( + "%sbool_t\n" % indent + + "%sxdr_%s(XDR *xdrs, %s *objp)\n" % (indent, obj.name, obj.name) + + "%s{\n" % indent + + self.generate_type_call( + obj.body.discriminator, + "objp->%s" % obj.body.discriminator.identifier, + obj.body.discriminator.identifier, + embedded=True, + indent=indent, + ) + + "%s switch (objp->%s) {\n" + % (indent, obj.body.discriminator.identifier) + ) + + for case in obj.body.cases: + code = ( + code + + "%s case %s:\n" % (indent, case.value) + + self.generate_type_call( + case.decl, + "objp->%s_u.%s" % (obj.name, case.decl.identifier), + obj.name, + embedded=True, + indent=indent + " ", + ) + + "%s break;\n" % indent + ) + + code = code + "%s default:\n" % indent + + if obj.body.default is not None: + code = ( + code + + self.generate_type_call( + obj.body.default, + "objp->%s_u.%s" % (obj.name, obj.body.default.identifier), + obj.name, + embedded=True, + indent=indent + " ", + ) + + "%s break;\n" % indent + ) + else: + code = code + "%s return FALSE;\n" % indent + + code = ( + code + + "%s }\n" % indent + + "%s return TRUE;\n" % indent + + "%s}\n" % indent + ) + return code + + def visit_definition_struct(self, obj, indent, context): + code = ( + "%sbool_t\n" % indent + + "%sxdr_%s(XDR *xdrs, %s *objp)\n" % (indent, obj.name, obj.name) + + "%s{\n" % indent + ) + for field in obj.body.fields: + code = code + self.generate_type_call( + field, + "objp->%s" % field.identifier, + field.identifier, + embedded=True, + indent=indent, + ) + code = code + "%s return TRUE;\n" % indent + "%s}\n" % indent + return code + + def visit_definition_typedef(self, obj, indent, context): + code = "%sbool_t\n" % indent + if isinstance(obj.decl, XDRDeclarationFixedArray): + code = code + "%sxdr_%s(XDR *xdrs, %s objp)\n" % ( + indent, + obj.decl.identifier, + obj.decl.identifier, + ) + else: + code = code + "%sxdr_%s(XDR *xdrs, %s *objp)\n" % ( + indent, + obj.decl.identifier, + obj.decl.identifier, + ) + code = ( + code + + "%s{\n" % indent + + self.generate_type_call( + obj.decl, "objp", obj.decl.identifier, embedded=False, indent=indent + ) + + "%s return TRUE;\n" % indent + + "%s}\n" % indent + ) + return code + + def visit_declaration_pointer(self, obj, indent, context): + return "%s%s *%s" % (indent, self.visit_object(obj.typ), obj.identifier) + + def visit_declaration_fixedarray(self, obj, indent, context): + return "%s%s %s[%s]" % ( + indent, + self.visit_object(obj.typ), + obj.identifier, + obj.length, + ) + + def visit_declaration_variablearray(self, obj, indent, context): + return "%s%s *%s" % (indent, self.visit_object(obj.typ), obj.identifier) + + def visit_type_custom(self, obj, indent, context): + return "%s%s" % (indent, obj.identifier) + + def visit_type_opaque(self, obj, indent, context): + return "%sopaque" % indent + + def visit_type_string(self, obj, indent, context): + return "%sstring" % indent + + def visit_type_char(self, obj, indent, context): + return "%schar" % indent + + def visit_type_unsignedchar(self, obj, indent, context): + return "%su_char" % indent + + def visit_type_short(self, obj, indent, context): + return "%sshort" % indent + + def visit_type_unsignedshort(self, obj, indent, context): + return "%su_short" % indent + + def visit_type_int(self, obj, indent, context): + return "%sint" % indent + + def visit_type_unsignedint(self, obj, indent, context): + return "%su_int" % indent + + def visit_type_hyper(self, obj, indent, context): + return "%sint64_t" % indent + + def visit_type_unsignedhyper(self, obj, indent, context): + if context == "func": + return "%su_int64_t" % indent + else: + return "%suint64_t" % indent + + def visit_type_bool(self, obj, indent, context): + if context == "func": + return "%sbool" % indent + else: + return "%sbool_t" % indent + + def visit_type_float(self, obj, indent, context): + return "%sfloat" % indent + + def visit_type_double(self, obj, indent, context): + return "%sdouble" % indent + + def visit_enum_value(self, obj, indent, context): + return "%s%s = %s" % (indent, obj.name, obj.value) + + def visit_union_case(self, obj, indent, context): + return self.visit_object(obj.value, indent) diff --git a/scripts/rpcgen/tests/demo.c b/scripts/rpcgen/tests/demo.c new file mode 100644 index 0000000000..a261b4fe22 --- /dev/null +++ b/scripts/rpcgen/tests/demo.c @@ -0,0 +1,351 @@ +bool_t +xdr_TestEnum(XDR *xdrs, TestEnum *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestStruct(XDR *xdrs, TestStruct *objp) +{ + if (!xdr_char(xdrs, &objp->c1)) + return FALSE; + if (!xdr_char(xdrs, &objp->c2)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestUnion(XDR *xdrs, TestUnion *objp) +{ + if (!xdr_int(xdrs, &objp->type)) + return FALSE; + switch (objp->type) { + case 20: + if (!xdr_int(xdrs, &objp->TestUnion_u.i1)) + return FALSE; + break; + case 30: + if (!xdr_int(xdrs, &objp->TestUnion_u.i2)) + return FALSE; + break; + default: + if (!xdr_int(xdrs, &objp->TestUnion_u.i3)) + return FALSE; + break; + } + return TRUE; +} + +bool_t +xdr_TestUnionVoidDefault(XDR *xdrs, TestUnionVoidDefault *objp) +{ + if (!xdr_int(xdrs, &objp->type)) + return FALSE; + switch (objp->type) { + case 21: + if (!xdr_int(xdrs, &objp->TestUnionVoidDefault_u.i1)) + return FALSE; + break; + case 31: + if (!xdr_int(xdrs, &objp->TestUnionVoidDefault_u.i2)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_TestUnionNoDefault(XDR *xdrs, TestUnionNoDefault *objp) +{ + if (!xdr_int(xdrs, &objp->type)) + return FALSE; + switch (objp->type) { + case 22: + if (!xdr_int(xdrs, &objp->TestUnionNoDefault_u.i1)) + return FALSE; + break; + case 32: + if (!xdr_int(xdrs, &objp->TestUnionNoDefault_u.i2)) + return FALSE; + break; + default: + return FALSE; + } + return TRUE; +} + +bool_t +xdr_TestIntScalar(XDR *xdrs, TestIntScalar *objp) +{ + if (!xdr_int(xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestIntPointer(XDR *xdrs, TestIntPointer *objp) +{ + if (!xdr_pointer(xdrs, (char **)objp, sizeof(int), (xdrproc_t)xdr_int)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestIntFixedArray(XDR *xdrs, TestIntFixedArray objp) +{ + if (!xdr_vector(xdrs, (char *)objp, 3, + sizeof(int), (xdrproc_t)xdr_int)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestIntVariableArray(XDR *xdrs, TestIntVariableArray *objp) +{ + if (!xdr_array(xdrs, (char **)&objp->TestIntVariableArray_val, (u_int *) &objp->TestIntVariableArray_len, 5, + sizeof(int), (xdrproc_t)xdr_int)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestStringVariableArray(XDR *xdrs, TestStringVariableArray *objp) +{ + if (!xdr_string(xdrs, objp, 7)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestOpaqueFixedArray(XDR *xdrs, TestOpaqueFixedArray objp) +{ + if (!xdr_opaque(xdrs, objp, 9)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestOpaqueVariableArray(XDR *xdrs, TestOpaqueVariableArray *objp) +{ + if (!xdr_bytes(xdrs, (char **)&objp->TestOpaqueVariableArray_val, (u_int *) &objp->TestOpaqueVariableArray_len, 11)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestEnumScalar(XDR *xdrs, TestEnumScalar *objp) +{ + if (!xdr_TestEnum(xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestEnumPointer(XDR *xdrs, TestEnumPointer *objp) +{ + if (!xdr_pointer(xdrs, (char **)objp, sizeof(TestEnum), (xdrproc_t)xdr_TestEnum)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestEnumFixedArray(XDR *xdrs, TestEnumFixedArray objp) +{ + if (!xdr_vector(xdrs, (char *)objp, 13, + sizeof(TestEnum), (xdrproc_t)xdr_TestEnum)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestEnumVariableArray(XDR *xdrs, TestEnumVariableArray *objp) +{ + if (!xdr_array(xdrs, (char **)&objp->TestEnumVariableArray_val, (u_int *) &objp->TestEnumVariableArray_len, 15, + sizeof(TestEnum), (xdrproc_t)xdr_TestEnum)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestStructScalar(XDR *xdrs, TestStructScalar *objp) +{ + if (!xdr_TestStruct(xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestStructPointer(XDR *xdrs, TestStructPointer *objp) +{ + if (!xdr_pointer(xdrs, (char **)objp, sizeof(TestStruct), (xdrproc_t)xdr_TestStruct)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestStructFixedArray(XDR *xdrs, TestStructFixedArray objp) +{ + if (!xdr_vector(xdrs, (char *)objp, 17, + sizeof(TestStruct), (xdrproc_t)xdr_TestStruct)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestStructVariableArray(XDR *xdrs, TestStructVariableArray *objp) +{ + if (!xdr_array(xdrs, (char **)&objp->TestStructVariableArray_val, (u_int *) &objp->TestStructVariableArray_len, 19, + sizeof(TestStruct), (xdrproc_t)xdr_TestStruct)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestUnionScalar(XDR *xdrs, TestUnionScalar *objp) +{ + if (!xdr_TestUnion(xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestUnionPointer(XDR *xdrs, TestUnionPointer *objp) +{ + if (!xdr_pointer(xdrs, (char **)objp, sizeof(TestUnion), (xdrproc_t)xdr_TestUnion)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestUnionFixedArray(XDR *xdrs, TestUnionFixedArray objp) +{ + if (!xdr_vector(xdrs, (char *)objp, 21, + sizeof(TestUnion), (xdrproc_t)xdr_TestUnion)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestUnionVariableArray(XDR *xdrs, TestUnionVariableArray *objp) +{ + if (!xdr_array(xdrs, (char **)&objp->TestUnionVariableArray_val, (u_int *) &objp->TestUnionVariableArray_len, 23, + sizeof(TestUnion), (xdrproc_t)xdr_TestUnion)) + return FALSE; + return TRUE; +} + +bool_t +xdr_TestStructAllTypes(XDR *xdrs, TestStructAllTypes *objp) +{ + if (!xdr_char(xdrs, &objp->sc)) + return FALSE; + if (!xdr_u_char(xdrs, &objp->suc)) + return FALSE; + if (!xdr_short(xdrs, &objp->ss)) + return FALSE; + if (!xdr_u_short(xdrs, &objp->sus)) + return FALSE; + if (!xdr_int(xdrs, &objp->si)) + return FALSE; + if (!xdr_u_int(xdrs, &objp->sui)) + return FALSE; + if (!xdr_int64_t(xdrs, &objp->sh)) + return FALSE; + if (!xdr_u_int64_t(xdrs, &objp->suh)) + return FALSE; + if (!xdr_bool(xdrs, &objp->sb)) + return FALSE; + if (!xdr_float(xdrs, &objp->sf)) + return FALSE; + if (!xdr_double(xdrs, &objp->sd)) + return FALSE; + if (!xdr_pointer(xdrs, (char **)&objp->ip, sizeof(int), (xdrproc_t)xdr_int)) + return FALSE; + if (!xdr_vector(xdrs, (char *)objp->ifa, TestConstDec, + sizeof(int), (xdrproc_t)xdr_int)) + return FALSE; + if (!xdr_array(xdrs, (char **)&objp->iva.iva_val, (u_int *) &objp->iva.iva_len, TestConstHex, + sizeof(int), (xdrproc_t)xdr_int)) + return FALSE; + if (!xdr_string(xdrs, &objp->stva, TestConstOct)) + return FALSE; + if (!xdr_opaque(xdrs, objp->ofa, 33)) + return FALSE; + if (!xdr_bytes(xdrs, (char **)&objp->ova.ova_val, (u_int *) &objp->ova.ova_len, 35)) + return FALSE; + if (!xdr_TestEnum(xdrs, &objp->e1)) + return FALSE; + if (!xdr_TestEnum(xdrs, &objp->e2)) + return FALSE; + if (!xdr_pointer(xdrs, (char **)&objp->ep, sizeof(TestEnum), (xdrproc_t)xdr_TestEnum)) + return FALSE; + if (!xdr_vector(xdrs, (char *)objp->efa, 37, + sizeof(TestEnum), (xdrproc_t)xdr_TestEnum)) + return FALSE; + if (!xdr_array(xdrs, (char **)&objp->eva.eva_val, (u_int *) &objp->eva.eva_len, 39, + sizeof(TestEnum), (xdrproc_t)xdr_TestEnum)) + return FALSE; + if (!xdr_TestStruct(xdrs, &objp->s)) + return FALSE; + if (!xdr_pointer(xdrs, (char **)&objp->sp, sizeof(TestStruct), (xdrproc_t)xdr_TestStruct)) + return FALSE; + if (!xdr_vector(xdrs, (char *)objp->sfa, 41, + sizeof(TestStruct), (xdrproc_t)xdr_TestStruct)) + return FALSE; + if (!xdr_array(xdrs, (char **)&objp->sva.sva_val, (u_int *) &objp->sva.sva_len, 43, + sizeof(TestStruct), (xdrproc_t)xdr_TestStruct)) + return FALSE; + if (!xdr_TestUnion(xdrs, &objp->u)) + return FALSE; + if (!xdr_pointer(xdrs, (char **)&objp->up, sizeof(TestUnion), (xdrproc_t)xdr_TestUnion)) + return FALSE; + if (!xdr_vector(xdrs, (char *)objp->ufa, 45, + sizeof(TestUnion), (xdrproc_t)xdr_TestUnion)) + return FALSE; + if (!xdr_array(xdrs, (char **)&objp->uva.uva_val, (u_int *) &objp->uva.uva_len, 47, + sizeof(TestUnion), (xdrproc_t)xdr_TestUnion)) + return FALSE; + if (!xdr_TestIntScalar(xdrs, &objp->tis)) + return FALSE; + if (!xdr_TestIntPointer(xdrs, &objp->tip)) + return FALSE; + if (!xdr_TestIntFixedArray(xdrs, objp->tifa)) + return FALSE; + if (!xdr_TestIntVariableArray(xdrs, &objp->tiva)) + return FALSE; + if (!xdr_TestStringVariableArray(xdrs, &objp->tstva)) + return FALSE; + if (!xdr_TestOpaqueFixedArray(xdrs, objp->tofa)) + return FALSE; + if (!xdr_TestOpaqueVariableArray(xdrs, &objp->tova)) + return FALSE; + if (!xdr_TestEnumScalar(xdrs, &objp->tes)) + return FALSE; + if (!xdr_TestEnumPointer(xdrs, &objp->tep)) + return FALSE; + if (!xdr_TestEnumFixedArray(xdrs, objp->tefa)) + return FALSE; + if (!xdr_TestEnumVariableArray(xdrs, &objp->teva)) + return FALSE; + if (!xdr_TestStructScalar(xdrs, &objp->tss)) + return FALSE; + if (!xdr_TestStructPointer(xdrs, &objp->tsp)) + return FALSE; + if (!xdr_TestStructFixedArray(xdrs, objp->tsfa)) + return FALSE; + if (!xdr_TestStructVariableArray(xdrs, &objp->tsva)) + return FALSE; + if (!xdr_TestUnionScalar(xdrs, &objp->tu)) + return FALSE; + if (!xdr_TestUnionPointer(xdrs, &objp->tup)) + return FALSE; + if (!xdr_TestUnionFixedArray(xdrs, objp->tufa)) + return FALSE; + if (!xdr_TestUnionVariableArray(xdrs, &objp->tuva)) + return FALSE; + return TRUE; +} diff --git a/scripts/rpcgen/tests/demo.h b/scripts/rpcgen/tests/demo.h new file mode 100644 index 0000000000..6fac61e7e9 --- /dev/null +++ b/scripts/rpcgen/tests/demo.h @@ -0,0 +1,216 @@ +enum TestEnum { + TEST_ENUM_ONE = 1, + TEST_ENUM_TWO = 2, +}; +typedef enum TestEnum TestEnum; + +struct TestStruct { + char c1; + char c2; +}; +typedef struct TestStruct TestStruct; + +struct TestUnion { + int type; + union { + int i1; + int i2; + int i3; + } TestUnion_u; +}; +typedef struct TestUnion TestUnion; + +struct TestUnionVoidDefault { + int type; + union { + int i1; + int i2; + } TestUnionVoidDefault_u; +}; +typedef struct TestUnionVoidDefault TestUnionVoidDefault; + +struct TestUnionNoDefault { + int type; + union { + int i1; + int i2; + } TestUnionNoDefault_u; +}; +typedef struct TestUnionNoDefault TestUnionNoDefault; + +typedef int TestIntScalar; + +typedef int *TestIntPointer; + +typedef int TestIntFixedArray[3]; + +typedef struct { + u_int TestIntVariableArray_len; + int *TestIntVariableArray_val; +} TestIntVariableArray; + +typedef char *TestStringVariableArray; + +typedef char TestOpaqueFixedArray[9]; + +typedef struct { + u_int TestOpaqueVariableArray_len; + char *TestOpaqueVariableArray_val; +} TestOpaqueVariableArray; + +typedef TestEnum TestEnumScalar; + +typedef TestEnum *TestEnumPointer; + +typedef TestEnum TestEnumFixedArray[13]; + +typedef struct { + u_int TestEnumVariableArray_len; + TestEnum *TestEnumVariableArray_val; +} TestEnumVariableArray; + +typedef TestStruct TestStructScalar; + +typedef TestStruct *TestStructPointer; + +typedef TestStruct TestStructFixedArray[17]; + +typedef struct { + u_int TestStructVariableArray_len; + TestStruct *TestStructVariableArray_val; +} TestStructVariableArray; + +typedef TestUnion TestUnionScalar; + +typedef TestUnion *TestUnionPointer; + +typedef TestUnion TestUnionFixedArray[21]; + +typedef struct { + u_int TestUnionVariableArray_len; + TestUnion *TestUnionVariableArray_val; +} TestUnionVariableArray; + +#define TestConstDec 25 + +#define TestConstHex 0x27 + +#define TestConstOct 031 + +struct TestStructAllTypes { + char sc; + u_char suc; + short ss; + u_short sus; + int si; + u_int sui; + int64_t sh; + uint64_t suh; + bool_t sb; + float sf; + double sd; + int *ip; + int ifa[TestConstDec]; + struct { + u_int iva_len; + int *iva_val; + } iva; + char *stva; + char ofa[33]; + struct { + u_int ova_len; + char *ova_val; + } ova; + TestEnum e1; + TestEnum e2; + TestEnum *ep; + TestEnum efa[37]; + struct { + u_int eva_len; + TestEnum *eva_val; + } eva; + TestStruct s; + TestStruct *sp; + TestStruct sfa[41]; + struct { + u_int sva_len; + TestStruct *sva_val; + } sva; + TestUnion u; + TestUnion *up; + TestUnion ufa[45]; + struct { + u_int uva_len; + TestUnion *uva_val; + } uva; + TestIntScalar tis; + TestIntPointer tip; + TestIntFixedArray tifa; + TestIntVariableArray tiva; + TestStringVariableArray tstva; + TestOpaqueFixedArray tofa; + TestOpaqueVariableArray tova; + TestEnumScalar tes; + TestEnumPointer tep; + TestEnumFixedArray tefa; + TestEnumVariableArray teva; + TestStructScalar tss; + TestStructPointer tsp; + TestStructFixedArray tsfa; + TestStructVariableArray tsva; + TestUnionScalar tu; + TestUnionPointer tup; + TestUnionFixedArray tufa; + TestUnionVariableArray tuva; +}; +typedef struct TestStructAllTypes TestStructAllTypes; + +extern bool_t xdr_TestEnum(XDR *, TestEnum*); + +extern bool_t xdr_TestStruct(XDR *, TestStruct*); + +extern bool_t xdr_TestUnion(XDR *, TestUnion*); + +extern bool_t xdr_TestUnionVoidDefault(XDR *, TestUnionVoidDefault*); + +extern bool_t xdr_TestUnionNoDefault(XDR *, TestUnionNoDefault*); + +extern bool_t xdr_TestIntScalar(XDR *, TestIntScalar*); + +extern bool_t xdr_TestIntPointer(XDR *, TestIntPointer*); + +extern bool_t xdr_TestIntFixedArray(XDR *, TestIntFixedArray); + +extern bool_t xdr_TestIntVariableArray(XDR *, TestIntVariableArray*); + +extern bool_t xdr_TestStringVariableArray(XDR *, TestStringVariableArray*); + +extern bool_t xdr_TestOpaqueFixedArray(XDR *, TestOpaqueFixedArray); + +extern bool_t xdr_TestOpaqueVariableArray(XDR *, TestOpaqueVariableArray*); + +extern bool_t xdr_TestEnumScalar(XDR *, TestEnumScalar*); + +extern bool_t xdr_TestEnumPointer(XDR *, TestEnumPointer*); + +extern bool_t xdr_TestEnumFixedArray(XDR *, TestEnumFixedArray); + +extern bool_t xdr_TestEnumVariableArray(XDR *, TestEnumVariableArray*); + +extern bool_t xdr_TestStructScalar(XDR *, TestStructScalar*); + +extern bool_t xdr_TestStructPointer(XDR *, TestStructPointer*); + +extern bool_t xdr_TestStructFixedArray(XDR *, TestStructFixedArray); + +extern bool_t xdr_TestStructVariableArray(XDR *, TestStructVariableArray*); + +extern bool_t xdr_TestUnionScalar(XDR *, TestUnionScalar*); + +extern bool_t xdr_TestUnionPointer(XDR *, TestUnionPointer*); + +extern bool_t xdr_TestUnionFixedArray(XDR *, TestUnionFixedArray); + +extern bool_t xdr_TestUnionVariableArray(XDR *, TestUnionVariableArray*); + +extern bool_t xdr_TestStructAllTypes(XDR *, TestStructAllTypes*); diff --git a/scripts/rpcgen/tests/demo.x b/scripts/rpcgen/tests/demo.x new file mode 100644 index 0000000000..ec69913f3d --- /dev/null +++ b/scripts/rpcgen/tests/demo.x @@ -0,0 +1,128 @@ +enum TestEnum { + TEST_ENUM_ONE = 1, + TEST_ENUM_TWO = 2 +}; + +struct TestStruct { + char c1; + char c2; +}; + +union TestUnion switch (int type) { + case 20: + int i1; + case 30: + int i2; + default: + int i3; +}; + +union TestUnionVoidDefault switch (int type) { + case 21: + int i1; + case 31: + int i2; + default: + void; +}; + +union TestUnionNoDefault switch (int type) { + case 22: + int i1; + case 32: + int i2; +}; + +typedef int TestIntScalar; +typedef int *TestIntPointer; +typedef int TestIntFixedArray[3]; +typedef int TestIntVariableArray<5>; + +typedef string TestStringVariableArray<7>; + +typedef opaque TestOpaqueFixedArray[9]; +typedef opaque TestOpaqueVariableArray<11>; + +typedef TestEnum TestEnumScalar; +typedef TestEnum *TestEnumPointer; +typedef TestEnum TestEnumFixedArray[13]; +typedef TestEnum TestEnumVariableArray<15>; + +typedef TestStruct TestStructScalar; +typedef TestStruct *TestStructPointer; +typedef TestStruct TestStructFixedArray[17]; +typedef TestStruct TestStructVariableArray<19>; + +typedef TestUnion TestUnionScalar; +typedef TestUnion *TestUnionPointer; +typedef TestUnion TestUnionFixedArray[21]; +typedef TestUnion TestUnionVariableArray<23>; + +const TestConstDec = 25; +const TestConstHex = 0x27; +const TestConstOct = 031; + +struct TestStructAllTypes { + char sc; + unsigned char suc; + short ss; + unsigned short sus; + int si; + unsigned int sui; + hyper sh; + unsigned hyper suh; + bool sb; + float sf; + double sd; +/* quadruple sq; */ + + int *ip; + int ifa[TestConstDec]; + int iva<TestConstHex>; + + string stva<TestConstOct>; + + opaque ofa[33]; + opaque ova<35>; + + TestEnum e1; + TestEnum e2; + TestEnum *ep; + TestEnum efa[37]; + TestEnum eva<39>; + + TestStruct s; + TestStruct *sp; + TestStruct sfa[41]; + TestStruct sva<43>; + + TestUnion u; + TestUnion *up; + TestUnion ufa[45]; + TestUnion uva<47>; + + TestIntScalar tis; + TestIntPointer tip; + TestIntFixedArray tifa; + TestIntVariableArray tiva; + + TestStringVariableArray tstva; + + TestOpaqueFixedArray tofa; + TestOpaqueVariableArray tova; + + TestEnumScalar tes; + TestEnumPointer tep; + TestEnumFixedArray tefa; + TestEnumVariableArray teva; + + TestStructScalar tss; + TestStructPointer tsp; + TestStructFixedArray tsfa; + TestStructVariableArray tsva; + + TestUnionScalar tu; + TestUnionPointer tup; + TestUnionFixedArray tufa; + TestUnionVariableArray tuva; +}; diff --git a/scripts/rpcgen/tests/meson.build b/scripts/rpcgen/tests/meson.build index 4b1ea308ce..953a3dbede 100644 --- a/scripts/rpcgen/tests/meson.build +++ b/scripts/rpcgen/tests/meson.build @@ -1,4 +1,5 @@ rpcgen_tests = files([ + 'test_generator.py', 'test_lexer.py', 'test_parser.py', ]) diff --git a/scripts/rpcgen/tests/test_generator.py b/scripts/rpcgen/tests/test_generator.py new file mode 100644 index 0000000000..bc7660a6fc --- /dev/null +++ b/scripts/rpcgen/tests/test_generator.py @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +import os +from pathlib import Path + +from rpcgen.parser import XDRParser +from rpcgen.generator import ( + XDRTypeDeclarationGenerator, + XDRMarshallDeclarationGenerator, + XDRMarshallImplementationGenerator, +) + + +def test_generate_header(): + x = Path(Path(__file__).parent, "demo.x") + h = Path(Path(__file__).parent, "demo.h") + with x.open("r") as fp: + parser = XDRParser(fp) + spec = parser.parse() + + got = ( + XDRTypeDeclarationGenerator(spec).visit() + + "\n" + + XDRMarshallDeclarationGenerator(spec).visit() + ) + + with h.open("r") as fp: + want = fp.read() + + if "VIR_TEST_REGENERATE_OUTPUT" in os.environ: + want = got + with h.open("w") as fp: + fp.write(want) + + assert got == want + + +def test_generate_source(): + x = Path(Path(__file__).parent, "demo.x") + h = Path(Path(__file__).parent, "demo.c") + with x.open("r") as fp: + parser = XDRParser(fp) + spec = parser.parse() + + got = XDRMarshallImplementationGenerator(spec).visit() + + with h.open("r") as fp: + want = fp.read() + + if "VIR_TEST_REGENERATE_OUTPUT" in os.environ: + want = got + with h.open("w") as fp: + fp.write(want) + + assert got == want -- 2.39.1

Test the serialization done by libtirpc, so that when we later switch to our own code, we can prove wire compatibility. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- build-aux/syntax-check.mk | 11 +- scripts/rpcgen/tests/demo.x | 1 - scripts/rpcgen/tests/meson.build | 15 + scripts/rpcgen/tests/test_demo.c | 789 ++++++++++++++++++ scripts/rpcgen/tests/test_demo_enum.bin | Bin 0 -> 4 bytes .../tests/test_demo_enum_fixed_array.bin | Bin 0 -> 52 bytes .../tests/test_demo_enum_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_enum_pointer_set.bin | Bin 0 -> 8 bytes .../rpcgen/tests/test_demo_enum_scalar.bin | Bin 0 -> 4 bytes .../test_demo_enum_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_enum_variable_array_set.bin | Bin 0 -> 16 bytes .../tests/test_demo_int_fixed_array.bin | Bin 0 -> 12 bytes .../tests/test_demo_int_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_int_pointer_set.bin | Bin 0 -> 8 bytes scripts/rpcgen/tests/test_demo_int_scalar.bin | Bin 0 -> 4 bytes .../test_demo_int_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_int_variable_array_set.bin | Bin 0 -> 16 bytes .../tests/test_demo_opaque_fixed_array.bin | Bin 0 -> 12 bytes .../test_demo_opaque_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_opaque_variable_array_set.bin | Bin 0 -> 8 bytes .../test_demo_string_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_string_variable_array_set.bin | Bin 0 -> 12 bytes scripts/rpcgen/tests/test_demo_struct.bin | Bin 0 -> 8 bytes .../tests/test_demo_struct_fixed_array.bin | Bin 0 -> 136 bytes .../tests/test_demo_struct_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_struct_pointer_set.bin | Bin 0 -> 12 bytes .../rpcgen/tests/test_demo_struct_scalar.bin | 1 + .../test_demo_struct_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_struct_variable_array_set.bin | Bin 0 -> 28 bytes .../tests/test_demo_test_struct_all_types.bin | Bin 0 -> 1752 bytes scripts/rpcgen/tests/test_demo_union_case.bin | Bin 0 -> 8 bytes .../rpcgen/tests/test_demo_union_default.bin | Bin 0 -> 8 bytes .../tests/test_demo_union_fixed_array.bin | Bin 0 -> 168 bytes .../tests/test_demo_union_no_default_case.bin | Bin 0 -> 8 bytes .../tests/test_demo_union_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_union_pointer_set.bin | Bin 0 -> 12 bytes .../rpcgen/tests/test_demo_union_scalar.bin | Bin 0 -> 8 bytes .../test_demo_union_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_union_variable_array_set.bin | Bin 0 -> 28 bytes .../test_demo_union_void_default_case.bin | Bin 0 -> 8 bytes .../test_demo_union_void_default_default.bin | 1 + 41 files changed, 813 insertions(+), 5 deletions(-) create mode 100644 scripts/rpcgen/tests/test_demo.c create mode 100644 scripts/rpcgen/tests/test_demo_enum.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_opaque_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_opaque_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_opaque_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_string_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_string_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_test_struct_all_types.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_case.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_default.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_no_default_case.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_void_default_case.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_void_default_default.bin diff --git a/build-aux/syntax-check.mk b/build-aux/syntax-check.mk index 375fad188b..2599ba688f 100644 --- a/build-aux/syntax-check.mk +++ b/build-aux/syntax-check.mk @@ -1358,7 +1358,7 @@ exclude_file_name_regexp--sc_avoid_strcase = ^tools/(vsh\.h|nss/libvirt_nss_(lea exclude_file_name_regexp--sc_avoid_write = ^src/libvirt-stream\.c$$ exclude_file_name_regexp--sc_gettext_init = \ - ^((tests|examples)/|tools/virt-login-shell.c) + ^((tests|examples)/|tools/virt-login-shell\.c$$|scripts/rpcgen/tests/test_demo\.c$$) exclude_file_name_regexp--sc_copyright_usage = \ ^COPYING(|\.LESSER)$$ @@ -1387,7 +1387,7 @@ exclude_file_name_regexp--sc_prohibit_close = \ (\.p[yl]$$|\.spec\.in$$|^docs/|^(src/util/vir(file|event)\.c|src/libvirt-stream\.c|tests/(vir.+mock\.c|commandhelper\.c|qemusecuritymock\.c)|tools/nss/libvirt_nss_(leases|macs)\.c)|tools/virt-qemu-qmp-proxy$$) exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = \ - (^tests/(nodedevmdevctl|virhostcpu|virpcitest|virstoragetest)data/|docs/js/.*\.js|docs/fonts/.*\.woff|\.diff|tests/virconfdata/no-newline\.conf$$) + (^tests/(nodedevmdevctl|virhostcpu|virpcitest|virstoragetest)data/|docs/js/.*\.js|docs/fonts/.*\.woff|\.diff|tests/virconfdata/no-newline\.conf$$|\.bin) exclude_file_name_regexp--sc_prohibit_fork_wrappers = \ (^(src/(util/(vircommand|virdaemon)|lxc/lxc_controller)|tests/testutils)\.c$$) @@ -1429,10 +1429,10 @@ exclude_file_name_regexp--sc_prohibit_xmlURI = ^src/util/viruri\.c$$ exclude_file_name_regexp--sc_prohibit_return_as_function = \.py$$ exclude_file_name_regexp--sc_require_config_h = \ - ^(examples/c/.*/.*\.c|tools/virsh-edit\.c|tests/virmockstathelpers\.c|scripts/rpcgen/tests/demo\.c)$$ + ^(examples/c/.*/.*\.c|tools/virsh-edit\.c|tests/virmockstathelpers\.c|scripts/rpcgen/tests/(test_)?demo\.c)$$ exclude_file_name_regexp--sc_require_config_h_first = \ - ^(examples/|tools/virsh-edit\.c$$|tests/virmockstathelpers.c) + ^(examples/|tools/virsh-edit\.c$$|tests/virmockstathelpers\.c$$|scripts/rpcgen/tests/test_demo\.c$$) exclude_file_name_regexp--sc_trailing_blank = \ /sysinfodata/.*\.data|/virhostcpudata/.*\.cpuinfo$$ @@ -1499,6 +1499,9 @@ exclude_file_name_regexp--sc_header-ifdef = \ exclude_file_name_regexp--sc_black = \ ^tools/|src/|tests/|ci/|run\.in|scripts/[^/]*\.py +exclude_file_name_regexp--sc_spacing-check = \ + ^scripts/rpcgen/tests/test_demo\.[ch]$$ + ## -------------- ## ## Implementation ## ## -------------- ## diff --git a/scripts/rpcgen/tests/demo.x b/scripts/rpcgen/tests/demo.x index ec69913f3d..7260ad08df 100644 --- a/scripts/rpcgen/tests/demo.x +++ b/scripts/rpcgen/tests/demo.x @@ -74,7 +74,6 @@ struct TestStructAllTypes { bool sb; float sf; double sd; -/* quadruple sq; */ int *ip; int ifa[TestConstDec]; diff --git a/scripts/rpcgen/tests/meson.build b/scripts/rpcgen/tests/meson.build index 953a3dbede..b504684394 100644 --- a/scripts/rpcgen/tests/meson.build +++ b/scripts/rpcgen/tests/meson.build @@ -3,3 +3,18 @@ rpcgen_tests = files([ 'test_lexer.py', 'test_parser.py', ]) + + +test_demo = executable( + 'test_demo', + [ 'test_demo.c' ], + dependencies: [ + xdr_dep, glib_dep + ], +) + +test( + 'test_demo', + test_demo, + workdir: meson.current_source_dir(), +) diff --git a/scripts/rpcgen/tests/test_demo.c b/scripts/rpcgen/tests/test_demo.c new file mode 100644 index 0000000000..54f48e5637 --- /dev/null +++ b/scripts/rpcgen/tests/test_demo.c @@ -0,0 +1,789 @@ +#include <glib.h> +#include <rpc/xdr.h> +#include <stdbool.h> + +#include "demo.h" +#include "demo.c" + +static void test_xdr(xdrproc_t proc, void *vorig, void *vnew, const char *testname, bool fail) +{ + XDR xdr; + /* 128kb is big enough for any of our test data */ + size_t buflen = 128 * 1000; + g_autofree char *buf = g_new0(char, buflen); + g_autofree char *expfile = g_strdup_printf("test_demo_%s.bin", testname); + g_autofree char *expected = NULL; + size_t explen; + size_t actlen; + g_autoptr(GError) err = NULL; + bool_t ret; + + /* Step 1: serialize the vorig and compare to the data in test .bin files */ + xdrmem_create(&xdr, buf, buflen, XDR_ENCODE); + + ret = !!proc(&xdr, vorig); + g_assert_cmpint(ret, ==, !fail); + + if (fail) + goto cleanup; + + actlen = xdr_getpos(&xdr); + + if (getenv("VIR_TEST_REGENERATE_OUTPUT")) { + g_file_set_contents(expfile, buf, actlen, NULL); + } + + g_file_get_contents(expfile, &expected, &explen, &err); + if (err != NULL) { + g_printerr("%s\n", err->message); + abort(); + } + + g_assert_cmpint(explen, ==, actlen); + + g_assert_cmpint(memcmp(buf, expected, actlen), ==, 0); + + xdr_destroy(&xdr); + + /* Step 2: de-serialize the state to create a new object */ + xdrmem_create(&xdr, buf, buflen, XDR_DECODE); + + ret = !!proc(&xdr, vnew); + g_assert_cmpint(ret, ==, true); + + actlen = xdr_getpos(&xdr); + g_assert_cmpint(explen, ==, actlen); + + xdr_destroy(&xdr); + + /* Step 3: serialize the new object again to prove we + * round-tripped the original object */ + memset(buf, 0, buflen); + + xdrmem_create(&xdr, buf, buflen, XDR_ENCODE); + + ret = !!proc(&xdr, vnew); + g_assert_cmpint(ret, ==, true); + + actlen = xdr_getpos(&xdr); + + g_assert_cmpint(explen, ==, actlen); + + g_assert_cmpint(memcmp(buf, expected, actlen), ==, 0); + xdr_destroy(&xdr); + + /* Step 4: free mem from the new object only; the orig + * was on the stack so leave untouched */ + xdrmem_create(&xdr, buf, buflen, XDR_FREE); + + ret = !!proc(&xdr, vnew); + g_assert_cmpint(ret, ==, true); + + cleanup: + xdr_destroy(&xdr); +} + +static void test_enum(void) +{ + TestEnum vorig = TEST_ENUM_TWO; + TestEnum vnew = 0; + + test_xdr((xdrproc_t)xdr_TestEnum, &vorig, &vnew, "enum", false); +} + +static void test_struct(void) +{ + TestStruct vorig = { + .c1 = 'a', .c2 = 'b', + }; + TestStruct vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestStruct, &vorig, &vnew, "struct", false); +} + +static void test_union_case(void) +{ + TestUnion vorig = { + .type = 20, .TestUnion_u = { .i1 = 1729 }, + }; + TestUnion vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestUnion, &vorig, &vnew, "union_case", false); +} + +static void test_union_default(void) +{ + TestUnion vorig = { + .type = 87539319, .TestUnion_u = { .i3 = 1729 }, + }; + TestUnion vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestUnion, &vorig, &vnew, "union_default", false); +} + +static void test_union_void_default_case(void) +{ + TestUnionVoidDefault vorig = { + .type = 21, .TestUnionVoidDefault_u = { .i1 = 1729 }, + }; + TestUnionVoidDefault vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestUnionVoidDefault, &vorig, &vnew, "union_void_default_case", false); +} + +static void test_union_void_default_default(void) +{ + TestUnionVoidDefault vorig = { + .type = 87539319 + }; + TestUnionVoidDefault vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestUnionVoidDefault, &vorig, &vnew, "union_void_default_default", false); +} + +static void test_union_no_default_case(void) +{ + TestUnionNoDefault vorig = { + .type = 22, .TestUnionNoDefault_u = { .i1 = 1729 }, + }; + TestUnionNoDefault vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestUnionNoDefault, &vorig, &vnew, "union_no_default_case", false); +} + +static void test_union_no_default_default(void) +{ + TestUnionNoDefault vorig = { + .type = 87539319, + }; + TestUnionNoDefault vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestUnionNoDefault, &vorig, &vnew, "union_no_default_default", true); +} + +static void test_int_scalar(void) +{ + TestIntScalar vorig = 1729; + TestIntScalar vnew = 0; + + test_xdr((xdrproc_t)xdr_TestIntScalar, &vorig, &vnew, "int_scalar", false); +} + +static void test_int_pointer_set(void) +{ + int vorigp = 1729; + TestIntPointer vorig = &vorigp; + TestIntPointer vnew = NULL; + + test_xdr((xdrproc_t)xdr_TestIntPointer, &vorig, &vnew, "int_pointer_set", false); +} + +static void test_int_pointer_null(void) +{ + TestIntPointer vorig = NULL; + TestIntPointer vnew = NULL; + + test_xdr((xdrproc_t)xdr_TestIntPointer, &vorig, &vnew, "int_pointer_null", false); +} + +static void test_int_fixed_array(void) +{ + TestIntFixedArray vorig = { 1729, 0, 87539319 }; + TestIntFixedArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestIntFixedArray, + vorig, vnew, "int_fixed_array", false); +} + +static void test_int_variable_array_set(void) +{ + TestIntVariableArray vorig = { + .TestIntVariableArray_len = 3, + .TestIntVariableArray_val = (int[]) { 1729, 0, 87539319 } + }; + TestIntVariableArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestIntVariableArray, + &vorig, &vnew, "int_variable_array_set", false); +} + +static void test_int_variable_array_overflow(void) +{ + TestIntVariableArray vorig = { + .TestIntVariableArray_len = 6, + .TestIntVariableArray_val = (int[]) { 1729, 0, 87539319, 0, 1729 } + }; + TestIntVariableArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestIntVariableArray, + &vorig, &vnew, "int_variable_array_overflow", true); +} + +static void test_int_variable_array_empty(void) +{ + TestIntVariableArray vorig = { + .TestIntVariableArray_len = 0, + .TestIntVariableArray_val = (int[]) {0}, + }; + TestIntVariableArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestIntVariableArray, + &vorig, &vnew, "int_variable_array_empty", false); +} + +static void test_string_variable_array_set(void) +{ + TestStringVariableArray vorig = (TestStringVariableArray) "taxis"; + TestStringVariableArray vnew = NULL; + + test_xdr((xdrproc_t)xdr_TestStringVariableArray, + &vorig, &vnew, "string_variable_array_set", false); +} + +static void test_string_variable_array_empty(void) +{ + TestStringVariableArray vorig = (TestStringVariableArray)""; + TestStringVariableArray vnew = NULL; + + test_xdr((xdrproc_t)xdr_TestStringVariableArray, + &vorig, &vnew, "string_variable_array_empty", false); +} + +static void test_opaque_fixed_array(void) +{ + TestOpaqueFixedArray vorig = { 0xca, 0xfe, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78 }; + TestOpaqueFixedArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestOpaqueFixedArray, vorig, vnew, "opaque_fixed_array", false); +} + +static void test_opaque_variable_array_set(void) +{ + TestOpaqueVariableArray vorig = { + .TestOpaqueVariableArray_len = 3, + .TestOpaqueVariableArray_val = (char[]) { 0xca, 0xfe, 0x12 }, + }; + TestOpaqueVariableArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestOpaqueVariableArray, + &vorig, &vnew, "opaque_variable_array_set", false); +} + +static void test_opaque_variable_array_overflow(void) +{ + TestOpaqueVariableArray vorig = { + .TestOpaqueVariableArray_len = 12, + .TestOpaqueVariableArray_val = (char[]) { + 0xca, 0xfe, 0x12, 0xca, 0xfe, 0x12, + 0xca, 0xfe, 0x12, 0xca, 0xfe, 0x12, + }, + }; + TestOpaqueVariableArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestOpaqueVariableArray, + &vorig, &vnew, "opaque_variable_array_overflow", true); +} + +static void test_opaque_variable_array_empty(void) +{ + TestOpaqueVariableArray vorig = { + .TestOpaqueVariableArray_len = 0, + .TestOpaqueVariableArray_val = (char[]) {0}, + }; + TestOpaqueVariableArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestOpaqueVariableArray, + &vorig, &vnew, "opaque_variable_array_empty", false); +} + +static void test_enum_scalar(void) +{ + TestEnumScalar vorig = TEST_ENUM_TWO; + TestEnumScalar vnew = 0; + + test_xdr((xdrproc_t)xdr_TestEnumScalar, + &vorig, &vnew, "enum_scalar", false); +} + +static void test_enum_pointer_set(void) +{ + TestEnum vorigp = TEST_ENUM_TWO; + TestEnumPointer vorig = &vorigp; + TestEnumPointer vnew = NULL; + + test_xdr((xdrproc_t)xdr_TestEnumPointer, + &vorig, &vnew, "enum_pointer_set", false); +} + +static void test_enum_pointer_null(void) +{ + TestEnumPointer vorig = NULL; + TestEnumPointer vnew = NULL; + + test_xdr((xdrproc_t)xdr_TestEnumPointer, + &vorig, &vnew, "enum_pointer_null", false); +} + +static void test_enum_fixed_array(void) +{ + TestEnumFixedArray vorig = { + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE + }; + TestEnumFixedArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestEnumFixedArray, vorig, vnew, "enum_fixed_array", false); +} + +static void test_enum_variable_array_set(void) +{ + TestEnumVariableArray vorig = { + .TestEnumVariableArray_len = 3, + .TestEnumVariableArray_val = (TestEnum[]) { + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, + }, + }; + TestEnumVariableArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestEnumVariableArray, + &vorig, &vnew, "enum_variable_array_set", false); +} + +static void test_enum_variable_array_overflow(void) +{ + TestEnumVariableArray vorig = { + .TestEnumVariableArray_len = 16, + .TestEnumVariableArray_val = (TestEnum[]) { + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + } + }; + TestEnumVariableArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestEnumVariableArray, + &vorig, &vnew, "enum_variable_array_overflow", true); +} + +static void test_enum_variable_array_empty(void) +{ + TestEnumVariableArray vorig = { + .TestEnumVariableArray_len = 0, + .TestEnumVariableArray_val = (TestEnum[]) {0}, + }; + TestEnumVariableArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestEnumVariableArray, + &vorig, &vnew, "enum_variable_array_empty", false); +} + +#define TEST_STRUCT_INIT (TestStruct) { .c1 = 0xca, .c2 = 0xfe } +#define TEST_STRUCT_INIT_ALT (TestStruct) { .c1 = 0x09, .c2 = 0x07 } + +static void test_struct_scalar(void) +{ + TestStructScalar vorig = TEST_STRUCT_INIT; + TestStructScalar vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestStructScalar, + &vorig, &vnew, "struct_scalar", false); +} + +static void test_struct_pointer_set(void) +{ + TestStruct vorigp = TEST_STRUCT_INIT; + TestStructPointer vorig = &vorigp; + TestStructPointer vnew = NULL; + + test_xdr((xdrproc_t)xdr_TestStructPointer, + &vorig, &vnew, "struct_pointer_set", false); +} + +static void test_struct_pointer_null(void) +{ + TestStructPointer vorig = NULL; + TestStructPointer vnew = NULL; + + test_xdr((xdrproc_t)xdr_TestStructPointer, + &vorig, &vnew, "struct_pointer_null", false); +} + +static void test_struct_fixed_array(void) +{ + TestStructFixedArray vorig = { + TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, + TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, + TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, + TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, + TEST_STRUCT_INIT_ALT + }; + TestStructFixedArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestStructFixedArray, vorig, vnew, "struct_fixed_array", false); +} + +static void test_struct_variable_array_set(void) +{ + TestStructVariableArray vorig = { + .TestStructVariableArray_len = 3, + .TestStructVariableArray_val = (TestStruct[]) { + TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT_ALT, + }, + }; + TestStructVariableArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestStructVariableArray, + &vorig, &vnew, "struct_variable_array_set", false); +} + +static void test_struct_variable_array_overflow(void) +{ + TestStructVariableArray vorig = { + .TestStructVariableArray_len = 20, + .TestStructVariableArray_val = (TestStruct[]) { + TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, + TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, + TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, + TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, + TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, + } + }; + TestStructVariableArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestStructVariableArray, + &vorig, &vnew, "struct_variable_array_overflow", true); +} + +static void test_struct_variable_array_empty(void) +{ + TestStructVariableArray vorig = { + .TestStructVariableArray_len = 0, + .TestStructVariableArray_val = (TestStruct[]) {}, + }; + TestStructVariableArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestStructVariableArray, + &vorig, &vnew, "struct_variable_array_empty", false); +} + +#define TEST_UNION_INIT (TestUnion) { .type = 20, .TestUnion_u = { .i1 = 1729 } } +#define TEST_UNION_INIT_ALT (TestUnion) { .type = 1729, .TestUnion_u = { .i3 = 87539319 } } + +static void test_union_scalar(void) +{ + TestUnionScalar vorig = TEST_UNION_INIT; + TestUnionScalar vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestUnionScalar, + &vorig, &vnew, "union_scalar", false); +} + +static void test_union_pointer_set(void) +{ + TestUnion vorigp = TEST_UNION_INIT; + TestUnionPointer vorig = &vorigp; + TestUnionPointer vnew = NULL; + + test_xdr((xdrproc_t)xdr_TestUnionPointer, + &vorig, &vnew, "union_pointer_set", false); +} + +static void test_union_pointer_null(void) +{ + TestUnionPointer vorig = NULL; + TestUnionPointer vnew = NULL; + + test_xdr((xdrproc_t)xdr_TestUnionPointer, + &vorig, &vnew, "union_pointer_null", false); +} + +static void test_union_fixed_array(void) +{ + TestUnionFixedArray vorig = { + TEST_UNION_INIT, TEST_UNION_INIT_ALT, TEST_UNION_INIT, TEST_UNION_INIT_ALT, + TEST_UNION_INIT_ALT, TEST_UNION_INIT, TEST_UNION_INIT_ALT, TEST_UNION_INIT, + TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, + TEST_UNION_INIT_ALT, TEST_UNION_INIT_ALT, TEST_UNION_INIT, TEST_UNION_INIT, + TEST_UNION_INIT_ALT + }; + TestUnionFixedArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestUnionFixedArray, vorig, vnew, "union_fixed_array", false); +} + +static void test_union_variable_array_set(void) +{ + TestUnionVariableArray vorig = { + .TestUnionVariableArray_len = 3, + .TestUnionVariableArray_val = (TestUnion[]) { + TEST_UNION_INIT, TEST_UNION_INIT_ALT, TEST_UNION_INIT_ALT, + }, + }; + TestUnionVariableArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestUnionVariableArray, + &vorig, &vnew, "union_variable_array_set", false); +} + +static void test_union_variable_array_overflow(void) +{ + TestUnionVariableArray vorig = { + .TestUnionVariableArray_len = 24, + .TestUnionVariableArray_val = (TestUnion[]) { + TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, + TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, + TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, + TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, + TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, + TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, + } + }; + TestUnionVariableArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestUnionVariableArray, + &vorig, &vnew, "union_variable_array_overflow", true); +} + +static void test_union_variable_array_empty(void) +{ + TestUnionVariableArray vorig = { + .TestUnionVariableArray_len = 0, + .TestUnionVariableArray_val = (TestUnion[]) {}, + }; + TestUnionVariableArray vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestUnionVariableArray, + &vorig, &vnew, "union_variable_array_empty", false); +} + +static void test_struct_all_types(void) +{ + int ip = 1729; + TestEnum ep = TEST_ENUM_TWO; + TestStruct sp = TEST_STRUCT_INIT; + TestUnion up = TEST_UNION_INIT; + TestStructAllTypes vorig = { + .sc = 'x', + .suc = 'y', + .ss = -7, + .sus = 14, + .si = -1729, + .sui = 1729, + .sh = -87539319, + .suh = -87539319, + .sb = true, + .sf = 0.1729, + .sd = 8753.9319, + .ip = &ip, + .ifa = { 1, 2, 3 }, + .iva = { + .iva_len = 3, + .iva_val = (int[]) { 7, 8, 9 }, + }, + .stva = (char *)"hello", + .ofa = { + 0x1, 0x2, 0x3, 0xff, 0xff, 0xff, 0xff, 0x1, + 0x1, 0x2, 0x3, 0xff, 0xff, 0xff, 0xff, 0x1, + 0x1, 0x2, 0x3, 0xff, 0xff, 0xff, 0xff, 0x1, + 0x1, 0x2, 0x3, 0xff, 0xff, 0xff, 0xff, 0x1, + 0xff, + }, + .ova = { + .ova_len = 3, + .ova_val = (char[]) { 0x1, 0xca, 0xfe }, + }, + .e1 = TEST_ENUM_ONE, + .e2 = TEST_ENUM_TWO, + .ep = &ep, + .efa = { + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + TEST_ENUM_ONE, + }, + .eva = { + .eva_len = 3, + .eva_val = (TestEnum[]) { + TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + }, + }, + .s = TEST_STRUCT_INIT, + .sp = &sp, + .sfa = { + TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, + TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, + TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, + TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, + TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, + TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, + TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, + TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, + TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, + TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, + TEST_STRUCT_INIT, + }, + .sva = { + .sva_len = 3, + .sva_val = (TestStruct[]) { + TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, + }, + }, + .u = TEST_UNION_INIT, + .up = &up, + .ufa = { + TEST_UNION_INIT, TEST_UNION_INIT_ALT, TEST_UNION_INIT, TEST_UNION_INIT_ALT, + TEST_UNION_INIT_ALT, TEST_UNION_INIT, TEST_UNION_INIT_ALT, TEST_UNION_INIT, + TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, + TEST_UNION_INIT_ALT, TEST_UNION_INIT_ALT, TEST_UNION_INIT, TEST_UNION_INIT, + TEST_UNION_INIT, TEST_UNION_INIT_ALT, TEST_UNION_INIT, TEST_UNION_INIT_ALT, + TEST_UNION_INIT_ALT, TEST_UNION_INIT, TEST_UNION_INIT_ALT, TEST_UNION_INIT, + TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, + TEST_UNION_INIT_ALT, TEST_UNION_INIT_ALT, TEST_UNION_INIT, TEST_UNION_INIT, + TEST_UNION_INIT, TEST_UNION_INIT_ALT, TEST_UNION_INIT, TEST_UNION_INIT_ALT, + TEST_UNION_INIT_ALT, TEST_UNION_INIT, TEST_UNION_INIT_ALT, TEST_UNION_INIT, + TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, + TEST_UNION_INIT_ALT, + }, + .uva = { + .uva_len = 3, + .uva_val = (TestUnion[]) { + TEST_UNION_INIT, TEST_UNION_INIT_ALT, TEST_UNION_INIT_ALT, + }, + }, + .tis = 1729, + .tip = &ip, + .tifa = { 1, 2, 3 }, + .tiva = { + .TestIntVariableArray_len = 3, + .TestIntVariableArray_val = (int[]) { 7, 8, 9 }, + }, + .tstva = (char *)"hello", + .tofa = { + 0x1, 0x2, 0x3, 0xff, 0xff, 0xff, 0xff, 0x1, + 0xff, + }, + .tova = { + .TestOpaqueVariableArray_len = 3, + .TestOpaqueVariableArray_val = (char[]) { 0x1, 0xca, 0xfe }, + }, + .tes = TEST_ENUM_ONE, + .tep = &ep, + .tefa = { + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + TEST_ENUM_ONE, + }, + .teva = { + .TestEnumVariableArray_len = 3, + .TestEnumVariableArray_val = (TestEnum[]) { + TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, + }, + }, + .tss = TEST_STRUCT_INIT, + .tsp = &sp, + .tsfa = { + TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, + TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, + TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, + TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, + TEST_STRUCT_INIT, + }, + .tsva = { + .TestStructVariableArray_len = 3, + .TestStructVariableArray_val = (TestStruct[]) { + TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, + }, + }, + .tu = TEST_UNION_INIT, + .tup = &up, + .tufa = { + TEST_UNION_INIT, TEST_UNION_INIT_ALT, TEST_UNION_INIT, TEST_UNION_INIT_ALT, + TEST_UNION_INIT_ALT, TEST_UNION_INIT, TEST_UNION_INIT_ALT, TEST_UNION_INIT, + TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, + TEST_UNION_INIT_ALT, TEST_UNION_INIT_ALT, TEST_UNION_INIT, TEST_UNION_INIT, + TEST_UNION_INIT, TEST_UNION_INIT_ALT, TEST_UNION_INIT, TEST_UNION_INIT_ALT, + TEST_UNION_INIT_ALT, + }, + .tuva = { + .TestUnionVariableArray_len = 3, + .TestUnionVariableArray_val = (TestUnion[]) { + TEST_UNION_INIT, TEST_UNION_INIT_ALT, TEST_UNION_INIT_ALT, + }, + }, + }; + TestStructAllTypes vnew = {0}; + + test_xdr((xdrproc_t)xdr_TestStructAllTypes, + &vorig, &vnew, "test_struct_all_types", false); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + g_test_set_nonfatal_assertions(); + + g_test_add_func("/xdr/enum", test_enum); + + g_test_add_func("/xdr/struct", test_struct); + + g_test_add_func("/xdr/union/case", test_union_case); + g_test_add_func("/xdr/union/default", test_union_default); + g_test_add_func("/xdr/union-void-default/case", test_union_void_default_case); + g_test_add_func("/xdr/union-void-default/default", test_union_void_default_default); + g_test_add_func("/xdr/union-no-default/case", test_union_no_default_case); + g_test_add_func("/xdr/union-no-default/default", test_union_no_default_default); + + g_test_add_func("/xdr/int-scalar", test_int_scalar); + g_test_add_func("/xdr/int-pointer/set", test_int_pointer_set); + g_test_add_func("/xdr/int-pointer/null", test_int_pointer_null); + g_test_add_func("/xdr/int-fixed-array", test_int_fixed_array); + g_test_add_func("/xdr/int-variable-array/set", test_int_variable_array_set); + g_test_add_func("/xdr/int-variable-array/overflow", test_int_variable_array_overflow); + g_test_add_func("/xdr/int-variable-array/empty", test_int_variable_array_empty); + + g_test_add_func("/xdr/string-variable-array/set", test_string_variable_array_set); + g_test_add_func("/xdr/string-variable-array/empty", test_string_variable_array_empty); + + g_test_add_func("/xdr/opaque-fixed-array", test_opaque_fixed_array); + g_test_add_func("/xdr/opaque-variable-array/set", test_opaque_variable_array_set); + g_test_add_func("/xdr/opaque-variable-array/overflow", test_opaque_variable_array_overflow); + g_test_add_func("/xdr/opaque-variable-array/empty", test_opaque_variable_array_empty); + + g_test_add_func("/xdr/enum-scalar", test_enum_scalar); + g_test_add_func("/xdr/enum-pointer/set", test_enum_pointer_set); + g_test_add_func("/xdr/enum-pointer/null", test_enum_pointer_null); + g_test_add_func("/xdr/enum-fixed-array", test_enum_fixed_array); + g_test_add_func("/xdr/enum-variable-array/set", test_enum_variable_array_set); + g_test_add_func("/xdr/enum-variable-array/overflow", test_enum_variable_array_overflow); + g_test_add_func("/xdr/enum-variable-array/empty", test_enum_variable_array_empty); + + g_test_add_func("/xdr/struct-scalar", test_struct_scalar); + g_test_add_func("/xdr/struct-pointer/set", test_struct_pointer_set); + g_test_add_func("/xdr/struct-pointer/null", test_struct_pointer_null); + g_test_add_func("/xdr/struct-fixed-array", test_struct_fixed_array); + g_test_add_func("/xdr/struct-variable-array/set", test_struct_variable_array_set); + g_test_add_func("/xdr/struct-variable-array/overflow", test_struct_variable_array_overflow); + g_test_add_func("/xdr/struct-variable-array/empty", test_struct_variable_array_empty); + + g_test_add_func("/xdr/union-scalar", test_union_scalar); + g_test_add_func("/xdr/union-pointer/set", test_union_pointer_set); + g_test_add_func("/xdr/union-pointer/null", test_union_pointer_null); + g_test_add_func("/xdr/union-fixed-array", test_union_fixed_array); + g_test_add_func("/xdr/union-variable-array/set", test_union_variable_array_set); + g_test_add_func("/xdr/union-variable-array/overflow", test_union_variable_array_overflow); + g_test_add_func("/xdr/union-variable-array/empty", test_union_variable_array_empty); + + g_test_add_func("/xdr/struct-all-types", test_struct_all_types); + + return g_test_run(); +} diff --git a/scripts/rpcgen/tests/test_demo_enum.bin b/scripts/rpcgen/tests/test_demo_enum.bin new file mode 100644 index 0000000000000000000000000000000000000000..b6a8ef3e7ca7c398cd8f65bb1e21a23c0d251536 GIT binary patch literal 4 LcmZQzU|<3O00sa9 literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_enum_fixed_array.bin b/scripts/rpcgen/tests/test_demo_enum_fixed_array.bin new file mode 100644 index 0000000000000000000000000000000000000000..869e8134ac62626562dda76a4eea95f9779ab266 GIT binary patch literal 52 WcmZQzU|?imU|<4bVrZZ;1_l5E1OO2L literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_enum_pointer_null.bin b/scripts/rpcgen/tests/test_demo_enum_pointer_null.bin new file mode 100644 index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4 GIT binary patch literal 4 LcmZQzU|;|M00aO5 literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_enum_pointer_set.bin b/scripts/rpcgen/tests/test_demo_enum_pointer_set.bin new file mode 100644 index 0000000000000000000000000000000000000000..dc4fb37fcdbedaa327cd251b1a0666fe66a51917 GIT binary patch literal 8 PcmZQzU|?imU|<3O01p5J literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_enum_scalar.bin b/scripts/rpcgen/tests/test_demo_enum_scalar.bin new file mode 100644 index 0000000000000000000000000000000000000000..b6a8ef3e7ca7c398cd8f65bb1e21a23c0d251536 GIT binary patch literal 4 LcmZQzU|<3O00sa9 literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_enum_variable_array_empty.bin b/scripts/rpcgen/tests/test_demo_enum_variable_array_empty.bin new file mode 100644 index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4 GIT binary patch literal 4 LcmZQzU|;|M00aO5 literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_enum_variable_array_set.bin b/scripts/rpcgen/tests/test_demo_enum_variable_array_set.bin new file mode 100644 index 0000000000000000000000000000000000000000..63c142946282ff9fc3d398e1a7ff0d354572875a GIT binary patch literal 16 TcmZQzU|?ooU|<AdCJ+q(080P} literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_int_fixed_array.bin b/scripts/rpcgen/tests/test_demo_int_fixed_array.bin new file mode 100644 index 0000000000000000000000000000000000000000..4e19f58a908989c4cc5af6aa9ed8459959fbc796 GIT binary patch literal 12 RcmZQzU^~bF1gz%!$^i+z0yzKx literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_int_pointer_null.bin b/scripts/rpcgen/tests/test_demo_int_pointer_null.bin new file mode 100644 index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4 GIT binary patch literal 4 LcmZQzU|;|M00aO5 literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_int_pointer_set.bin b/scripts/rpcgen/tests/test_demo_int_pointer_set.bin new file mode 100644 index 0000000000000000000000000000000000000000..7574dc886a36e645ac50963f0857faa542bfd3b1 GIT binary patch literal 8 PcmZQzU|?imU^@r^0NMb_ literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_int_scalar.bin b/scripts/rpcgen/tests/test_demo_int_scalar.bin new file mode 100644 index 0000000000000000000000000000000000000000..53ae788bb25812da65525031f29181e79fb7dc2e GIT binary patch literal 4 LcmZQzU^@r^0MP)* literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_int_variable_array_empty.bin b/scripts/rpcgen/tests/test_demo_int_variable_array_empty.bin new file mode 100644 index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4 GIT binary patch literal 4 LcmZQzU|;|M00aO5 literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_int_variable_array_set.bin b/scripts/rpcgen/tests/test_demo_int_variable_array_set.bin new file mode 100644 index 0000000000000000000000000000000000000000..2ef627b63f7c9aaed9be8d01a8be2fd889b1453b GIT binary patch literal 16 VcmZQzU|?ooU^~bF1gz%!$^i-J0z3c! literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_opaque_fixed_array.bin b/scripts/rpcgen/tests/test_demo_opaque_fixed_array.bin new file mode 100644 index 0000000000000000000000000000000000000000..c60ee0612b962fd290f7ad6a6cae4028c7e8f191 GIT binary patch literal 12 TcmX^0Pe|FsH7vb?fq?-4AIAf% literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_opaque_variable_array_empty.bin b/scripts/rpcgen/tests/test_demo_opaque_variable_array_empty.bin new file mode 100644 index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4 GIT binary patch literal 4 LcmZQzU|;|M00aO5 literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_opaque_variable_array_set.bin b/scripts/rpcgen/tests/test_demo_opaque_variable_array_set.bin new file mode 100644 index 0000000000000000000000000000000000000000..6970f11f819c17aff128663c8cdcc314ea357545 GIT binary patch literal 8 PcmZQzU|>G=Ply2k23-N( literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_string_variable_array_empty.bin b/scripts/rpcgen/tests/test_demo_string_variable_array_empty.bin new file mode 100644 index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4 GIT binary patch literal 4 LcmZQzU|;|M00aO5 literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_string_variable_array_set.bin b/scripts/rpcgen/tests/test_demo_string_variable_array_set.bin new file mode 100644 index 0000000000000000000000000000000000000000..78e29054977ae0cf3a9a29e568c586407891c363 GIT binary patch literal 12 TcmZQzU|=mttjH{8U|;|M4JiUI literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_struct.bin b/scripts/rpcgen/tests/test_demo_struct.bin new file mode 100644 index 0000000000000000000000000000000000000000..17d90c3c949f7e06f21a758ec281b8739386ae32 GIT binary patch literal 8 PcmZQzU`S+OU`PT00#5+M literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_struct_fixed_array.bin b/scripts/rpcgen/tests/test_demo_struct_fixed_array.bin new file mode 100644 index 0000000000000000000000000000000000000000..f0e786ddea02cbd342ec9f6d3c6ee2b090b38792 GIT binary patch literal 136 ncmezW|Np7~|NsAEU|`?`Vs;=Kg^x=drj8H|(+{K3)x*RAqQp)G literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_struct_pointer_null.bin b/scripts/rpcgen/tests/test_demo_struct_pointer_null.bin new file mode 100644 index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4 GIT binary patch literal 4 LcmZQzU|;|M00aO5 literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_struct_pointer_set.bin b/scripts/rpcgen/tests/test_demo_struct_pointer_set.bin new file mode 100644 index 0000000000000000000000000000000000000000..572814793222ad03346747bb3041bb7eafc5205e GIT binary patch literal 12 ScmZQzU|{_J|Nki<{s#ae=Lf_9 literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_struct_scalar.bin b/scripts/rpcgen/tests/test_demo_struct_scalar.bin new file mode 100644 index 0000000000..0e6959d56a --- /dev/null +++ b/scripts/rpcgen/tests/test_demo_struct_scalar.bin @@ -0,0 +1 @@ +�������� \ No newline at end of file diff --git a/scripts/rpcgen/tests/test_demo_struct_variable_array_empty.bin b/scripts/rpcgen/tests/test_demo_struct_variable_array_empty.bin new file mode 100644 index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4 GIT binary patch literal 4 LcmZQzU|;|M00aO5 literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_struct_variable_array_set.bin b/scripts/rpcgen/tests/test_demo_struct_variable_array_set.bin new file mode 100644 index 0000000000000000000000000000000000000000..a9406a21cf6b767b76e2041536e560f5ef3c0202 GIT binary patch literal 28 acmZQzU||0L|Nki<{>Q+;zzM|cFd6`$K?mjl literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_test_struct_all_types.bin b/scripts/rpcgen/tests/test_demo_test_struct_all_types.bin new file mode 100644 index 0000000000000000000000000000000000000000..5ee4ee5a6d5e467e373add81d6266f4acee2a150 GIT binary patch literal 1752 zcmds%ze+<<42N@iX{#Vk9efR^ZvNSPk%B|PQJtJ!`zqaqyGeZ@(ZSPSs$Y@Na0U^y z7s7Xv{Bp?+=f=$L%<R6_`X(L==Vqf`etmzwe1yuCv(uyHMSt>o_3*NA-*um~f!N7@ z>+yGwWe2iD+3<QcpWo<E2A#K9GFEBybY=D7RL`4U|1$kseV&^h^=&JeH(xkI#e5dy z=x1?sEm99Neaz!S>Y`6PBYN1<kw*_>93M*OmxuYrSx&y)Z_ZyF^~34Yt?GlH#nH7$ zJ<Rkmj}NJfKJkp`VM|9IJ&bYu7Ps~O4<xf?=fLgmY3_&}yWl5#;6MGR`+CpQd$I;< CFZ~+; literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_case.bin b/scripts/rpcgen/tests/test_demo_union_case.bin new file mode 100644 index 0000000000000000000000000000000000000000..b7ca515883a8101f1a1502a59a6adadc4eae6c2e GIT binary patch literal 8 PcmZQzU=U$oU^@r^0XYEN literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_default.bin b/scripts/rpcgen/tests/test_demo_union_default.bin new file mode 100644 index 0000000000000000000000000000000000000000..7acf7d7ef0eb935218c72dd8048520cd450b79d2 GIT binary patch literal 8 PcmZQI-&fASz;+M-2}J@q literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_fixed_array.bin b/scripts/rpcgen/tests/test_demo_union_fixed_array.bin new file mode 100644 index 0000000000000000000000000000000000000000..c666f3a1d66381b4cbe02e139f80362539ecd719 GIT binary patch literal 168 pcmZQzU=U$oU^@uHtmga588G;`#9{gf(J=im8eKhH9B4Ie002%@7#9El literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_no_default_case.bin b/scripts/rpcgen/tests/test_demo_union_no_default_case.bin new file mode 100644 index 0000000000000000000000000000000000000000..6dbd9a934f737640d1766b1c9d2b8483d1e2fd99 GIT binary patch literal 8 PcmZQzU=U+qU^@r^0Yd=Z literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_pointer_null.bin b/scripts/rpcgen/tests/test_demo_union_pointer_null.bin new file mode 100644 index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4 GIT binary patch literal 4 LcmZQzU|;|M00aO5 literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_pointer_set.bin b/scripts/rpcgen/tests/test_demo_union_pointer_set.bin new file mode 100644 index 0000000000000000000000000000000000000000..01dc9dabe89fe0a2c87b838350a422d65cfab6ef GIT binary patch literal 12 TcmZQzU|?imU=U$oU^@r^0Y(7b literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_scalar.bin b/scripts/rpcgen/tests/test_demo_union_scalar.bin new file mode 100644 index 0000000000000000000000000000000000000000..b7ca515883a8101f1a1502a59a6adadc4eae6c2e GIT binary patch literal 8 PcmZQzU=U$oU^@r^0XYEN literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_variable_array_empty.bin b/scripts/rpcgen/tests/test_demo_union_variable_array_empty.bin new file mode 100644 index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4 GIT binary patch literal 4 LcmZQzU|;|M00aO5 literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_variable_array_set.bin b/scripts/rpcgen/tests/test_demo_union_variable_array_set.bin new file mode 100644 index 0000000000000000000000000000000000000000..3edd18c10589b472d237e6cdbe2da69ba10efea3 GIT binary patch literal 28 acmZQzU|?ooU=U$oU^@uHtmga5VKe|PG6hcn literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_void_default_case.bin b/scripts/rpcgen/tests/test_demo_union_void_default_case.bin new file mode 100644 index 0000000000000000000000000000000000000000..b5f6c99ca52e8881d621342f22940a4931305973 GIT binary patch literal 8 PcmZQzU=U?sU^@r^0X_iT literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_void_default_default.bin b/scripts/rpcgen/tests/test_demo_union_void_default_default.bin new file mode 100644 index 0000000000..d7e8f43f03 --- /dev/null +++ b/scripts/rpcgen/tests/test_demo_union_void_default_default.bin @@ -0,0 +1 @@ +7�w \ No newline at end of file -- 2.39.1

On 3/8/23 17:39, Daniel P. Berrangé wrote:
Test the serialization done by libtirpc, so that when we later switch to our own code, we can prove wire compatibility.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- build-aux/syntax-check.mk | 11 +- scripts/rpcgen/tests/demo.x | 1 - scripts/rpcgen/tests/meson.build | 15 + scripts/rpcgen/tests/test_demo.c | 789 ++++++++++++++++++ scripts/rpcgen/tests/test_demo_enum.bin | Bin 0 -> 4 bytes .../tests/test_demo_enum_fixed_array.bin | Bin 0 -> 52 bytes .../tests/test_demo_enum_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_enum_pointer_set.bin | Bin 0 -> 8 bytes .../rpcgen/tests/test_demo_enum_scalar.bin | Bin 0 -> 4 bytes .../test_demo_enum_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_enum_variable_array_set.bin | Bin 0 -> 16 bytes .../tests/test_demo_int_fixed_array.bin | Bin 0 -> 12 bytes .../tests/test_demo_int_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_int_pointer_set.bin | Bin 0 -> 8 bytes scripts/rpcgen/tests/test_demo_int_scalar.bin | Bin 0 -> 4 bytes .../test_demo_int_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_int_variable_array_set.bin | Bin 0 -> 16 bytes .../tests/test_demo_opaque_fixed_array.bin | Bin 0 -> 12 bytes .../test_demo_opaque_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_opaque_variable_array_set.bin | Bin 0 -> 8 bytes .../test_demo_string_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_string_variable_array_set.bin | Bin 0 -> 12 bytes scripts/rpcgen/tests/test_demo_struct.bin | Bin 0 -> 8 bytes .../tests/test_demo_struct_fixed_array.bin | Bin 0 -> 136 bytes .../tests/test_demo_struct_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_struct_pointer_set.bin | Bin 0 -> 12 bytes .../rpcgen/tests/test_demo_struct_scalar.bin | 1 + .../test_demo_struct_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_struct_variable_array_set.bin | Bin 0 -> 28 bytes .../tests/test_demo_test_struct_all_types.bin | Bin 0 -> 1752 bytes scripts/rpcgen/tests/test_demo_union_case.bin | Bin 0 -> 8 bytes .../rpcgen/tests/test_demo_union_default.bin | Bin 0 -> 8 bytes .../tests/test_demo_union_fixed_array.bin | Bin 0 -> 168 bytes .../tests/test_demo_union_no_default_case.bin | Bin 0 -> 8 bytes .../tests/test_demo_union_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_union_pointer_set.bin | Bin 0 -> 12 bytes .../rpcgen/tests/test_demo_union_scalar.bin | Bin 0 -> 8 bytes .../test_demo_union_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_union_variable_array_set.bin | Bin 0 -> 28 bytes .../test_demo_union_void_default_case.bin | Bin 0 -> 8 bytes .../test_demo_union_void_default_default.bin | 1 + 41 files changed, 813 insertions(+), 5 deletions(-) create mode 100644 scripts/rpcgen/tests/test_demo.c create mode 100644 scripts/rpcgen/tests/test_demo_enum.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_opaque_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_opaque_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_opaque_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_string_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_string_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_test_struct_all_types.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_case.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_default.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_no_default_case.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_void_default_case.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_void_default_default.bin
diff --git a/scripts/rpcgen/tests/test_demo_struct_scalar.bin b/scripts/rpcgen/tests/test_demo_struct_scalar.bin new file mode 100644 index 0000000000..0e6959d56a --- /dev/null +++ b/scripts/rpcgen/tests/test_demo_struct_scalar.bin @@ -0,0 +1 @@ +
I don't know what's going on but this surely can't be an empty file. Also, some other .bin files are missing. Squash this in (generated by VIR_TEST_REGENERATE_OUTPUT=1) --- scripts/rpcgen/tests/test_demo_struct_scalar.bin | 2 +- .../test_demo_struct_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_struct_variable_array_set.bin | Bin 0 -> 28 bytes .../tests/test_demo_test_struct_all_types.bin | Bin 0 -> 1752 bytes scripts/rpcgen/tests/test_demo_union_case.bin | Bin 0 -> 8 bytes scripts/rpcgen/tests/test_demo_union_default.bin | Bin 0 -> 8 bytes .../rpcgen/tests/test_demo_union_fixed_array.bin | Bin 0 -> 168 bytes .../tests/test_demo_union_no_default_case.bin | Bin 0 -> 8 bytes .../tests/test_demo_union_pointer_null.bin | Bin 0 -> 4 bytes .../rpcgen/tests/test_demo_union_pointer_set.bin | Bin 0 -> 12 bytes scripts/rpcgen/tests/test_demo_union_scalar.bin | Bin 0 -> 8 bytes .../test_demo_union_variable_array_empty.bin | Bin 0 -> 4 bytes .../tests/test_demo_union_variable_array_set.bin | Bin 0 -> 28 bytes .../tests/test_demo_union_void_default_case.bin | Bin 0 -> 8 bytes .../test_demo_union_void_default_default.bin | 1 + 15 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 scripts/rpcgen/tests/test_demo_struct_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_test_struct_all_types.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_case.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_default.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_no_default_case.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_void_default_case.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_void_default_default.bin diff --git a/scripts/rpcgen/tests/test_demo_struct_scalar.bin b/scripts/rpcgen/tests/test_demo_struct_scalar.bin index 8b13789179..0e6959d56a 100644 --- a/scripts/rpcgen/tests/test_demo_struct_scalar.bin +++ b/scripts/rpcgen/tests/test_demo_struct_scalar.bin @@ -1 +1 @@ - +ÿÿÿÊÿÿÿþ \ No newline at end of file diff --git a/scripts/rpcgen/tests/test_demo_struct_variable_array_empty.bin b/scripts/rpcgen/tests/test_demo_struct_variable_array_empty.bin new file mode 100644 index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4 GIT binary patch literal 4 LcmZQzU|;|M00aO5 literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_struct_variable_array_set.bin b/scripts/rpcgen/tests/test_demo_struct_variable_array_set.bin new file mode 100644 index 0000000000000000000000000000000000000000..a9406a21cf6b767b76e2041536e560f5ef3c0202 GIT binary patch literal 28 acmZQzU||0L|Nki<{>Q+;zzM|cFd6`$K?mjl literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_test_struct_all_types.bin b/scripts/rpcgen/tests/test_demo_test_struct_all_types.bin new file mode 100644 index 0000000000000000000000000000000000000000..5ee4ee5a6d5e467e373add81d6266f4acee2a150 GIT binary patch literal 1752 zcmds%ze+<<42N@iX{#Vk9efR^ZvNSPk%B|PQJtJ!`zqaqyGeZ@(ZSPSs$Y@Na0U^y z7s7Xv{Bp?+=f=$L%<R6_`X(L==Vqf`etmzwe1yuCv(uyHMSt>o_3*NA-*um~f!N7@ z>+yGwWe2iD+3<QcpWo<E2A#K9GFEBybY=D7RL`4U|1$kseV&^h^=&JeH(xkI#e5dy z=x1?sEm99Neaz!S>Y`6PBYN1<kw*_>93M*OmxuYrSx&y)Z_ZyF^~34Yt?GlH#nH7$ zJ<Rkmj}NJfKJkp`VM|9IJ&bYu7Ps~O4<xf?=fLgmY3_&}yWl5#;6MGR`+CpQd$I;< CFZ~+; literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_case.bin b/scripts/rpcgen/tests/test_demo_union_case.bin new file mode 100644 index 0000000000000000000000000000000000000000..b7ca515883a8101f1a1502a59a6adadc4eae6c2e GIT binary patch literal 8 PcmZQzU=U$oU^@r^0XYEN literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_default.bin b/scripts/rpcgen/tests/test_demo_union_default.bin new file mode 100644 index 0000000000000000000000000000000000000000..7acf7d7ef0eb935218c72dd8048520cd450b79d2 GIT binary patch literal 8 PcmZQI-&fASz;+M-2}J@q literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_fixed_array.bin b/scripts/rpcgen/tests/test_demo_union_fixed_array.bin new file mode 100644 index 0000000000000000000000000000000000000000..c666f3a1d66381b4cbe02e139f80362539ecd719 GIT binary patch literal 168 pcmZQzU=U$oU^@uHtmga588G;`#9{gf(J=im8eKhH9B4Ie002%@7#9El literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_no_default_case.bin b/scripts/rpcgen/tests/test_demo_union_no_default_case.bin new file mode 100644 index 0000000000000000000000000000000000000000..6dbd9a934f737640d1766b1c9d2b8483d1e2fd99 GIT binary patch literal 8 PcmZQzU=U+qU^@r^0Yd=Z literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_pointer_null.bin b/scripts/rpcgen/tests/test_demo_union_pointer_null.bin new file mode 100644 index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4 GIT binary patch literal 4 LcmZQzU|;|M00aO5 literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_pointer_set.bin b/scripts/rpcgen/tests/test_demo_union_pointer_set.bin new file mode 100644 index 0000000000000000000000000000000000000000..01dc9dabe89fe0a2c87b838350a422d65cfab6ef GIT binary patch literal 12 TcmZQzU|?imU=U$oU^@r^0Y(7b literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_scalar.bin b/scripts/rpcgen/tests/test_demo_union_scalar.bin new file mode 100644 index 0000000000000000000000000000000000000000..b7ca515883a8101f1a1502a59a6adadc4eae6c2e GIT binary patch literal 8 PcmZQzU=U$oU^@r^0XYEN literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_variable_array_empty.bin b/scripts/rpcgen/tests/test_demo_union_variable_array_empty.bin new file mode 100644 index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4 GIT binary patch literal 4 LcmZQzU|;|M00aO5 literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_variable_array_set.bin b/scripts/rpcgen/tests/test_demo_union_variable_array_set.bin new file mode 100644 index 0000000000000000000000000000000000000000..3edd18c10589b472d237e6cdbe2da69ba10efea3 GIT binary patch literal 28 acmZQzU|?ooU=U$oU^@uHtmga5VKe|PG6hcn literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_void_default_case.bin b/scripts/rpcgen/tests/test_demo_union_void_default_case.bin new file mode 100644 index 0000000000000000000000000000000000000000..b5f6c99ca52e8881d621342f22940a4931305973 GIT binary patch literal 8 PcmZQzU=U?sU^@r^0X_iT literal 0 HcmV?d00001 diff --git a/scripts/rpcgen/tests/test_demo_union_void_default_default.bin b/scripts/rpcgen/tests/test_demo_union_void_default_default.bin new file mode 100644 index 0000000000..d7e8f43f03 --- /dev/null +++ b/scripts/rpcgen/tests/test_demo_union_void_default_default.bin @@ -0,0 +1 @@ +7¾w \ No newline at end of file -- 2.39.2

On Thu, Mar 09, 2023 at 04:12:04PM +0100, Michal Prívozník wrote:
On 3/8/23 17:39, Daniel P. Berrangé wrote:
Test the serialization done by libtirpc, so that when we later switch to our own code, we can prove wire compatibility.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- build-aux/syntax-check.mk | 11 +- scripts/rpcgen/tests/demo.x | 1 - scripts/rpcgen/tests/meson.build | 15 + scripts/rpcgen/tests/test_demo.c | 789 ++++++++++++++++++ scripts/rpcgen/tests/test_demo_enum.bin | Bin 0 -> 4 bytes .../tests/test_demo_enum_fixed_array.bin | Bin 0 -> 52 bytes .../tests/test_demo_enum_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_enum_pointer_set.bin | Bin 0 -> 8 bytes .../rpcgen/tests/test_demo_enum_scalar.bin | Bin 0 -> 4 bytes .../test_demo_enum_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_enum_variable_array_set.bin | Bin 0 -> 16 bytes .../tests/test_demo_int_fixed_array.bin | Bin 0 -> 12 bytes .../tests/test_demo_int_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_int_pointer_set.bin | Bin 0 -> 8 bytes scripts/rpcgen/tests/test_demo_int_scalar.bin | Bin 0 -> 4 bytes .../test_demo_int_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_int_variable_array_set.bin | Bin 0 -> 16 bytes .../tests/test_demo_opaque_fixed_array.bin | Bin 0 -> 12 bytes .../test_demo_opaque_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_opaque_variable_array_set.bin | Bin 0 -> 8 bytes .../test_demo_string_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_string_variable_array_set.bin | Bin 0 -> 12 bytes scripts/rpcgen/tests/test_demo_struct.bin | Bin 0 -> 8 bytes .../tests/test_demo_struct_fixed_array.bin | Bin 0 -> 136 bytes .../tests/test_demo_struct_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_struct_pointer_set.bin | Bin 0 -> 12 bytes .../rpcgen/tests/test_demo_struct_scalar.bin | 1 + .../test_demo_struct_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_struct_variable_array_set.bin | Bin 0 -> 28 bytes .../tests/test_demo_test_struct_all_types.bin | Bin 0 -> 1752 bytes scripts/rpcgen/tests/test_demo_union_case.bin | Bin 0 -> 8 bytes .../rpcgen/tests/test_demo_union_default.bin | Bin 0 -> 8 bytes .../tests/test_demo_union_fixed_array.bin | Bin 0 -> 168 bytes .../tests/test_demo_union_no_default_case.bin | Bin 0 -> 8 bytes .../tests/test_demo_union_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_union_pointer_set.bin | Bin 0 -> 12 bytes .../rpcgen/tests/test_demo_union_scalar.bin | Bin 0 -> 8 bytes .../test_demo_union_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_union_variable_array_set.bin | Bin 0 -> 28 bytes .../test_demo_union_void_default_case.bin | Bin 0 -> 8 bytes .../test_demo_union_void_default_default.bin | 1 + 41 files changed, 813 insertions(+), 5 deletions(-) create mode 100644 scripts/rpcgen/tests/test_demo.c create mode 100644 scripts/rpcgen/tests/test_demo_enum.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_opaque_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_opaque_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_opaque_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_string_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_string_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_test_struct_all_types.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_case.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_default.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_no_default_case.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_void_default_case.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_void_default_default.bin
diff --git a/scripts/rpcgen/tests/test_demo_struct_scalar.bin b/scripts/rpcgen/tests/test_demo_struct_scalar.bin new file mode 100644 index 0000000000..0e6959d56a --- /dev/null +++ b/scripts/rpcgen/tests/test_demo_struct_scalar.bin @@ -0,0 +1 @@ +
I don't know what's going on but this surely can't be an empty file. Also, some other .bin files are missing. Squash this in (generated by VIR_TEST_REGENERATE_OUTPUT=1)
I think something must have gone wrong with git formatting, because the changes you suggested below were exactly what my local commits actually have & tests pass. Rather odd. ..snip.. With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

The new program takes the form rpcgen [--mode source|header|repr] \ [--header include] \ xdr-file output-file If '--mode' is not given it parses the XDR file but does not generate anything, which is useful as a syntax check. The 'source' mode gives the '.c' file content, while 'header' gives the '.h' file content. 'repr' gives a representation of the abstract syntax tree, mostly useful for debugging the parser. If '--header' is given, it is added as a local #include ".." statement in the output and is valid for either 'header' or 'source' modes. Either 'xdr-file' or 'output-file' can be omitted in which case they default to stdin/stdout respectively. This rpcgen program will directly include the 'config.h' header in its output. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- scripts/rpcgen/main.py | 86 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100755 scripts/rpcgen/main.py diff --git a/scripts/rpcgen/main.py b/scripts/rpcgen/main.py new file mode 100755 index 0000000000..bf4ef38ede --- /dev/null +++ b/scripts/rpcgen/main.py @@ -0,0 +1,86 @@ +#!/usr/bin/python +# SPDX-License-Identifier: LGPL-2.1-or-later + +import argparse +import os +import sys + +from rpcgen.parser import XDRParser +from rpcgen.generator import ( + XDRTypeDeclarationGenerator, + XDRMarshallDeclarationGenerator, + XDRMarshallImplementationGenerator, +) + + +def parse_cli(): + parser = argparse.ArgumentParser("RPC code generator") + parser.add_argument( + "-m", + "--mode", + choices=["header", "source", "repr"], + help="Output generation mode", + ) + parser.add_argument( + "-r", "--header", default=[], action="append", help="Extra headers to include" + ) + parser.add_argument("input", default="-", nargs="?", help="XDR input protocol file") + parser.add_argument("output", default="-", nargs="?", help="Generated output file") + + return parser.parse_args() + + +def main(): + args = parse_cli() + + infp = sys.stdin + outfp = sys.stdout + if args.input != "-": + infp = open(args.input, "r") + if args.output != "-": + # the old genprotocol.pl wrapper would make the + # output files mode 0444, which will prevent us + # from writing directly do them. Explicitly + # unlinking first gets rid of any old possibly + # read-only copy + # + # We can delete this in a few years, once we + # know users won't have a previously generated + # readonly copy lieing around. + try: + os.unlink(args.output) + except Exception: + pass + outfp = open(args.output, "w") + + parser = XDRParser(infp) + spec = parser.parse() + + if args.mode == "header": + print("/* This file is auto-generated from %s */\n" % args.input, file=outfp) + print("#include <rpc/rpc.h>", file=outfp) + for h in args.header: + print('#include "%s"' % h, file=outfp) + print("", file=outfp) + print("#pragma once\n", file=outfp) + generator = XDRTypeDeclarationGenerator(spec) + print(generator.visit(), file=outfp) + generator = XDRMarshallDeclarationGenerator(spec) + print(generator.visit(), file=outfp) + elif args.mode == "source": + print("/* This file is auto-generated from %s */\n" % args.input, file=outfp) + print("#include <config.h>", file=outfp) + if args.input.endswith(".x"): + print('#include "%s.h"' % args.input[:-2], file=outfp) + for h in args.header: + print('#include "%s"' % h, file=outfp) + print("", file=outfp) + generator = XDRMarshallImplementationGenerator(spec) + print(generator.visit(), file=outfp) + elif args.mode == "repr": + print(spec, file=outfp) + else: + pass # Just validates XDR input syntax + + +main() -- 2.39.1

On a Wednesday in 2023, Daniel P. Berrangé wrote:
The new program takes the form
rpcgen [--mode source|header|repr] \ [--header include] \ xdr-file output-file
If '--mode' is not given it parses the XDR file but does not generate anything, which is useful as a syntax check. The 'source' mode gives the '.c' file content, while 'header' gives the '.h' file content. 'repr' gives a representation of the abstract syntax tree, mostly useful for debugging the parser.
If '--header' is given, it is added as a local #include ".." statement in the output and is valid for either 'header' or 'source' modes.
Either 'xdr-file' or 'output-file' can be omitted in which case they default to stdin/stdout respectively.
This rpcgen program will directly include the 'config.h' header in its output.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- scripts/rpcgen/main.py | 86 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100755 scripts/rpcgen/main.py
diff --git a/scripts/rpcgen/main.py b/scripts/rpcgen/main.py new file mode 100755 index 0000000000..bf4ef38ede --- /dev/null +++ b/scripts/rpcgen/main.py @@ -0,0 +1,86 @@ +#!/usr/bin/python
#!/usr/bin/env python
+ + if args.mode == "header": + print("/* This file is auto-generated from %s */\n" % args.input, file=outfp) + print("#include <rpc/rpc.h>", file=outfp) + for h in args.header: + print('#include "%s"' % h, file=outfp) + print("", file=outfp) + print("#pragma once\n", file=outfp) + generator = XDRTypeDeclarationGenerator(spec) + print(generator.visit(), file=outfp) + generator = XDRMarshallDeclarationGenerator(spec) + print(generator.visit(), file=outfp) + elif args.mode == "source": + print("/* This file is auto-generated from %s */\n" % args.input, file=outfp) + print("#include <config.h>", file=outfp)
+ if args.input.endswith(".x"): + print('#include "%s.h"' % args.input[:-2], file=outfp)
The .x file is in the source dir, while the .h file is in the build dir. Unless I remove the two lines above, I'm getting an error: src/remote/lxc_protocol.c:4:10: fatal error: '../../git/libvirt/src/remote/lxc_protocol.h' file not found #include "../../git/libvirt/src/remote/lxc_protocol.h" ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ And thanks to the --header option, there already is an include of lxc_protocol.h in the file: #include <config.h> #include "../../git/libvirt/src/remote/lxc_protocol.h" #include "lxc_protocol.h" If I use a builddir under libvirt.git, it somehow works: #include <config.h> #include "../src/remote/lxc_protocol.h" #include "lxc_protocol.h" Jano
+ for h in args.header: + print('#include "%s"' % h, file=outfp) + print("", file=outfp) + generator = XDRMarshallImplementationGenerator(spec) + print(generator.visit(), file=outfp) + elif args.mode == "repr": + print(spec, file=outfp) + else: + pass # Just validates XDR input syntax + + +main() -- 2.39.1

On Thu, Mar 09, 2023 at 03:25:38PM +0100, Ján Tomko wrote:
On a Wednesday in 2023, Daniel P. Berrangé wrote:
The new program takes the form
rpcgen [--mode source|header|repr] \ [--header include] \ xdr-file output-file
If '--mode' is not given it parses the XDR file but does not generate anything, which is useful as a syntax check. The 'source' mode gives the '.c' file content, while 'header' gives the '.h' file content. 'repr' gives a representation of the abstract syntax tree, mostly useful for debugging the parser.
If '--header' is given, it is added as a local #include ".." statement in the output and is valid for either 'header' or 'source' modes.
Either 'xdr-file' or 'output-file' can be omitted in which case they default to stdin/stdout respectively.
This rpcgen program will directly include the 'config.h' header in its output.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- scripts/rpcgen/main.py | 86 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100755 scripts/rpcgen/main.py
diff --git a/scripts/rpcgen/main.py b/scripts/rpcgen/main.py new file mode 100755 index 0000000000..bf4ef38ede --- /dev/null +++ b/scripts/rpcgen/main.py @@ -0,0 +1,86 @@ +#!/usr/bin/python
#!/usr/bin/env python
+ + if args.mode == "header": + print("/* This file is auto-generated from %s */\n" % args.input, file=outfp) + print("#include <rpc/rpc.h>", file=outfp) + for h in args.header: + print('#include "%s"' % h, file=outfp) + print("", file=outfp) + print("#pragma once\n", file=outfp) + generator = XDRTypeDeclarationGenerator(spec) + print(generator.visit(), file=outfp) + generator = XDRMarshallDeclarationGenerator(spec) + print(generator.visit(), file=outfp) + elif args.mode == "source": + print("/* This file is auto-generated from %s */\n" % args.input, file=outfp) + print("#include <config.h>", file=outfp)
+ if args.input.endswith(".x"): + print('#include "%s.h"' % args.input[:-2], file=outfp)
The .x file is in the source dir, while the .h file is in the build dir.
Unless I remove the two lines above, I'm getting an error:
src/remote/lxc_protocol.c:4:10: fatal error: '../../git/libvirt/src/remote/lxc_protocol.h' file not found #include "../../git/libvirt/src/remote/lxc_protocol.h" ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
And thanks to the --header option, there already is an include of lxc_protocol.h in the file:
#include <config.h> #include "../../git/libvirt/src/remote/lxc_protocol.h" #include "lxc_protocol.h"
If I use a builddir under libvirt.git, it somehow works:
#include <config.h> #include "../src/remote/lxc_protocol.h" #include "lxc_protocol.h"
Yes, that's what I used. Wierd. Anyway, as you say, it is redundant and I meant to remove it because it is saner to just pass the --header arg. With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

On 3/8/23 17:39, Daniel P. Berrangé wrote:
The new program takes the form
rpcgen [--mode source|header|repr] \ [--header include] \ xdr-file output-file
If '--mode' is not given it parses the XDR file but does not generate anything, which is useful as a syntax check. The 'source' mode gives the '.c' file content, while 'header' gives the '.h' file content. 'repr' gives a representation of the abstract syntax tree, mostly useful for debugging the parser.
If '--header' is given, it is added as a local #include ".." statement in the output and is valid for either 'header' or 'source' modes.
Either 'xdr-file' or 'output-file' can be omitted in which case they default to stdin/stdout respectively.
This rpcgen program will directly include the 'config.h' header in its output.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- scripts/rpcgen/main.py | 86 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100755 scripts/rpcgen/main.py
diff --git a/scripts/rpcgen/main.py b/scripts/rpcgen/main.py new file mode 100755 index 0000000000..bf4ef38ede --- /dev/null +++ b/scripts/rpcgen/main.py @@ -0,0 +1,86 @@ +#!/usr/bin/python
#!/usr/bin/env python3 Michal

This replaces use of 'rpcgen' with our new python impl of the RPC code generator. Since the new impl generates code that matches our style/coding rules, and does not contain long standing bugs, we no longer need to post-process the output. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- libvirt.spec.in | 1 - meson.build | 11 --- scripts/rpcgen/meson.build | 5 ++ scripts/rpcgen/rpcgen/meson.build | 7 ++ src/admin/meson.build | 8 +- src/locking/meson.build | 8 +- src/logging/meson.build | 8 +- src/lxc/meson.build | 12 ++- src/remote/meson.build | 8 +- src/rpc/genprotocol.pl | 121 ------------------------------ src/rpc/meson.build | 9 ++- 11 files changed, 52 insertions(+), 146 deletions(-) create mode 100644 scripts/rpcgen/rpcgen/meson.build delete mode 100755 src/rpc/genprotocol.pl diff --git a/libvirt.spec.in b/libvirt.spec.in index 84d2f1c65a..aca7e23512 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -377,7 +377,6 @@ BuildRequires: wireshark-devel %if %{with_libssh} BuildRequires: libssh-devel >= 0.8.1 %endif -BuildRequires: rpcgen BuildRequires: libtirpc-devel # Needed for the firewalld_reload macro %if %{with_firewalld_zone} diff --git a/meson.build b/meson.build index 9f660c7604..ef1f697e0b 100644 --- a/meson.build +++ b/meson.build @@ -743,10 +743,6 @@ required_programs = [ 'xsltproc', ] -required_programs_groups = [ - { 'name': 'rpcgen', 'prog': [ 'rpcgen', 'portable-rpcgen' ] }, -] - if host_machine.system() == 'freebsd' required_programs += 'ifconfig' endif @@ -758,13 +754,6 @@ foreach name : required_programs set_variable('@0@_prog'.format(varname), prog) endforeach -foreach item : required_programs_groups - prog = find_program(item.get('prog'), dirs: libvirt_sbin_path) - varname = item.get('name').underscorify() - conf.set_quoted(varname.to_upper(), prog.full_path()) - set_variable('@0@_prog'.format(varname), prog) -endforeach - # optional programs optional_programs = [ diff --git a/scripts/rpcgen/meson.build b/scripts/rpcgen/meson.build index 52526bf812..65236457be 100644 --- a/scripts/rpcgen/meson.build +++ b/scripts/rpcgen/meson.build @@ -1,3 +1,5 @@ +subdir('rpcgen') + if pytest_prog.found() subdir('tests') @@ -9,3 +11,6 @@ if pytest_prog.found() workdir: meson.current_source_dir(), ) endif + +rpcgen_prog = find_program('main.py') +rpcgen_src += files(['main.py']) diff --git a/scripts/rpcgen/rpcgen/meson.build b/scripts/rpcgen/rpcgen/meson.build new file mode 100644 index 0000000000..5a0f59eecf --- /dev/null +++ b/scripts/rpcgen/rpcgen/meson.build @@ -0,0 +1,7 @@ +rpcgen_src = files([ + 'ast.py', + 'lexer.py', + 'generator.py', + 'parser.py', + 'visitor.py', +]) diff --git a/src/admin/meson.build b/src/admin/meson.build index 692cc128a3..e5e6a87706 100644 --- a/src/admin/meson.build +++ b/src/admin/meson.build @@ -13,8 +13,10 @@ admin_protocol_h = custom_target( 'admin_protocol.h', input: admin_driver_protocol, output: 'admin_protocol.h', + depend_files: rpcgen_src, command: [ - genprotocol_prog, rpcgen_prog, '-h', '@INPUT@', '@OUTPUT@', + meson_python_prog, python3_prog, rpcgen_prog, + '--mode=header', '@INPUT@', '@OUTPUT@', ], ) admin_driver_generated += admin_protocol_h @@ -23,8 +25,10 @@ admin_driver_generated += custom_target( 'admin_protocol.c', input: admin_driver_protocol, output: 'admin_protocol.c', + depend_files: rpcgen_src, command: [ - genprotocol_prog, rpcgen_prog, '-c', '@INPUT@', '@OUTPUT@', + meson_python_prog, python3_prog, rpcgen_prog, + '--mode=source', '--header=admin_protocol.h', '@INPUT@', '@OUTPUT@', ], ) diff --git a/src/locking/meson.build b/src/locking/meson.build index 72f7780438..529caa1b9e 100644 --- a/src/locking/meson.build +++ b/src/locking/meson.build @@ -18,8 +18,10 @@ lock_protocol_generated += custom_target( 'lock_protocol.h', input: lock_protocol, output: 'lock_protocol.h', + depend_files: rpcgen_src, command: [ - genprotocol_prog, rpcgen_prog, '-h', '@INPUT@', '@OUTPUT@', + meson_python_prog, python3_prog, rpcgen_prog, + '--mode=header', '@INPUT@', '@OUTPUT@', ], ) @@ -27,8 +29,10 @@ lock_protocol_generated += custom_target( 'lock_protocol.c', input: lock_protocol, output: 'lock_protocol.c', + depend_files: rpcgen_src, command: [ - genprotocol_prog, rpcgen_prog, '-c', '@INPUT@', '@OUTPUT@', + meson_python_prog, python3_prog, rpcgen_prog, + '--mode=source', '--header=lock_protocol.h', '@INPUT@', '@OUTPUT@', ], ) diff --git a/src/logging/meson.build b/src/logging/meson.build index fa6af50fa6..4f5ca92052 100644 --- a/src/logging/meson.build +++ b/src/logging/meson.build @@ -10,8 +10,10 @@ log_protocol_header_generated = custom_target( 'log_protocol.h', input: log_protocol, output: 'log_protocol.h', + depend_files: rpcgen_src, command: [ - genprotocol_prog, rpcgen_prog, '-h', '@INPUT@', '@OUTPUT@' + meson_python_prog, python3_prog, rpcgen_prog, + '--mode=header', '@INPUT@', '@OUTPUT@', ], ) log_protocol_generated += log_protocol_header_generated @@ -20,8 +22,10 @@ log_protocol_generated += custom_target( 'log_protocol.c', input: log_protocol, output: 'log_protocol.c', + depend_files: rpcgen_src, command: [ - genprotocol_prog, rpcgen_prog, '-c', '@INPUT@', '@OUTPUT@' + meson_python_prog, python3_prog, rpcgen_prog, + '--mode=source', '--header=log_protocol.h', '@INPUT@', '@OUTPUT@', ], ) diff --git a/src/lxc/meson.build b/src/lxc/meson.build index 99d4a34213..3a21f1f006 100644 --- a/src/lxc/meson.build +++ b/src/lxc/meson.build @@ -21,14 +21,22 @@ lxc_monitor_protocol_generated += custom_target( 'lxc_monitor_protocol_h', input: lxc_monitor_protocol, output: 'lxc_monitor_protocol.h', - command: [ genprotocol_prog, rpcgen_prog, '-h', '@INPUT@', '@OUTPUT@' ] + depend_files: rpcgen_src, + command: [ + meson_python_prog, python3_prog, rpcgen_prog, + '--mode=header', '@INPUT@', '@OUTPUT@', + ] ) lxc_monitor_protocol_generated += custom_target( 'lxc_monitor_protocol_c', input: lxc_monitor_protocol, output: 'lxc_monitor_protocol.c', - command: [ genprotocol_prog, rpcgen_prog, '-c', '@INPUT@', '@OUTPUT@' ] + depend_files: rpcgen_src, + command: [ + meson_python_prog, python3_prog, rpcgen_prog, + '--mode=source', '--header=lxc_monitor_protocol.h', '@INPUT@', '@OUTPUT@', + ], ) lxc_monitor_generated = custom_target( diff --git a/src/remote/meson.build b/src/remote/meson.build index eb4f7a0068..ce41591f5b 100644 --- a/src/remote/meson.build +++ b/src/remote/meson.build @@ -25,8 +25,10 @@ foreach name : [ 'remote', 'qemu', 'lxc' ] protocol_h, input: protocol_x, output: protocol_h, + depend_files: rpcgen_src, command: [ - genprotocol_prog, rpcgen_prog, '-h', '@INPUT@', '@OUTPUT@', + meson_python_prog, python3_prog, rpcgen_prog, + '--mode=header', '@INPUT@', '@OUTPUT@', ], ) @@ -34,8 +36,10 @@ foreach name : [ 'remote', 'qemu', 'lxc' ] protocol_c, input: protocol_x, output: protocol_c, + depend_files: rpcgen_src, command: [ - genprotocol_prog, rpcgen_prog, '-c', '@INPUT@', '@OUTPUT@', + meson_python_prog, python3_prog, rpcgen_prog, + '--mode=source', '--header=' + protocol_h, '@INPUT@', '@OUTPUT@', ], ) diff --git a/src/rpc/genprotocol.pl b/src/rpc/genprotocol.pl deleted file mode 100755 index 079627964f..0000000000 --- a/src/rpc/genprotocol.pl +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env perl -# -# Generate code for an XDR protocol, optionally applying -# fixups to the glibc rpcgen code so that it compiles -# with warnings turned on. -# -# This code is evil. Arguably better would be just to compile -# without -Werror. Update: The IXDR_PUT_LONG replacements are -# actually fixes for 64 bit, so this file is necessary. Arguably -# so is the type-punning fix. -# -# Copyright (C) 2007, 2011-2013 Red Hat, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library. If not, see -# <http://www.gnu.org/licenses/>. -# -# Richard Jones <rjones@redhat.com> - -use strict; - -my $in_function = 0; -my @function = (); - -my $rpcgen = shift; -my $mode = shift; -my $xdrdef = shift; -my $target = shift; - -unlink $target; - -if ($rpcgen =~ /portable-rpcgen/) { - $rpcgen = "$rpcgen -o -"; -} -open RPCGEN, "-|", "$rpcgen $mode $xdrdef" - or die "cannot run $rpcgen $mode $xdrdef: $!"; -open TARGET, ">$target" - or die "cannot create $target: $!"; - -my $fixup = $^O eq "linux" || $^O eq "gnukfreebsd" || $^O eq "freebsd" || $^O eq "darwin"; - -if ($mode eq "-c") { - print TARGET "#include <config.h>\n"; -} - -while (<RPCGEN>) { - # We only want to fixup the GLibc rpcgen output - # So just print data unchanged, if non-Linux - unless ($fixup) { - print TARGET; - next; - } - - if (m/^{/) { - $in_function = 1; - print TARGET; - next; - } - - s/\t/ /g; - - # Fix VPATH builds - s,#include ".*/([^/]+)protocol\.h",#include "${1}protocol.h",; - - # Portability for Solaris RPC - s/u_quad_t/uint64_t/g; - s/quad_t/int64_t/g; - s/xdr_u_quad_t/xdr_uint64_t/g; - s/xdr_quad_t/xdr_int64_t/g; - s/(?<!IXDR_GET_INT32 )IXDR_GET_LONG/IXDR_GET_INT32/g; - - if (m/^}/) { - $in_function = 0; - - # Note: The body of the function is in @function. - - # Remove decl of buf, if buf isn't used in the function. - my @uses = grep /[^.>]\bbuf\b/, @function; - @function = grep !/[^.>]\bbuf\b/, @function if @uses == 1; - - # Remove decl of i, if i isn't used in the function. - @uses = grep /[^.>]\bi\b/, @function; - @function = grep !/[^.>]\bi\b/, @function if @uses == 1; - - # The code uses 'IXDR_PUT_{U_,}LONG' but it's wrong in two - # ways: Firstly these functions are deprecated and don't - # work on 64 bit platforms. Secondly the return value should - # be ignored. Correct both these mistakes. - @function = - map { s/\bIXDR_PUT_((U_)?)LONG\b/(void)IXDR_PUT_$1INT32/; $_ } - map { s/\bXDR_INLINE\b/(int32_t*)XDR_INLINE/; $_ } - @function; - - print TARGET (join ("", @function)); - @function = (); - } - - unless ($in_function) { - print TARGET; - } else { - push @function, $_; - } -} - -close TARGET - or die "cannot save $target: $!"; -close RPCGEN - or die "cannot shutdown $rpcgen: $!"; - -chmod 0444, $target - or die "cannot set $target readonly: $!"; diff --git a/src/rpc/meson.build b/src/rpc/meson.build index 36a2809adf..d58f3caaf5 100644 --- a/src/rpc/meson.build +++ b/src/rpc/meson.build @@ -1,4 +1,3 @@ -genprotocol_prog = find_program('genprotocol.pl') gendispatch_prog = find_program('gendispatch.pl') socket_sources = [ @@ -53,8 +52,10 @@ foreach name : [ 'virnet', 'virkeepalive' ] header_file, input: protocol_file, output: header_file, + depend_files: rpcgen_src, command: [ - genprotocol_prog, rpcgen_prog, '-h', '@INPUT@', '@OUTPUT@', + meson_python_prog, python3_prog, rpcgen_prog, + '--mode=header', '@INPUT@', '@OUTPUT@', ], ) @@ -62,8 +63,10 @@ foreach name : [ 'virnet', 'virkeepalive' ] source_file, input: protocol_file, output: source_file, + depend_files: rpcgen_src, command: [ - genprotocol_prog, rpcgen_prog, '-c', '@INPUT@', '@OUTPUT@', + meson_python_prog, python3_prog, rpcgen_prog, + '--mode=source', '--header=' + header_file, '@INPUT@', '@OUTPUT@', ], ) -- 2.39.1

This will eliminate the need to call xdr_free to clear pointers from data structures. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- build-aux/syntax-check.mk | 2 +- scripts/rpcgen/main.py | 4 + scripts/rpcgen/rpcgen/generator.py | 64 +++++++++-- scripts/rpcgen/tests/demo.c | 144 +++++++++++++++++++++++++ scripts/rpcgen/tests/demo.h | 48 +++++++++ scripts/rpcgen/tests/test_demo.c | 91 ++++++++-------- scripts/rpcgen/tests/test_generator.py | 7 +- 7 files changed, 298 insertions(+), 62 deletions(-) diff --git a/build-aux/syntax-check.mk b/build-aux/syntax-check.mk index 2599ba688f..317cf223e7 100644 --- a/build-aux/syntax-check.mk +++ b/build-aux/syntax-check.mk @@ -1464,7 +1464,7 @@ exclude_file_name_regexp--sc_prohibit_mixed_case_abbreviations = \ ^src/(vbox/vbox_CAPI.*.h|esx/esx_vi.(c|h)|esx/esx_storage_backend_iscsi.c)$$ exclude_file_name_regexp--sc_prohibit_empty_first_line = \ - ^tests/vmwareverdata/fusion-5.0.3.txt$$ + ^tests/vmwareverdata/fusion-5.0.3.txt|scripts/rpcgen/tests/demo\.c$$ exclude_file_name_regexp--sc_prohibit_useless_translation = \ ^tests/virpolkittest.c diff --git a/scripts/rpcgen/main.py b/scripts/rpcgen/main.py index bf4ef38ede..d50f08c180 100755 --- a/scripts/rpcgen/main.py +++ b/scripts/rpcgen/main.py @@ -8,6 +8,7 @@ import sys from rpcgen.parser import XDRParser from rpcgen.generator import ( XDRTypeDeclarationGenerator, + XDRTypeImplementationGenerator, XDRMarshallDeclarationGenerator, XDRMarshallImplementationGenerator, ) @@ -59,6 +60,7 @@ def main(): if args.mode == "header": print("/* This file is auto-generated from %s */\n" % args.input, file=outfp) print("#include <rpc/rpc.h>", file=outfp) + print('#include "internal.h"', file=outfp) for h in args.header: print('#include "%s"' % h, file=outfp) print("", file=outfp) @@ -75,6 +77,8 @@ def main(): for h in args.header: print('#include "%s"' % h, file=outfp) print("", file=outfp) + generator = XDRTypeImplementationGenerator(spec) + print(generator.visit(), file=outfp) generator = XDRMarshallImplementationGenerator(spec) print(generator.visit(), file=outfp) elif args.mode == "repr": diff --git a/scripts/rpcgen/rpcgen/generator.py b/scripts/rpcgen/rpcgen/generator.py index 110cd12c5e..c0f1e03ec4 100644 --- a/scripts/rpcgen/rpcgen/generator.py +++ b/scripts/rpcgen/rpcgen/generator.py @@ -28,24 +28,42 @@ class XDRTypeDeclarationGenerator(XDRVisitor): ) + "%stypedef enum %s %s;\n" % (indent, obj.name, obj.name) return code - def visit_definition_struct(self, obj, indent, context): - code = "%sstruct %s %s;\n" % ( + def generate_cleanup(self, name, indent): + code = "%svoid xdr_%s_clear(%s *objp);\n" % ( indent, - obj.name, - self.visit_object(obj.body, indent), - ) + "%stypedef struct %s %s;\n" % (indent, obj.name, obj.name) + name, + name, + ) + "%sG_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(%s, xdr_%s_clear);\n" % ( + indent, + name, + name, + ) + return code + + def visit_definition_struct(self, obj, indent, context): + code = ( + "%sstruct %s %s;\n" + % (indent, obj.name, self.visit_object(obj.body, indent)) + + "%stypedef struct %s %s;\n" % (indent, obj.name, obj.name) + + self.generate_cleanup(obj.name, indent) + ) return code def visit_definition_union(self, obj, indent, context): - code = "%sstruct %s %s;\n" % ( - indent, - obj.name, - self.visit_object(obj.body, indent, obj.name), - ) + "%stypedef struct %s %s;\n" % (indent, obj.name, obj.name) + code = ( + "%sstruct %s %s;\n" + % (indent, obj.name, self.visit_object(obj.body, indent, obj.name)) + + "%stypedef struct %s %s;\n" % (indent, obj.name, obj.name) + + self.generate_cleanup(obj.name, indent) + ) return code def visit_definition_typedef(self, obj, indent, context): - return "%stypedef %s;\n" % (indent, self.visit_object(obj.decl, indent)) + code = "%stypedef %s;\n" % ( + indent, + self.visit_object(obj.decl, indent), + ) + self.generate_cleanup(obj.decl.identifier, indent) + return code def visit_declaration_scalar(self, obj, indent, context): return "%s %s" % (self.visit_object(obj.typ, indent), obj.identifier) @@ -167,6 +185,30 @@ class XDRTypeDeclarationGenerator(XDRVisitor): return code +class XDRTypeImplementationGenerator(XDRVisitor): + def visit_definition_enum(self, obj, indent, context): + pass + + def generate_cleanup(self, name, indent): + code = ( + "\n" + + "%svoid xdr_%s_clear(%s *objp)\n" % (indent, name, name) + + "%s{\n" % indent + + "%s xdr_free((xdrproc_t)xdr_%s, (char *)objp);\n" % (indent, name) + + "%s}\n" % indent + ) + return code + + def visit_definition_union(self, obj, indent, context): + return self.generate_cleanup(obj.name, indent) + + def visit_definition_struct(self, obj, indent, context): + return self.generate_cleanup(obj.name, indent) + + def visit_definition_typedef(self, obj, indent, context): + return self.generate_cleanup(obj.decl.identifier, indent) + + class XDRMarshallDeclarationGenerator(XDRVisitor): def visit_definition_enum(self, obj, indent, context): return "%sextern bool_t xdr_%s(XDR *, %s*);\n" % (indent, obj.name, obj.name) diff --git a/scripts/rpcgen/tests/demo.c b/scripts/rpcgen/tests/demo.c index a261b4fe22..d57547d5eb 100644 --- a/scripts/rpcgen/tests/demo.c +++ b/scripts/rpcgen/tests/demo.c @@ -1,3 +1,147 @@ + +void xdr_TestStruct_clear(TestStruct *objp) +{ + xdr_free((xdrproc_t)xdr_TestStruct, (char *)objp); +} + + +void xdr_TestUnion_clear(TestUnion *objp) +{ + xdr_free((xdrproc_t)xdr_TestUnion, (char *)objp); +} + + +void xdr_TestUnionVoidDefault_clear(TestUnionVoidDefault *objp) +{ + xdr_free((xdrproc_t)xdr_TestUnionVoidDefault, (char *)objp); +} + + +void xdr_TestUnionNoDefault_clear(TestUnionNoDefault *objp) +{ + xdr_free((xdrproc_t)xdr_TestUnionNoDefault, (char *)objp); +} + + +void xdr_TestIntScalar_clear(TestIntScalar *objp) +{ + xdr_free((xdrproc_t)xdr_TestIntScalar, (char *)objp); +} + + +void xdr_TestIntPointer_clear(TestIntPointer *objp) +{ + xdr_free((xdrproc_t)xdr_TestIntPointer, (char *)objp); +} + + +void xdr_TestIntFixedArray_clear(TestIntFixedArray *objp) +{ + xdr_free((xdrproc_t)xdr_TestIntFixedArray, (char *)objp); +} + + +void xdr_TestIntVariableArray_clear(TestIntVariableArray *objp) +{ + xdr_free((xdrproc_t)xdr_TestIntVariableArray, (char *)objp); +} + + +void xdr_TestStringVariableArray_clear(TestStringVariableArray *objp) +{ + xdr_free((xdrproc_t)xdr_TestStringVariableArray, (char *)objp); +} + + +void xdr_TestOpaqueFixedArray_clear(TestOpaqueFixedArray *objp) +{ + xdr_free((xdrproc_t)xdr_TestOpaqueFixedArray, (char *)objp); +} + + +void xdr_TestOpaqueVariableArray_clear(TestOpaqueVariableArray *objp) +{ + xdr_free((xdrproc_t)xdr_TestOpaqueVariableArray, (char *)objp); +} + + +void xdr_TestEnumScalar_clear(TestEnumScalar *objp) +{ + xdr_free((xdrproc_t)xdr_TestEnumScalar, (char *)objp); +} + + +void xdr_TestEnumPointer_clear(TestEnumPointer *objp) +{ + xdr_free((xdrproc_t)xdr_TestEnumPointer, (char *)objp); +} + + +void xdr_TestEnumFixedArray_clear(TestEnumFixedArray *objp) +{ + xdr_free((xdrproc_t)xdr_TestEnumFixedArray, (char *)objp); +} + + +void xdr_TestEnumVariableArray_clear(TestEnumVariableArray *objp) +{ + xdr_free((xdrproc_t)xdr_TestEnumVariableArray, (char *)objp); +} + + +void xdr_TestStructScalar_clear(TestStructScalar *objp) +{ + xdr_free((xdrproc_t)xdr_TestStructScalar, (char *)objp); +} + + +void xdr_TestStructPointer_clear(TestStructPointer *objp) +{ + xdr_free((xdrproc_t)xdr_TestStructPointer, (char *)objp); +} + + +void xdr_TestStructFixedArray_clear(TestStructFixedArray *objp) +{ + xdr_free((xdrproc_t)xdr_TestStructFixedArray, (char *)objp); +} + + +void xdr_TestStructVariableArray_clear(TestStructVariableArray *objp) +{ + xdr_free((xdrproc_t)xdr_TestStructVariableArray, (char *)objp); +} + + +void xdr_TestUnionScalar_clear(TestUnionScalar *objp) +{ + xdr_free((xdrproc_t)xdr_TestUnionScalar, (char *)objp); +} + + +void xdr_TestUnionPointer_clear(TestUnionPointer *objp) +{ + xdr_free((xdrproc_t)xdr_TestUnionPointer, (char *)objp); +} + + +void xdr_TestUnionFixedArray_clear(TestUnionFixedArray *objp) +{ + xdr_free((xdrproc_t)xdr_TestUnionFixedArray, (char *)objp); +} + + +void xdr_TestUnionVariableArray_clear(TestUnionVariableArray *objp) +{ + xdr_free((xdrproc_t)xdr_TestUnionVariableArray, (char *)objp); +} + + +void xdr_TestStructAllTypes_clear(TestStructAllTypes *objp) +{ + xdr_free((xdrproc_t)xdr_TestStructAllTypes, (char *)objp); +} + bool_t xdr_TestEnum(XDR *xdrs, TestEnum *objp) { diff --git a/scripts/rpcgen/tests/demo.h b/scripts/rpcgen/tests/demo.h index 6fac61e7e9..36bcb40916 100644 --- a/scripts/rpcgen/tests/demo.h +++ b/scripts/rpcgen/tests/demo.h @@ -9,6 +9,8 @@ struct TestStruct { char c2; }; typedef struct TestStruct TestStruct; +void xdr_TestStruct_clear(TestStruct *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestStruct, xdr_TestStruct_clear); struct TestUnion { int type; @@ -19,6 +21,8 @@ struct TestUnion { } TestUnion_u; }; typedef struct TestUnion TestUnion; +void xdr_TestUnion_clear(TestUnion *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestUnion, xdr_TestUnion_clear); struct TestUnionVoidDefault { int type; @@ -28,6 +32,8 @@ struct TestUnionVoidDefault { } TestUnionVoidDefault_u; }; typedef struct TestUnionVoidDefault TestUnionVoidDefault; +void xdr_TestUnionVoidDefault_clear(TestUnionVoidDefault *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestUnionVoidDefault, xdr_TestUnionVoidDefault_clear); struct TestUnionNoDefault { int type; @@ -37,59 +43,99 @@ struct TestUnionNoDefault { } TestUnionNoDefault_u; }; typedef struct TestUnionNoDefault TestUnionNoDefault; +void xdr_TestUnionNoDefault_clear(TestUnionNoDefault *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestUnionNoDefault, xdr_TestUnionNoDefault_clear); typedef int TestIntScalar; +void xdr_TestIntScalar_clear(TestIntScalar *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestIntScalar, xdr_TestIntScalar_clear); typedef int *TestIntPointer; +void xdr_TestIntPointer_clear(TestIntPointer *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestIntPointer, xdr_TestIntPointer_clear); typedef int TestIntFixedArray[3]; +void xdr_TestIntFixedArray_clear(TestIntFixedArray *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestIntFixedArray, xdr_TestIntFixedArray_clear); typedef struct { u_int TestIntVariableArray_len; int *TestIntVariableArray_val; } TestIntVariableArray; +void xdr_TestIntVariableArray_clear(TestIntVariableArray *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestIntVariableArray, xdr_TestIntVariableArray_clear); typedef char *TestStringVariableArray; +void xdr_TestStringVariableArray_clear(TestStringVariableArray *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestStringVariableArray, xdr_TestStringVariableArray_clear); typedef char TestOpaqueFixedArray[9]; +void xdr_TestOpaqueFixedArray_clear(TestOpaqueFixedArray *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestOpaqueFixedArray, xdr_TestOpaqueFixedArray_clear); typedef struct { u_int TestOpaqueVariableArray_len; char *TestOpaqueVariableArray_val; } TestOpaqueVariableArray; +void xdr_TestOpaqueVariableArray_clear(TestOpaqueVariableArray *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestOpaqueVariableArray, xdr_TestOpaqueVariableArray_clear); typedef TestEnum TestEnumScalar; +void xdr_TestEnumScalar_clear(TestEnumScalar *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestEnumScalar, xdr_TestEnumScalar_clear); typedef TestEnum *TestEnumPointer; +void xdr_TestEnumPointer_clear(TestEnumPointer *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestEnumPointer, xdr_TestEnumPointer_clear); typedef TestEnum TestEnumFixedArray[13]; +void xdr_TestEnumFixedArray_clear(TestEnumFixedArray *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestEnumFixedArray, xdr_TestEnumFixedArray_clear); typedef struct { u_int TestEnumVariableArray_len; TestEnum *TestEnumVariableArray_val; } TestEnumVariableArray; +void xdr_TestEnumVariableArray_clear(TestEnumVariableArray *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestEnumVariableArray, xdr_TestEnumVariableArray_clear); typedef TestStruct TestStructScalar; +void xdr_TestStructScalar_clear(TestStructScalar *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestStructScalar, xdr_TestStructScalar_clear); typedef TestStruct *TestStructPointer; +void xdr_TestStructPointer_clear(TestStructPointer *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestStructPointer, xdr_TestStructPointer_clear); typedef TestStruct TestStructFixedArray[17]; +void xdr_TestStructFixedArray_clear(TestStructFixedArray *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestStructFixedArray, xdr_TestStructFixedArray_clear); typedef struct { u_int TestStructVariableArray_len; TestStruct *TestStructVariableArray_val; } TestStructVariableArray; +void xdr_TestStructVariableArray_clear(TestStructVariableArray *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestStructVariableArray, xdr_TestStructVariableArray_clear); typedef TestUnion TestUnionScalar; +void xdr_TestUnionScalar_clear(TestUnionScalar *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestUnionScalar, xdr_TestUnionScalar_clear); typedef TestUnion *TestUnionPointer; +void xdr_TestUnionPointer_clear(TestUnionPointer *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestUnionPointer, xdr_TestUnionPointer_clear); typedef TestUnion TestUnionFixedArray[21]; +void xdr_TestUnionFixedArray_clear(TestUnionFixedArray *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestUnionFixedArray, xdr_TestUnionFixedArray_clear); typedef struct { u_int TestUnionVariableArray_len; TestUnion *TestUnionVariableArray_val; } TestUnionVariableArray; +void xdr_TestUnionVariableArray_clear(TestUnionVariableArray *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestUnionVariableArray, xdr_TestUnionVariableArray_clear); #define TestConstDec 25 @@ -164,6 +210,8 @@ struct TestStructAllTypes { TestUnionVariableArray tuva; }; typedef struct TestStructAllTypes TestStructAllTypes; +void xdr_TestStructAllTypes_clear(TestStructAllTypes *objp); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TestStructAllTypes, xdr_TestStructAllTypes_clear); extern bool_t xdr_TestEnum(XDR *, TestEnum*); diff --git a/scripts/rpcgen/tests/test_demo.c b/scripts/rpcgen/tests/test_demo.c index 54f48e5637..cfb4cbe146 100644 --- a/scripts/rpcgen/tests/test_demo.c +++ b/scripts/rpcgen/tests/test_demo.c @@ -72,13 +72,6 @@ static void test_xdr(xdrproc_t proc, void *vorig, void *vnew, const char *testna g_assert_cmpint(memcmp(buf, expected, actlen), ==, 0); xdr_destroy(&xdr); - /* Step 4: free mem from the new object only; the orig - * was on the stack so leave untouched */ - xdrmem_create(&xdr, buf, buflen, XDR_FREE); - - ret = !!proc(&xdr, vnew); - g_assert_cmpint(ret, ==, true); - cleanup: xdr_destroy(&xdr); } @@ -96,7 +89,7 @@ static void test_struct(void) TestStruct vorig = { .c1 = 'a', .c2 = 'b', }; - TestStruct vnew = {0}; + g_auto(TestStruct) vnew = {0}; test_xdr((xdrproc_t)xdr_TestStruct, &vorig, &vnew, "struct", false); } @@ -106,7 +99,7 @@ static void test_union_case(void) TestUnion vorig = { .type = 20, .TestUnion_u = { .i1 = 1729 }, }; - TestUnion vnew = {0}; + g_auto(TestUnion) vnew = {0}; test_xdr((xdrproc_t)xdr_TestUnion, &vorig, &vnew, "union_case", false); } @@ -116,7 +109,7 @@ static void test_union_default(void) TestUnion vorig = { .type = 87539319, .TestUnion_u = { .i3 = 1729 }, }; - TestUnion vnew = {0}; + g_auto(TestUnion) vnew = {0}; test_xdr((xdrproc_t)xdr_TestUnion, &vorig, &vnew, "union_default", false); } @@ -126,7 +119,7 @@ static void test_union_void_default_case(void) TestUnionVoidDefault vorig = { .type = 21, .TestUnionVoidDefault_u = { .i1 = 1729 }, }; - TestUnionVoidDefault vnew = {0}; + g_auto(TestUnionVoidDefault) vnew = {0}; test_xdr((xdrproc_t)xdr_TestUnionVoidDefault, &vorig, &vnew, "union_void_default_case", false); } @@ -136,7 +129,7 @@ static void test_union_void_default_default(void) TestUnionVoidDefault vorig = { .type = 87539319 }; - TestUnionVoidDefault vnew = {0}; + g_auto(TestUnionVoidDefault) vnew = {0}; test_xdr((xdrproc_t)xdr_TestUnionVoidDefault, &vorig, &vnew, "union_void_default_default", false); } @@ -146,7 +139,7 @@ static void test_union_no_default_case(void) TestUnionNoDefault vorig = { .type = 22, .TestUnionNoDefault_u = { .i1 = 1729 }, }; - TestUnionNoDefault vnew = {0}; + g_auto(TestUnionNoDefault) vnew = {0}; test_xdr((xdrproc_t)xdr_TestUnionNoDefault, &vorig, &vnew, "union_no_default_case", false); } @@ -156,7 +149,7 @@ static void test_union_no_default_default(void) TestUnionNoDefault vorig = { .type = 87539319, }; - TestUnionNoDefault vnew = {0}; + g_auto(TestUnionNoDefault) vnew = {0}; test_xdr((xdrproc_t)xdr_TestUnionNoDefault, &vorig, &vnew, "union_no_default_default", true); } @@ -164,7 +157,7 @@ static void test_union_no_default_default(void) static void test_int_scalar(void) { TestIntScalar vorig = 1729; - TestIntScalar vnew = 0; + g_auto(TestIntScalar) vnew = 0; test_xdr((xdrproc_t)xdr_TestIntScalar, &vorig, &vnew, "int_scalar", false); } @@ -173,7 +166,7 @@ static void test_int_pointer_set(void) { int vorigp = 1729; TestIntPointer vorig = &vorigp; - TestIntPointer vnew = NULL; + g_auto(TestIntPointer) vnew = NULL; test_xdr((xdrproc_t)xdr_TestIntPointer, &vorig, &vnew, "int_pointer_set", false); } @@ -181,7 +174,7 @@ static void test_int_pointer_set(void) static void test_int_pointer_null(void) { TestIntPointer vorig = NULL; - TestIntPointer vnew = NULL; + g_auto(TestIntPointer) vnew = NULL; test_xdr((xdrproc_t)xdr_TestIntPointer, &vorig, &vnew, "int_pointer_null", false); } @@ -189,7 +182,7 @@ static void test_int_pointer_null(void) static void test_int_fixed_array(void) { TestIntFixedArray vorig = { 1729, 0, 87539319 }; - TestIntFixedArray vnew = {0}; + g_auto(TestIntFixedArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestIntFixedArray, vorig, vnew, "int_fixed_array", false); @@ -201,7 +194,7 @@ static void test_int_variable_array_set(void) .TestIntVariableArray_len = 3, .TestIntVariableArray_val = (int[]) { 1729, 0, 87539319 } }; - TestIntVariableArray vnew = {0}; + g_auto(TestIntVariableArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestIntVariableArray, &vorig, &vnew, "int_variable_array_set", false); @@ -213,7 +206,7 @@ static void test_int_variable_array_overflow(void) .TestIntVariableArray_len = 6, .TestIntVariableArray_val = (int[]) { 1729, 0, 87539319, 0, 1729 } }; - TestIntVariableArray vnew = {0}; + g_auto(TestIntVariableArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestIntVariableArray, &vorig, &vnew, "int_variable_array_overflow", true); @@ -225,7 +218,7 @@ static void test_int_variable_array_empty(void) .TestIntVariableArray_len = 0, .TestIntVariableArray_val = (int[]) {0}, }; - TestIntVariableArray vnew = {0}; + g_auto(TestIntVariableArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestIntVariableArray, &vorig, &vnew, "int_variable_array_empty", false); @@ -234,7 +227,7 @@ static void test_int_variable_array_empty(void) static void test_string_variable_array_set(void) { TestStringVariableArray vorig = (TestStringVariableArray) "taxis"; - TestStringVariableArray vnew = NULL; + g_auto(TestStringVariableArray) vnew = NULL; test_xdr((xdrproc_t)xdr_TestStringVariableArray, &vorig, &vnew, "string_variable_array_set", false); @@ -243,7 +236,7 @@ static void test_string_variable_array_set(void) static void test_string_variable_array_empty(void) { TestStringVariableArray vorig = (TestStringVariableArray)""; - TestStringVariableArray vnew = NULL; + g_auto(TestStringVariableArray) vnew = NULL; test_xdr((xdrproc_t)xdr_TestStringVariableArray, &vorig, &vnew, "string_variable_array_empty", false); @@ -252,7 +245,7 @@ static void test_string_variable_array_empty(void) static void test_opaque_fixed_array(void) { TestOpaqueFixedArray vorig = { 0xca, 0xfe, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78 }; - TestOpaqueFixedArray vnew = {0}; + g_auto(TestOpaqueFixedArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestOpaqueFixedArray, vorig, vnew, "opaque_fixed_array", false); } @@ -263,7 +256,7 @@ static void test_opaque_variable_array_set(void) .TestOpaqueVariableArray_len = 3, .TestOpaqueVariableArray_val = (char[]) { 0xca, 0xfe, 0x12 }, }; - TestOpaqueVariableArray vnew = {0}; + g_auto(TestOpaqueVariableArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestOpaqueVariableArray, &vorig, &vnew, "opaque_variable_array_set", false); @@ -278,7 +271,7 @@ static void test_opaque_variable_array_overflow(void) 0xca, 0xfe, 0x12, 0xca, 0xfe, 0x12, }, }; - TestOpaqueVariableArray vnew = {0}; + g_auto(TestOpaqueVariableArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestOpaqueVariableArray, &vorig, &vnew, "opaque_variable_array_overflow", true); @@ -290,7 +283,7 @@ static void test_opaque_variable_array_empty(void) .TestOpaqueVariableArray_len = 0, .TestOpaqueVariableArray_val = (char[]) {0}, }; - TestOpaqueVariableArray vnew = {0}; + g_auto(TestOpaqueVariableArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestOpaqueVariableArray, &vorig, &vnew, "opaque_variable_array_empty", false); @@ -299,7 +292,7 @@ static void test_opaque_variable_array_empty(void) static void test_enum_scalar(void) { TestEnumScalar vorig = TEST_ENUM_TWO; - TestEnumScalar vnew = 0; + g_auto(TestEnumScalar) vnew = 0; test_xdr((xdrproc_t)xdr_TestEnumScalar, &vorig, &vnew, "enum_scalar", false); @@ -309,7 +302,7 @@ static void test_enum_pointer_set(void) { TestEnum vorigp = TEST_ENUM_TWO; TestEnumPointer vorig = &vorigp; - TestEnumPointer vnew = NULL; + g_auto(TestEnumPointer) vnew = NULL; test_xdr((xdrproc_t)xdr_TestEnumPointer, &vorig, &vnew, "enum_pointer_set", false); @@ -318,7 +311,7 @@ static void test_enum_pointer_set(void) static void test_enum_pointer_null(void) { TestEnumPointer vorig = NULL; - TestEnumPointer vnew = NULL; + g_auto(TestEnumPointer) vnew = NULL; test_xdr((xdrproc_t)xdr_TestEnumPointer, &vorig, &vnew, "enum_pointer_null", false); @@ -331,7 +324,7 @@ static void test_enum_fixed_array(void) TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE }; - TestEnumFixedArray vnew = {0}; + g_auto(TestEnumFixedArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestEnumFixedArray, vorig, vnew, "enum_fixed_array", false); } @@ -344,7 +337,7 @@ static void test_enum_variable_array_set(void) TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, }, }; - TestEnumVariableArray vnew = {0}; + g_auto(TestEnumVariableArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestEnumVariableArray, &vorig, &vnew, "enum_variable_array_set", false); @@ -361,7 +354,7 @@ static void test_enum_variable_array_overflow(void) TEST_ENUM_ONE, TEST_ENUM_TWO, TEST_ENUM_ONE, TEST_ENUM_TWO, } }; - TestEnumVariableArray vnew = {0}; + g_auto(TestEnumVariableArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestEnumVariableArray, &vorig, &vnew, "enum_variable_array_overflow", true); @@ -373,7 +366,7 @@ static void test_enum_variable_array_empty(void) .TestEnumVariableArray_len = 0, .TestEnumVariableArray_val = (TestEnum[]) {0}, }; - TestEnumVariableArray vnew = {0}; + g_auto(TestEnumVariableArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestEnumVariableArray, &vorig, &vnew, "enum_variable_array_empty", false); @@ -385,7 +378,7 @@ static void test_enum_variable_array_empty(void) static void test_struct_scalar(void) { TestStructScalar vorig = TEST_STRUCT_INIT; - TestStructScalar vnew = {0}; + g_auto(TestStructScalar) vnew = {0}; test_xdr((xdrproc_t)xdr_TestStructScalar, &vorig, &vnew, "struct_scalar", false); @@ -395,7 +388,7 @@ static void test_struct_pointer_set(void) { TestStruct vorigp = TEST_STRUCT_INIT; TestStructPointer vorig = &vorigp; - TestStructPointer vnew = NULL; + g_auto(TestStructPointer) vnew = NULL; test_xdr((xdrproc_t)xdr_TestStructPointer, &vorig, &vnew, "struct_pointer_set", false); @@ -404,7 +397,7 @@ static void test_struct_pointer_set(void) static void test_struct_pointer_null(void) { TestStructPointer vorig = NULL; - TestStructPointer vnew = NULL; + g_auto(TestStructPointer) vnew = NULL; test_xdr((xdrproc_t)xdr_TestStructPointer, &vorig, &vnew, "struct_pointer_null", false); @@ -419,7 +412,7 @@ static void test_struct_fixed_array(void) TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT }; - TestStructFixedArray vnew = {0}; + g_auto(TestStructFixedArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestStructFixedArray, vorig, vnew, "struct_fixed_array", false); } @@ -432,7 +425,7 @@ static void test_struct_variable_array_set(void) TEST_STRUCT_INIT, TEST_STRUCT_INIT_ALT, TEST_STRUCT_INIT_ALT, }, }; - TestStructVariableArray vnew = {0}; + g_auto(TestStructVariableArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestStructVariableArray, &vorig, &vnew, "struct_variable_array_set", false); @@ -450,7 +443,7 @@ static void test_struct_variable_array_overflow(void) TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, TEST_STRUCT_INIT, } }; - TestStructVariableArray vnew = {0}; + g_auto(TestStructVariableArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestStructVariableArray, &vorig, &vnew, "struct_variable_array_overflow", true); @@ -462,7 +455,7 @@ static void test_struct_variable_array_empty(void) .TestStructVariableArray_len = 0, .TestStructVariableArray_val = (TestStruct[]) {}, }; - TestStructVariableArray vnew = {0}; + g_auto(TestStructVariableArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestStructVariableArray, &vorig, &vnew, "struct_variable_array_empty", false); @@ -474,7 +467,7 @@ static void test_struct_variable_array_empty(void) static void test_union_scalar(void) { TestUnionScalar vorig = TEST_UNION_INIT; - TestUnionScalar vnew = {0}; + g_auto(TestUnionScalar) vnew = {0}; test_xdr((xdrproc_t)xdr_TestUnionScalar, &vorig, &vnew, "union_scalar", false); @@ -484,7 +477,7 @@ static void test_union_pointer_set(void) { TestUnion vorigp = TEST_UNION_INIT; TestUnionPointer vorig = &vorigp; - TestUnionPointer vnew = NULL; + g_auto(TestUnionPointer) vnew = NULL; test_xdr((xdrproc_t)xdr_TestUnionPointer, &vorig, &vnew, "union_pointer_set", false); @@ -493,7 +486,7 @@ static void test_union_pointer_set(void) static void test_union_pointer_null(void) { TestUnionPointer vorig = NULL; - TestUnionPointer vnew = NULL; + g_auto(TestUnionPointer) vnew = NULL; test_xdr((xdrproc_t)xdr_TestUnionPointer, &vorig, &vnew, "union_pointer_null", false); @@ -508,7 +501,7 @@ static void test_union_fixed_array(void) TEST_UNION_INIT_ALT, TEST_UNION_INIT_ALT, TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT_ALT }; - TestUnionFixedArray vnew = {0}; + g_auto(TestUnionFixedArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestUnionFixedArray, vorig, vnew, "union_fixed_array", false); } @@ -521,7 +514,7 @@ static void test_union_variable_array_set(void) TEST_UNION_INIT, TEST_UNION_INIT_ALT, TEST_UNION_INIT_ALT, }, }; - TestUnionVariableArray vnew = {0}; + g_auto(TestUnionVariableArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestUnionVariableArray, &vorig, &vnew, "union_variable_array_set", false); @@ -540,7 +533,7 @@ static void test_union_variable_array_overflow(void) TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, TEST_UNION_INIT, } }; - TestUnionVariableArray vnew = {0}; + g_auto(TestUnionVariableArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestUnionVariableArray, &vorig, &vnew, "union_variable_array_overflow", true); @@ -552,7 +545,7 @@ static void test_union_variable_array_empty(void) .TestUnionVariableArray_len = 0, .TestUnionVariableArray_val = (TestUnion[]) {}, }; - TestUnionVariableArray vnew = {0}; + g_auto(TestUnionVariableArray) vnew = {0}; test_xdr((xdrproc_t)xdr_TestUnionVariableArray, &vorig, &vnew, "union_variable_array_empty", false); @@ -720,7 +713,7 @@ static void test_struct_all_types(void) }, }, }; - TestStructAllTypes vnew = {0}; + g_auto(TestStructAllTypes) vnew = {0}; test_xdr((xdrproc_t)xdr_TestStructAllTypes, &vorig, &vnew, "test_struct_all_types", false); diff --git a/scripts/rpcgen/tests/test_generator.py b/scripts/rpcgen/tests/test_generator.py index bc7660a6fc..6660810f41 100644 --- a/scripts/rpcgen/tests/test_generator.py +++ b/scripts/rpcgen/tests/test_generator.py @@ -6,6 +6,7 @@ from pathlib import Path from rpcgen.parser import XDRParser from rpcgen.generator import ( XDRTypeDeclarationGenerator, + XDRTypeImplementationGenerator, XDRMarshallDeclarationGenerator, XDRMarshallImplementationGenerator, ) @@ -42,7 +43,11 @@ def test_generate_source(): parser = XDRParser(fp) spec = parser.parse() - got = XDRMarshallImplementationGenerator(spec).visit() + got = ( + XDRTypeImplementationGenerator(spec).visit() + + "\n" + + XDRMarshallImplementationGenerator(spec).visit() + ) with h.open("r") as fp: want = fp.read() -- 2.39.1

Currently some, but not all, methods have a call to the xdr_free function, for the 'ret' variable. This is done on methods where there are complex structs containing allocated memory. In other cases the structs contain allocated memory, but the pointer is stolen, so xdr_free is not called. In other cases no allocated memory is present, so xdr_free. This is hard to reason about, because the definition of the struct is not visible in the client stubs. Switch to use g_auto() for the 'ret' variable, which means 'xdr_free' is always going to be called. Some places now need to use g_steal_pointer as a result. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/rpc/gendispatch.pl | 60 +++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl index b186849606..e151d33aaa 100755 --- a/src/rpc/gendispatch.pl +++ b/src/rpc/gendispatch.pl @@ -1440,7 +1440,7 @@ elsif ($mode eq "client") { " &args.$1.$1_len,\n" . " VIR_TYPED_PARAM_STRING_OKAY) < 0) {\n" . " xdr_free((xdrproc_t)xdr_$call->{args}, (char *)&args);\n" . - " goto done;\n" . + " goto cleanup;\n" . " }"); push(@free_list, " virTypedParamsRemoteFree((struct _virTypedParameterRemote *) args.params.params_val,\n" . " args.params.params_len);\n"); @@ -1527,7 +1527,7 @@ elsif ($mode eq "client") { if ($rettype eq "void") { $call_ret = "NULL"; } else { - push(@vars_list, "$rettype ret = {0}"); + push(@vars_list, "g_auto($rettype) ret = {0}"); foreach my $ret_member (@{$call->{ret_members}}) { if ($multi_ret) { @@ -1582,12 +1582,11 @@ elsif ($mode eq "client") { # error out on unannotated arrays die "$1_nonnull_string array without insert@<offset> annotation: $ret_member"; } elsif ($ret_member =~ m/^(?:admin|remote)_nonnull_string (\S+);/) { - push(@ret_list, "rv = ret.$1;"); + push(@ret_list, "rv = g_steal_pointer(&ret.$1);"); $single_ret_var = "char *rv = NULL"; $single_ret_type = "char *"; } elsif ($ret_member =~ m/^(?:admin|remote)_string (\S+);/) { - push(@ret_list, "rv = ret.$1 ? *ret.$1 : NULL;"); - push(@ret_list, "VIR_FREE(ret.$1);"); + push(@ret_list, "rv = ret.$1 ? g_steal_pointer(ret.$1) : NULL;"); $single_ret_var = "char *rv = NULL"; $single_ret_type = "char *"; } elsif ($ret_member =~ m/^remote_nonnull_(domain|network|network_port|storage_pool|storage_vol|node_device|interface|secret|nwfilter|nwfilter_binding|domain_checkpoint|domain_snapshot) (\S+);/) { @@ -1599,7 +1598,6 @@ elsif ($mode eq "client") { # SPECIAL: virDomainCreateWithFlags updates the given # domain object instead of returning a new one push(@ret_list, "dom->id = ret.dom.id;"); - push(@ret_list, "xdr_free((xdrproc_t)xdr_$call->{ret}, (char *)&ret);"); push(@ret_list, "rv = 0;"); $single_ret_var = "int rv = -1"; $single_ret_type = "int"; @@ -1612,7 +1610,6 @@ elsif ($mode eq "client") { push(@ret_list, "rv = get_nonnull_$name($priv_src, ret.$arg_name);"); } - push(@ret_list, "xdr_free((xdrproc_t)xdr_$rettype, (char *)&ret);"); $single_ret_var = "vir${type_name}Ptr rv = NULL"; $single_ret_type = "vir${type_name}Ptr"; } @@ -1712,8 +1709,6 @@ elsif ($mode eq "client") { push(@ret_list, "rv = get_nonnull_$name($priv_src, ret.$arg_name);"); } - push(@ret_list, "xdr_free((xdrproc_t)xdr_$rettype, (char *)&ret);"); - $single_ret_var = "virAdm${type_name}Ptr rv = NULL"; $single_ret_type = "virAdm${type_name}Ptr"; } elsif ($ret_member =~ m/^(\/)?\*/) { @@ -1820,11 +1815,11 @@ elsif ($mode eq "client") { if ($call->{streamflag} ne "none") { print "\n"; print " if (!(netst = virNetClientStreamNew(priv->remoteProgram, $call->{constname}, priv->counter, sparse)))\n"; - print " goto done;\n"; + print " goto cleanup;\n"; print "\n"; print " if (virNetClientAddStream(priv->client, netst) < 0) {\n"; print " virObjectUnref(netst);\n"; - print " goto done;\n"; + print " goto cleanup;\n"; print " }"; print "\n"; print " st->driver = &remoteStreamDrv;\n"; @@ -1837,7 +1832,7 @@ elsif ($mode eq "client") { print "\n"; print " if (feature == VIR_DRV_FEATURE_REMOTE) {\n"; print " rv = 1;\n"; - print " goto done;\n"; + print " goto cleanup;\n"; print " }\n"; } @@ -1847,7 +1842,7 @@ elsif ($mode eq "client") { print " virReportError(VIR_ERR_RPC,\n"; print " _(\"%s length greater than maximum: %d > %d\"),\n"; print " $args_check->{name}, (int)$args_check->{arg}, $args_check->{limit});\n"; - print " goto done;\n"; + print " goto cleanup;\n"; print " }\n"; } @@ -1858,7 +1853,7 @@ elsif ($mode eq "client") { print " _(\"too many remote ${single_ret_list_error_msg_type}s: %d > %d,\"\n"; print " \"in parameter '$single_ret_list_name' for 'vir$call->{ProcName}'\"),\n"; print " $single_ret_list_max_var, $single_ret_list_max_define);\n"; - print " goto done;\n"; + print " goto cleanup;\n"; print " }\n"; } @@ -1909,7 +1904,7 @@ elsif ($mode eq "client") { print " st->privateData = NULL;\n"; } - print " goto done;\n"; + print " goto cleanup;\n"; print " }\n"; print "\n"; @@ -1982,29 +1977,22 @@ elsif ($mode eq "client") { } } - if ($single_ret_as_list or $single_ret_cleanup or $modern_ret_as_list) { + print "\n"; + print "cleanup:\n"; + if (@custom_error_cleanup) { + print " if (rv != 0) {\n"; + print " "; + print join("\n ", @custom_error_cleanup); + print " }\n"; + } + if ($modern_ret_as_list) { + print " if (tmp_results) {\n"; + print " for (i = 0; i < ret.$single_ret_list_name.${single_ret_list_name}_len; i++)\n"; + print " virObjectUnref(tmp_results[i]);\n"; + print " VIR_FREE(tmp_results);\n"; + print " }\n"; print "\n"; - print "cleanup:\n"; - if (@custom_error_cleanup) { - print " if (rv != 0) {\n"; - print " "; - print join("\n ", @custom_error_cleanup); - print " }\n"; - } - if ($modern_ret_as_list) { - print " if (tmp_results) {\n"; - print " for (i = 0; i < ret.$single_ret_list_name.${single_ret_list_name}_len; i++)\n"; - print " virObjectUnref(tmp_results[i]);\n"; - print " VIR_FREE(tmp_results);\n"; - print " }\n"; - print "\n"; - } - print " xdr_free((xdrproc_t)xdr_$call->{ret}, (char *)&ret);\n"; } - - print "\n"; - print "done:\n"; - print join("\n", @free_list); print " return rv;\n"; -- 2.39.1

Currently some, but not all, methods have a call to the xdr_free function, for the 'ret' variable. This is done on methods where there are complex structs containing allocated memory. In other cases the structs contain allocated memory, but the pointer is stolen, so xdr_free is not called. In other cases no allocated memory is present, so xdr_free. This is hard to reason about, because the definition of the struct is not visible in the client stubs. Switch to use g_auto() for the 'ret' variable, which means 'xdr_free' is always going to be called. Some places now need to use g_steal_pointer as a result. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/admin/admin_remote.c | 50 +++++++++++----------------------------- 1 file changed, 14 insertions(+), 36 deletions(-) diff --git a/src/admin/admin_remote.c b/src/admin/admin_remote.c index 3ae20ff373..3291a1e965 100644 --- a/src/admin/admin_remote.c +++ b/src/admin/admin_remote.c @@ -229,10 +229,9 @@ remoteAdminServerGetThreadPoolParameters(virAdmServerPtr srv, int *nparams, unsigned int flags) { - int rv = -1; remoteAdminPriv *priv = srv->conn->privateData; admin_server_get_threadpool_parameters_args args; - admin_server_get_threadpool_parameters_ret ret = {0}; + g_auto(admin_server_get_threadpool_parameters_ret) ret = {0}; VIR_LOCK_GUARD lock = virObjectLockGuard(priv); args.flags = flags; @@ -248,13 +247,9 @@ remoteAdminServerGetThreadPoolParameters(virAdmServerPtr srv, ADMIN_SERVER_THREADPOOL_PARAMETERS_MAX, params, nparams) < 0) - goto cleanup; - - rv = 0; + return -1; - cleanup: - xdr_free((xdrproc_t)xdr_admin_server_get_threadpool_parameters_ret, (char *) &ret); - return rv; + return 0; } static int @@ -297,10 +292,9 @@ remoteAdminClientGetInfo(virAdmClientPtr client, int *nparams, unsigned int flags) { - int rv = -1; remoteAdminPriv *priv = client->srv->conn->privateData; admin_client_get_info_args args; - admin_client_get_info_ret ret = {0}; + g_auto(admin_client_get_info_ret) ret = {0}; VIR_LOCK_GUARD lock = virObjectLockGuard(priv); args.flags = flags; @@ -316,13 +310,9 @@ remoteAdminClientGetInfo(virAdmClientPtr client, ADMIN_CLIENT_INFO_PARAMETERS_MAX, params, nparams) < 0) - goto cleanup; - - rv = 0; + return -1; - cleanup: - xdr_free((xdrproc_t)xdr_admin_client_get_info_ret, (char *) &ret); - return rv; + return 0; } static int @@ -331,9 +321,8 @@ remoteAdminServerGetClientLimits(virAdmServerPtr srv, int *nparams, unsigned int flags) { - int rv = -1; admin_server_get_client_limits_args args; - admin_server_get_client_limits_ret ret = {0}; + g_auto(admin_server_get_client_limits_ret) ret = {0}; remoteAdminPriv *priv = srv->conn->privateData; VIR_LOCK_GUARD lock = virObjectLockGuard(priv); @@ -352,14 +341,9 @@ remoteAdminServerGetClientLimits(virAdmServerPtr srv, ADMIN_SERVER_CLIENT_LIMITS_MAX, params, nparams) < 0) - goto cleanup; - - rv = 0; + return -1; - cleanup: - xdr_free((xdrproc_t) xdr_admin_server_get_client_limits_ret, - (char *) &ret); - return rv; + return 0; } static int @@ -401,10 +385,9 @@ remoteAdminConnectGetLoggingOutputs(virAdmConnectPtr conn, char **outputs, unsigned int flags) { - int rv = -1; remoteAdminPriv *priv = conn->privateData; admin_connect_get_logging_outputs_args args; - admin_connect_get_logging_outputs_ret ret = {0}; + g_auto(admin_connect_get_logging_outputs_ret) ret = {0}; VIR_LOCK_GUARD lock = virObjectLockGuard(priv); args.flags = flags; @@ -421,9 +404,7 @@ remoteAdminConnectGetLoggingOutputs(virAdmConnectPtr conn, if (outputs) *outputs = g_steal_pointer(&ret.outputs); - rv = ret.noutputs; - xdr_free((xdrproc_t) xdr_admin_connect_get_logging_outputs_ret, (char *) &ret); - return rv; + return ret.noutputs; } static int @@ -431,10 +412,9 @@ remoteAdminConnectGetLoggingFilters(virAdmConnectPtr conn, char **filters, unsigned int flags) { - int rv = -1; remoteAdminPriv *priv = conn->privateData; admin_connect_get_logging_filters_args args; - admin_connect_get_logging_filters_ret ret = {0}; + g_auto(admin_connect_get_logging_filters_ret) ret = {0}; VIR_LOCK_GUARD lock = virObjectLockGuard(priv); args.flags = flags; @@ -449,9 +429,7 @@ remoteAdminConnectGetLoggingFilters(virAdmConnectPtr conn, return -1; if (filters) - *filters = ret.filters ? *ret.filters : NULL; + *filters = ret.filters ? g_steal_pointer(ret.filters) : NULL; - rv = ret.nfilters; - VIR_FREE(ret.filters); - return rv; + return ret.nfilters; } -- 2.39.1

Currently some, but not all, methods have a call to the xdr_free function, for the 'ret' variable. This is done on methods where there are complex structs containing allocated memory. In other cases the structs contain allocated memory, but the pointer is stolen, so xdr_free is not called. In other cases no allocated memory is present, so xdr_free. This is hard to reason about, because the definition of the struct is not visible in the client stubs. Switch to use g_auto() for the 'ret' variable, which means 'xdr_free' is always going to be called. Some places now need to use g_steal_pointer as a result. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/remote/remote_driver.c | 754 +++++++++++-------------------------- 1 file changed, 230 insertions(+), 524 deletions(-) diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index a4c60be3d7..02a687a700 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -683,7 +683,7 @@ remoteConnectSupportsFeatureUnlocked(virConnectPtr conn, int feature) { remote_connect_supports_feature_args args = { feature }; - remote_connect_supports_feature_ret ret = { 0 }; + g_auto(remote_connect_supports_feature_ret) ret = { 0 }; int rc; rc = call(conn, priv, 0, REMOTE_PROC_CONNECT_SUPPORTS_FEATURE, @@ -1386,7 +1386,7 @@ remoteConnectClose(virConnectPtr conn) static const char * remoteConnectGetType(virConnectPtr conn) { - remote_connect_get_type_ret ret = {0}; + g_auto(remote_connect_get_type_ret) ret = {0}; struct private_data *priv = conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -1407,7 +1407,7 @@ remoteConnectGetType(virConnectPtr conn) static int remoteConnectIsSecure(virConnectPtr conn) { struct private_data *priv = conn->privateData; - remote_connect_is_secure_ret ret = {0}; + g_auto(remote_connect_is_secure_ret) ret = {0}; VIR_LOCK_GUARD lock = remoteDriverLock(priv); if (call(conn, priv, 0, REMOTE_PROC_CONNECT_IS_SECURE, @@ -1430,7 +1430,7 @@ static int remoteConnectIsEncrypted(virConnectPtr conn) { bool encrypted; struct private_data *priv = conn->privateData; - remote_connect_is_secure_ret ret = {0}; + g_auto(remote_connect_is_secure_ret) ret = {0}; VIR_LOCK_GUARD lock = remoteDriverLock(priv); if (call(conn, priv, 0, REMOTE_PROC_CONNECT_IS_SECURE, @@ -1457,9 +1457,8 @@ remoteNodeGetCPUStats(virConnectPtr conn, virNodeCPUStatsPtr params, int *nparams, unsigned int flags) { - int rv = -1; remote_node_get_cpu_stats_args args = {0}; - remote_node_get_cpu_stats_ret ret = {0}; + g_auto(remote_node_get_cpu_stats_ret) ret = {0}; size_t i; struct private_data *priv = conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -1481,15 +1480,14 @@ remoteNodeGetCPUStats(virConnectPtr conn, virReportError(VIR_ERR_RPC, "%s", _("remoteNodeGetCPUStats: " "returned number of stats exceeds limit")); - goto cleanup; + return -1; } /* Handle the case when the caller does not know the number of stats * and is asking for the number of stats supported */ if (*nparams == 0) { *nparams = ret.nparams; - rv = 0; - goto cleanup; + return 0; } *nparams = ret.params.params_len; @@ -1500,16 +1498,12 @@ remoteNodeGetCPUStats(virConnectPtr conn, virReportError(VIR_ERR_INTERNAL_ERROR, _("Stats %s too big for destination"), ret.params.params_val[i].field); - goto cleanup; + return -1; } params[i].value = ret.params.params_val[i].value; } - rv = 0; - - cleanup: - xdr_free((xdrproc_t) xdr_remote_node_get_cpu_stats_ret, (char *) &ret); - return rv; + return 0; } static int @@ -1519,9 +1513,8 @@ remoteNodeGetMemoryStats(virConnectPtr conn, int *nparams, unsigned int flags) { - int rv = -1; remote_node_get_memory_stats_args args = {0}; - remote_node_get_memory_stats_ret ret = {0}; + g_auto(remote_node_get_memory_stats_ret) ret = {0}; size_t i; struct private_data *priv = conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -1541,15 +1534,14 @@ remoteNodeGetMemoryStats(virConnectPtr conn, virReportError(VIR_ERR_RPC, "%s", _("remoteNodeGetMemoryStats: " "returned number of stats exceeds limit")); - goto cleanup; + return -1; } /* Handle the case when the caller does not know the number of stats * and is asking for the number of stats supported */ if (*nparams == 0) { *nparams = ret.nparams; - rv = 0; - goto cleanup; + return 0; } *nparams = ret.params.params_len; @@ -1560,16 +1552,12 @@ remoteNodeGetMemoryStats(virConnectPtr conn, virReportError(VIR_ERR_INTERNAL_ERROR, _("Stats %s too big for destination"), ret.params.params_val[i].field); - goto cleanup; + return -1; } params[i].value = ret.params.params_val[i].value; } - rv = 0; - - cleanup: - xdr_free((xdrproc_t) xdr_remote_node_get_memory_stats_ret, (char *) &ret); - return rv; + return 0; } static int @@ -1579,7 +1567,7 @@ remoteNodeGetCellsFreeMemory(virConnectPtr conn, int maxCells) { remote_node_get_cells_free_memory_args args = {0}; - remote_node_get_cells_free_memory_ret ret = {0}; + g_auto(remote_node_get_cells_free_memory_ret) ret = {0}; size_t i; struct private_data *priv = conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -1602,18 +1590,15 @@ remoteNodeGetCellsFreeMemory(virConnectPtr conn, for (i = 0; i < ret.cells.cells_len; i++) freeMems[i] = ret.cells.cells_val[i]; - xdr_free((xdrproc_t) xdr_remote_node_get_cells_free_memory_ret, (char *) &ret); - return ret.cells.cells_len; } static int remoteConnectListDomains(virConnectPtr conn, int *ids, int maxids) { - int rv = -1; size_t i; remote_connect_list_domains_args args = {0}; - remote_connect_list_domains_ret ret = {0}; + g_auto(remote_connect_list_domains_ret) ret = {0}; struct private_data *priv = conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -1634,17 +1619,13 @@ remoteConnectListDomains(virConnectPtr conn, int *ids, int maxids) virReportError(VIR_ERR_RPC, _("Too many domains '%d' for limit '%d'"), ret.ids.ids_len, maxids); - goto cleanup; + return -1; } for (i = 0; i < ret.ids.ids_len; ++i) ids[i] = ret.ids.ids_val[i]; - rv = ret.ids.ids_len; - - cleanup: - xdr_free((xdrproc_t) xdr_remote_connect_list_domains_ret, (char *) &ret); - return rv; + return ret.ids.ids_len; } static int @@ -1684,9 +1665,8 @@ remoteDomainBlockStatsFlags(virDomainPtr domain, int *nparams, unsigned int flags) { - int rv = -1; remote_domain_block_stats_flags_args args = {0}; - remote_domain_block_stats_flags_ret ret = {0}; + g_auto(remote_domain_block_stats_flags_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -1706,7 +1686,7 @@ remoteDomainBlockStatsFlags(virDomainPtr domain, virReportError(VIR_ERR_RPC, "%s", _("remoteDomainBlockStatsFlags: " "returned number of stats exceeds limit")); - goto cleanup; + return -1; } /* Handle the case when the caller does not know the number of stats @@ -1714,8 +1694,7 @@ remoteDomainBlockStatsFlags(virDomainPtr domain, */ if (*nparams == 0) { *nparams = ret.nparams; - rv = 0; - goto cleanup; + return 0; } *nparams = ret.params.params_len; @@ -1726,14 +1705,9 @@ remoteDomainBlockStatsFlags(virDomainPtr domain, REMOTE_DOMAIN_BLOCK_STATS_PARAMETERS_MAX, ¶ms, nparams) < 0) - goto cleanup; - - rv = 0; + return -1; - cleanup: - xdr_free((xdrproc_t) xdr_remote_domain_block_stats_flags_ret, - (char *) &ret); - return rv; + return 0; } static int @@ -1741,9 +1715,8 @@ remoteDomainGetMemoryParameters(virDomainPtr domain, virTypedParameterPtr params, int *nparams, unsigned int flags) { - int rv = -1; remote_domain_get_memory_parameters_args args = {0}; - remote_domain_get_memory_parameters_ret ret = {0}; + g_auto(remote_domain_get_memory_parameters_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -1761,8 +1734,7 @@ remoteDomainGetMemoryParameters(virDomainPtr domain, */ if (*nparams == 0) { *nparams = ret.nparams; - rv = 0; - goto cleanup; + return 0; } if (virTypedParamsDeserialize((struct _virTypedParameterRemote *) ret.params.params_val, @@ -1770,14 +1742,9 @@ remoteDomainGetMemoryParameters(virDomainPtr domain, REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX, ¶ms, nparams) < 0) - goto cleanup; - - rv = 0; + return -1; - cleanup: - xdr_free((xdrproc_t) xdr_remote_domain_get_memory_parameters_ret, - (char *) &ret); - return rv; + return 0; } static int @@ -1785,9 +1752,8 @@ remoteDomainGetNumaParameters(virDomainPtr domain, virTypedParameterPtr params, int *nparams, unsigned int flags) { - int rv = -1; remote_domain_get_numa_parameters_args args = {0}; - remote_domain_get_numa_parameters_ret ret = {0}; + g_auto(remote_domain_get_numa_parameters_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -1805,8 +1771,7 @@ remoteDomainGetNumaParameters(virDomainPtr domain, */ if (*nparams == 0) { *nparams = ret.nparams; - rv = 0; - goto cleanup; + return 0; } if (virTypedParamsDeserialize((struct _virTypedParameterRemote *) ret.params.params_val, @@ -1814,14 +1779,9 @@ remoteDomainGetNumaParameters(virDomainPtr domain, REMOTE_DOMAIN_NUMA_PARAMETERS_MAX, ¶ms, nparams) < 0) - goto cleanup; - - rv = 0; + return -1; - cleanup: - xdr_free((xdrproc_t) xdr_remote_domain_get_numa_parameters_ret, - (char *) &ret); - return rv; + return 0; } static int @@ -1830,9 +1790,8 @@ remoteDomainGetLaunchSecurityInfo(virDomainPtr domain, int *nparams, unsigned int flags) { - int rv = -1; remote_domain_get_launch_security_info_args args = {0}; - remote_domain_get_launch_security_info_ret ret = {0}; + g_auto(remote_domain_get_launch_security_info_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -1849,14 +1808,9 @@ remoteDomainGetLaunchSecurityInfo(virDomainPtr domain, REMOTE_DOMAIN_LAUNCH_SECURITY_INFO_PARAMS_MAX, params, nparams) < 0) - goto cleanup; - - rv = 0; + return -1; - cleanup: - xdr_free((xdrproc_t) xdr_remote_domain_get_launch_security_info_ret, - (char *) &ret); - return rv; + return 0; } static int @@ -1865,9 +1819,8 @@ remoteDomainGetPerfEvents(virDomainPtr domain, int *nparams, unsigned int flags) { - int rv = -1; remote_domain_get_perf_events_args args = {0}; - remote_domain_get_perf_events_ret ret = {0}; + g_auto(remote_domain_get_perf_events_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -1884,14 +1837,9 @@ remoteDomainGetPerfEvents(virDomainPtr domain, REMOTE_DOMAIN_PERF_EVENTS_MAX, params, nparams) < 0) - goto cleanup; - - rv = 0; + return -1; - cleanup: - xdr_free((xdrproc_t) xdr_remote_domain_get_perf_events_ret, - (char *) &ret); - return rv; + return 0; } static int @@ -1899,9 +1847,8 @@ remoteDomainGetBlkioParameters(virDomainPtr domain, virTypedParameterPtr params, int *nparams, unsigned int flags) { - int rv = -1; remote_domain_get_blkio_parameters_args args = {0}; - remote_domain_get_blkio_parameters_ret ret = {0}; + g_auto(remote_domain_get_blkio_parameters_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -1919,8 +1866,7 @@ remoteDomainGetBlkioParameters(virDomainPtr domain, */ if (*nparams == 0) { *nparams = ret.nparams; - rv = 0; - goto cleanup; + return 0; } if (virTypedParamsDeserialize((struct _virTypedParameterRemote *) ret.params.params_val, @@ -1928,14 +1874,9 @@ remoteDomainGetBlkioParameters(virDomainPtr domain, REMOTE_DOMAIN_BLKIO_PARAMETERS_MAX, ¶ms, nparams) < 0) - goto cleanup; - - rv = 0; + return -1; - cleanup: - xdr_free((xdrproc_t) xdr_remote_domain_get_blkio_parameters_ret, - (char *) &ret); - return rv; + return 0; } static int @@ -1945,10 +1886,9 @@ remoteDomainGetVcpuPinInfo(virDomainPtr domain, int maplen, unsigned int flags) { - int rv = -1; size_t i; remote_domain_get_vcpu_pin_info_args args = {0}; - remote_domain_get_vcpu_pin_info_ret ret = {0}; + g_auto(remote_domain_get_vcpu_pin_info_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -1983,14 +1923,14 @@ remoteDomainGetVcpuPinInfo(virDomainPtr domain, virReportError(VIR_ERR_RPC, _("host reports too many vCPUs: %d > %d"), ret.num, ncpumaps); - goto cleanup; + return -1; } if (ret.cpumaps.cpumaps_len > ncpumaps * maplen) { virReportError(VIR_ERR_RPC, _("host reports map buffer length exceeds maximum: %d > %d"), ret.cpumaps.cpumaps_len, ncpumaps * maplen); - goto cleanup; + return -1; } memset(cpumaps, 0, ncpumaps * maplen); @@ -1998,11 +1938,7 @@ remoteDomainGetVcpuPinInfo(virDomainPtr domain, for (i = 0; i < ret.cpumaps.cpumaps_len; ++i) cpumaps[i] = ret.cpumaps.cpumaps_val[i]; - rv = ret.num; - - cleanup: - xdr_free((xdrproc_t) xdr_remote_domain_get_vcpu_pin_info_ret, (char *) &ret); - return rv; + return ret.num; } static int @@ -2043,10 +1979,9 @@ remoteDomainGetEmulatorPinInfo(virDomainPtr domain, int maplen, unsigned int flags) { - int rv = -1; size_t i; remote_domain_get_emulator_pin_info_args args = {0}; - remote_domain_get_emulator_pin_info_ret ret = {0}; + g_auto(remote_domain_get_emulator_pin_info_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -2073,7 +2008,7 @@ remoteDomainGetEmulatorPinInfo(virDomainPtr domain, virReportError(VIR_ERR_RPC, _("host reports map buffer length exceeds maximum: %d > %d"), ret.cpumaps.cpumaps_len, maplen); - goto cleanup; + return -1; } memset(cpumaps, 0, maplen); @@ -2081,12 +2016,7 @@ remoteDomainGetEmulatorPinInfo(virDomainPtr domain, for (i = 0; i < ret.cpumaps.cpumaps_len; ++i) cpumaps[i] = ret.cpumaps.cpumaps_val[i]; - rv = ret.ret; - - cleanup: - xdr_free((xdrproc_t) xdr_remote_domain_get_emulator_pin_info_ret, - (char *) &ret); - return rv; + return ret.ret; } static int @@ -2096,10 +2026,9 @@ remoteDomainGetVcpus(virDomainPtr domain, unsigned char *cpumaps, int maplen) { - int rv = -1; size_t i; remote_domain_get_vcpus_args args = {0}; - remote_domain_get_vcpus_ret ret = {0}; + g_auto(remote_domain_get_vcpus_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -2130,13 +2059,13 @@ remoteDomainGetVcpus(virDomainPtr domain, virReportError(VIR_ERR_RPC, _("host reports too many vCPUs: %d > %d"), ret.info.info_len, maxinfo); - goto cleanup; + return -1; } if (ret.cpumaps.cpumaps_len > maxinfo * maplen) { virReportError(VIR_ERR_RPC, _("host reports map buffer length exceeds maximum: %d > %d"), ret.cpumaps.cpumaps_len, maxinfo * maplen); - goto cleanup; + return -1; } memset(info, 0, sizeof(virVcpuInfo) * maxinfo); @@ -2152,11 +2081,7 @@ remoteDomainGetVcpus(virDomainPtr domain, for (i = 0; i < ret.cpumaps.cpumaps_len; ++i) cpumaps[i] = ret.cpumaps.cpumaps_val[i]; - rv = ret.info.info_len; - - cleanup: - xdr_free((xdrproc_t) xdr_remote_domain_get_vcpus_ret, (char *) &ret); - return rv; + return ret.info.info_len; } static int @@ -2164,11 +2089,10 @@ remoteDomainGetIOThreadInfo(virDomainPtr dom, virDomainIOThreadInfoPtr **info, unsigned int flags) { - int rv = -1; size_t i; struct private_data *priv = dom->conn->privateData; remote_domain_get_iothread_info_args args = {0}; - remote_domain_get_iothread_info_ret ret = {0}; + g_auto(remote_domain_get_iothread_info_ret) ret = {0}; remote_domain_iothread_info *src; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -2187,7 +2111,7 @@ remoteDomainGetIOThreadInfo(virDomainPtr dom, virReportError(VIR_ERR_INTERNAL_ERROR, _("Too many IOThreads in info: %d for limit %d"), ret.info.info_len, REMOTE_IOTHREAD_INFO_MAX); - goto cleanup; + return -1; } if (info) { @@ -2195,8 +2119,7 @@ remoteDomainGetIOThreadInfo(virDomainPtr dom, if (!ret.info.info_len) { *info = NULL; - rv = ret.ret; - goto cleanup; + return ret.ret; } info_ret = g_new0(virDomainIOThreadInfoPtr, ret.info.info_len); @@ -2215,21 +2138,15 @@ remoteDomainGetIOThreadInfo(virDomainPtr dom, *info = info_ret; } - rv = ret.ret; - - cleanup: - xdr_free((xdrproc_t)xdr_remote_domain_get_iothread_info_ret, - (char *) &ret); - return rv; + return ret.ret; } static int remoteDomainGetSecurityLabel(virDomainPtr domain, virSecurityLabelPtr seclabel) { remote_domain_get_security_label_args args = {0}; - remote_domain_get_security_label_ret ret = {0}; + g_auto(remote_domain_get_security_label_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; - int rv = -1; VIR_LOCK_GUARD lock = remoteDriverLock(priv); make_nonnull_domain(&args.dom, domain); @@ -2244,26 +2161,21 @@ remoteDomainGetSecurityLabel(virDomainPtr domain, virSecurityLabelPtr seclabel) if (virStrcpyStatic(seclabel->label, ret.label.label_val) < 0) { virReportError(VIR_ERR_RPC, _("security label exceeds maximum: %zu"), sizeof(seclabel->label) - 1); - goto cleanup; + return -1; } seclabel->enforcing = ret.enforcing; } - rv = 0; - - cleanup: - xdr_free((xdrproc_t) xdr_remote_domain_get_security_label_ret, (char *)&ret); - return rv; + return 0; } static int remoteDomainGetSecurityLabelList(virDomainPtr domain, virSecurityLabelPtr* seclabels) { remote_domain_get_security_label_list_args args = {0}; - remote_domain_get_security_label_list_ret ret = {0}; + g_auto(remote_domain_get_security_label_list_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; size_t i; - int rv = -1; VIR_LOCK_GUARD lock = remoteDriverLock(priv); make_nonnull_domain(&args.dom, domain); @@ -2282,16 +2194,12 @@ remoteDomainGetSecurityLabelList(virDomainPtr domain, virSecurityLabelPtr* secla virReportError(VIR_ERR_RPC, _("security label exceeds maximum: %zd"), sizeof((*seclabels)->label) - 1); VIR_FREE(*seclabels); - goto cleanup; + return -1; } (*seclabels)[i].enforcing = cur->enforcing; } } - rv = ret.ret; - - cleanup: - xdr_free((xdrproc_t) xdr_remote_domain_get_security_label_list_ret, (char *)&ret); - return rv; + return ret.ret; } static int @@ -2301,7 +2209,7 @@ remoteDomainGetState(virDomainPtr domain, unsigned int flags) { remote_domain_get_state_args args = {0}; - remote_domain_get_state_ret ret = {0}; + g_auto(remote_domain_get_state_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -2323,9 +2231,8 @@ remoteDomainGetState(virDomainPtr domain, static int remoteNodeGetSecurityModel(virConnectPtr conn, virSecurityModelPtr secmodel) { - remote_node_get_security_model_ret ret = {0}; + g_auto(remote_node_get_security_model_ret) ret = {0}; struct private_data *priv = conn->privateData; - int rv = -1; VIR_LOCK_GUARD lock = remoteDriverLock(priv); memset(secmodel, 0, sizeof(*secmodel)); @@ -2339,7 +2246,7 @@ remoteNodeGetSecurityModel(virConnectPtr conn, virSecurityModelPtr secmodel) if (virStrcpyStatic(secmodel->model, ret.model.model_val) < 0) { virReportError(VIR_ERR_RPC, _("security model exceeds maximum: %zu"), sizeof(secmodel->model) - 1); - goto cleanup; + return -1; } } @@ -2347,15 +2254,11 @@ remoteNodeGetSecurityModel(virConnectPtr conn, virSecurityModelPtr secmodel) if (virStrcpyStatic(secmodel->doi, ret.doi.doi_val) < 0) { virReportError(VIR_ERR_RPC, _("security doi exceeds maximum: %zu"), sizeof(secmodel->doi) - 1); - goto cleanup; + return -1; } } - rv = 0; - - cleanup: - xdr_free((xdrproc_t) xdr_remote_node_get_security_model_ret, (char *)&ret); - return rv; + return 0; } static int @@ -2366,7 +2269,7 @@ remoteDomainMigratePrepare(virConnectPtr dconn, unsigned long resource) { remote_domain_migrate_prepare_args args = {0}; - remote_domain_migrate_prepare_ret ret = {0}; + g_auto(remote_domain_migrate_prepare_ret) ret = {0}; struct private_data *priv = dconn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -2381,11 +2284,12 @@ remoteDomainMigratePrepare(virConnectPtr dconn, return -1; if (ret.cookie.cookie_len > 0) { - *cookie = ret.cookie.cookie_val; /* Caller frees. */ + *cookie = g_steal_pointer(&ret.cookie.cookie_val); /* Caller frees. */ *cookielen = ret.cookie.cookie_len; + ret.cookie.cookie_len = 0; } if (ret.uri_out) - *uri_out = *ret.uri_out; /* Caller frees. */ + *uri_out = g_steal_pointer(ret.uri_out); /* Caller frees. */ VIR_FREE(ret.uri_out); return 0; @@ -2399,9 +2303,8 @@ remoteDomainMigratePrepare2(virConnectPtr dconn, unsigned long resource, const char *dom_xml) { - int rv = -1; remote_domain_migrate_prepare2_args args = {0}; - remote_domain_migrate_prepare2_ret ret = {0}; + g_auto(remote_domain_migrate_prepare2_ret) ret = {0}; struct private_data *priv = dconn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -2420,31 +2323,21 @@ remoteDomainMigratePrepare2(virConnectPtr dconn, if (!cookie || !cookielen) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("caller ignores cookie or cookielen")); - goto error; + return -1; } - *cookie = ret.cookie.cookie_val; /* Caller frees. */ + *cookie = g_steal_pointer(&ret.cookie.cookie_val); /* Caller frees. */ *cookielen = ret.cookie.cookie_len; } if (ret.uri_out) { if (!uri_out) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("caller ignores uri_out")); - goto error; + return -1; } - *uri_out = *ret.uri_out; /* Caller frees. */ + *uri_out = g_steal_pointer(ret.uri_out); /* Caller frees. */ } - rv = 0; - - done: - VIR_FREE(ret.uri_out); - return rv; - error: - if (ret.cookie.cookie_len) - VIR_FREE(ret.cookie.cookie_val); - if (ret.uri_out) - VIR_FREE(*ret.uri_out); - goto done; + return 0; } static int @@ -2452,7 +2345,7 @@ remoteDomainCreate(virDomainPtr domain) { remote_domain_create_args args = {0}; remote_domain_lookup_by_uuid_args args2 = {0}; - remote_domain_lookup_by_uuid_ret ret2 = {0}; + g_auto(remote_domain_lookup_by_uuid_ret) ret2 = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -2474,7 +2367,6 @@ remoteDomainCreate(virDomainPtr domain) return -1; domain->id = ret2.dom.id; - xdr_free((xdrproc_t) &xdr_remote_domain_lookup_by_uuid_ret, (char *) &ret2); return 0; } @@ -2483,7 +2375,7 @@ static char * remoteDomainGetSchedulerType(virDomainPtr domain, int *nparams) { remote_domain_get_scheduler_type_args args = {0}; - remote_domain_get_scheduler_type_ret ret = {0}; + g_auto(remote_domain_get_scheduler_type_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -2497,7 +2389,7 @@ remoteDomainGetSchedulerType(virDomainPtr domain, int *nparams) if (nparams) *nparams = ret.nparams; /* Caller frees this. */ - return ret.type; + return g_steal_pointer(&ret.type); } static int @@ -2506,9 +2398,8 @@ remoteDomainMemoryStats(virDomainPtr domain, unsigned int nr_stats, unsigned int flags) { - int rv = -1; remote_domain_memory_stats_args args = {0}; - remote_domain_memory_stats_ret ret = {0}; + g_auto(remote_domain_memory_stats_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; size_t i; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -2534,10 +2425,7 @@ remoteDomainMemoryStats(virDomainPtr domain, stats[i].tag = ret.stats.stats_val[i].tag; stats[i].val = ret.stats.stats_val[i].val; } - rv = ret.stats.stats_len; - xdr_free((xdrproc_t) xdr_remote_domain_memory_stats_ret, (char *) &ret); - - return rv; + return ret.stats.stats_len; } static int @@ -2548,9 +2436,8 @@ remoteDomainBlockPeek(virDomainPtr domain, void *buffer, unsigned int flags) { - int rv = -1; remote_domain_block_peek_args args = {0}; - remote_domain_block_peek_ret ret = {0}; + g_auto(remote_domain_block_peek_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -2577,15 +2464,11 @@ remoteDomainBlockPeek(virDomainPtr domain, if (ret.buffer.buffer_len != size) { virReportError(VIR_ERR_RPC, "%s", _("returned buffer is not same size as requested")); - goto cleanup; + return -1; } memcpy(buffer, ret.buffer.buffer_val, size); - rv = 0; - - cleanup: - VIR_FREE(ret.buffer.buffer_val); - return rv; + return 0; } static int @@ -2595,9 +2478,8 @@ remoteDomainMemoryPeek(virDomainPtr domain, void *buffer, unsigned int flags) { - int rv = -1; remote_domain_memory_peek_args args = {0}; - remote_domain_memory_peek_ret ret = {0}; + g_auto(remote_domain_memory_peek_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -2623,16 +2505,11 @@ remoteDomainMemoryPeek(virDomainPtr domain, if (ret.buffer.buffer_len != size) { virReportError(VIR_ERR_RPC, "%s", _("returned buffer is not same size as requested")); - goto cleanup; + return -1; } memcpy(buffer, ret.buffer.buffer_val, size); - rv = 0; - - cleanup: - VIR_FREE(ret.buffer.buffer_val); - - return rv; + return 0; } static int remoteDomainGetBlockJobInfo(virDomainPtr domain, @@ -2641,7 +2518,7 @@ static int remoteDomainGetBlockJobInfo(virDomainPtr domain, unsigned int flags) { remote_domain_get_block_job_info_args args = {0}; - remote_domain_get_block_job_info_ret ret = {0}; + g_auto(remote_domain_get_block_job_info_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -2673,9 +2550,8 @@ static int remoteDomainGetBlockIoTune(virDomainPtr domain, int *nparams, unsigned int flags) { - int rv = -1; remote_domain_get_block_io_tune_args args = {0}; - remote_domain_get_block_io_tune_ret ret = {0}; + g_auto(remote_domain_get_block_io_tune_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -2697,8 +2573,7 @@ static int remoteDomainGetBlockIoTune(virDomainPtr domain, */ if (*nparams == 0) { *nparams = ret.nparams; - rv = 0; - goto cleanup; + return -1; } if (virTypedParamsDeserialize((struct _virTypedParameterRemote *) ret.params.params_val, @@ -2706,14 +2581,9 @@ static int remoteDomainGetBlockIoTune(virDomainPtr domain, REMOTE_DOMAIN_BLOCK_IO_TUNE_PARAMETERS_MAX, ¶ms, nparams) < 0) - goto cleanup; - - rv = 0; + return -1; - cleanup: - xdr_free((xdrproc_t) xdr_remote_domain_get_block_io_tune_ret, - (char *) &ret); - return rv; + return 0; } static int remoteDomainGetCPUStats(virDomainPtr domain, @@ -2725,8 +2595,7 @@ static int remoteDomainGetCPUStats(virDomainPtr domain, { struct private_data *priv = domain->conn->privateData; remote_domain_get_cpu_stats_args args = {0}; - remote_domain_get_cpu_stats_ret ret = {0}; - int rv = -1; + g_auto(remote_domain_get_cpu_stats_ret) ret = {0}; int cpu; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -2763,16 +2632,14 @@ static int remoteDomainGetCPUStats(virDomainPtr domain, virReportError(VIR_ERR_RPC, "%s", _("remoteDomainGetCPUStats: " "returned number of stats exceeds limit")); - memset(params, 0, sizeof(*params) * nparams * ncpus); - goto cleanup; + return -1; } /* Handle the case when the caller does not know the number of stats * and is asking for the number of stats supported */ if (nparams == 0) { - rv = ret.nparams; - goto cleanup; + return ret.nparams; } /* The remote side did not send back any zero entries, so we have @@ -2789,18 +2656,13 @@ static int remoteDomainGetCPUStats(virDomainPtr domain, if (virTypedParamsDeserialize((struct _virTypedParameterRemote *) stride, ret.nparams, REMOTE_NODE_CPU_STATS_MAX, - &cpu_params, &tmp) < 0) - goto cleanup; + &cpu_params, &tmp) < 0) { + virTypedParamsClear(params, nparams * ncpus); + return -1; + } } - rv = ret.nparams; - cleanup: - if (rv < 0) - virTypedParamsClear(params, nparams * ncpus); - - xdr_free((xdrproc_t) xdr_remote_domain_get_cpu_stats_ret, - (char *) &ret); - return rv; + return ret.nparams; } @@ -2814,7 +2676,7 @@ remoteConnectNetworkEventRegisterAny(virConnectPtr conn, { struct private_data *priv = conn->privateData; remote_connect_network_event_register_any_args args = {0}; - remote_connect_network_event_register_any_ret ret = {0}; + g_auto(remote_connect_network_event_register_any_ret) ret = {0}; int callbackID; int count; remote_nonnull_network network; @@ -2895,7 +2757,7 @@ remoteConnectStoragePoolEventRegisterAny(virConnectPtr conn, { struct private_data *priv = conn->privateData; remote_connect_storage_pool_event_register_any_args args = {0}; - remote_connect_storage_pool_event_register_any_ret ret = {0}; + g_auto(remote_connect_storage_pool_event_register_any_ret) ret = {0}; int callbackID; int count; remote_nonnull_storage_pool storage_pool; @@ -2978,7 +2840,7 @@ remoteConnectNodeDeviceEventRegisterAny(virConnectPtr conn, { struct private_data *priv = conn->privateData; remote_connect_node_device_event_register_any_args args = {0}; - remote_connect_node_device_event_register_any_ret ret = {0}; + g_auto(remote_connect_node_device_event_register_any_ret) ret = {0}; int callbackID; int count; remote_nonnull_node_device node_device; @@ -3062,7 +2924,7 @@ remoteConnectSecretEventRegisterAny(virConnectPtr conn, { struct private_data *priv = conn->privateData; remote_connect_secret_event_register_any_args args = {0}; - remote_connect_secret_event_register_any_ret ret = {0}; + g_auto(remote_connect_secret_event_register_any_ret) ret = {0}; int callbackID; int count; remote_nonnull_secret sec; @@ -3147,7 +3009,7 @@ remoteConnectDomainQemuMonitorEventRegister(virConnectPtr conn, { struct private_data *priv = conn->privateData; qemu_connect_domain_monitor_event_register_args args; - qemu_connect_domain_monitor_event_register_ret ret = {0}; + g_auto(qemu_connect_domain_monitor_event_register_ret) ret = {0}; int callbackID; int count; remote_nonnull_domain domain; @@ -3227,9 +3089,8 @@ remoteConnectFindStoragePoolSources(virConnectPtr conn, const char *srcSpec, unsigned int flags) { - char *rv = NULL; remote_connect_find_storage_pool_sources_args args = {0}; - remote_connect_find_storage_pool_sources_ret ret = {0}; + g_auto(remote_connect_find_storage_pool_sources_ret) ret = {0}; struct private_data *priv = conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -3242,10 +3103,7 @@ remoteConnectFindStoragePoolSources(virConnectPtr conn, (xdrproc_t) xdr_remote_connect_find_storage_pool_sources_ret, (char *) &ret) == -1) return NULL; - rv = g_steal_pointer(&ret.xml); /* To stop xdr_free free'ing it */ - - xdr_free((xdrproc_t) xdr_remote_connect_find_storage_pool_sources_ret, (char *) &ret); - return rv; + return g_steal_pointer(&ret.xml); } /*----------------------------------------------------------------------*/ @@ -3332,7 +3190,7 @@ remoteAuthenticate(virConnectPtr conn, struct private_data *priv, virConnectAuthPtr auth G_GNUC_UNUSED, const char *authtype) { - struct remote_auth_list_ret ret = {0}; + g_auto(remote_auth_list_ret) ret = {0}; int err, type = REMOTE_AUTH_NONE; err = call(conn, priv, 0, @@ -3962,7 +3820,7 @@ static int remoteAuthPolkit(virConnectPtr conn, struct private_data *priv, virConnectAuthPtr auth G_GNUC_UNUSED) { - remote_auth_polkit_ret ret = {0}; + g_auto(remote_auth_polkit_ret) ret = {0}; VIR_DEBUG("Client initialize PolicyKit authentication"); if (call(conn, priv, 0, REMOTE_PROC_AUTH_POLKIT, @@ -4001,7 +3859,7 @@ remoteConnectDomainEventRegister(virConnectPtr conn, /* Tell the server when we are the first callback registering */ if (priv->serverEventFilter) { remote_connect_domain_event_callback_register_any_args args = {0}; - remote_connect_domain_event_callback_register_any_ret ret = {0}; + g_auto(remote_connect_domain_event_callback_register_any_ret) ret = {0}; args.eventID = VIR_DOMAIN_EVENT_ID_LIFECYCLE; args.dom = NULL; @@ -5110,7 +4968,7 @@ remoteSecretGetValue(virSecretPtr secret, size_t *value_size, unsigned int flags) { remote_secret_get_value_args args = {0}; - remote_secret_get_value_ret ret = {0}; + g_auto(remote_secret_get_value_ret) ret = {0}; struct private_data *priv = secret->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -5123,7 +4981,7 @@ remoteSecretGetValue(virSecretPtr secret, size_t *value_size, return NULL; *value_size = ret.value.value_len; - return (unsigned char *) ret.value.value_val; /* Caller frees. */ + return (unsigned char *) g_steal_pointer(&ret.value.value_val); /* Caller frees. */ } @@ -5517,7 +5375,7 @@ remoteConnectDomainEventRegisterAny(virConnectPtr conn, if (count == 1) { if (priv->serverEventFilter) { remote_connect_domain_event_callback_register_any_args args = {0}; - remote_connect_domain_event_callback_register_any_ret ret = {0}; + g_auto(remote_connect_domain_event_callback_register_any_ret) ret = {0}; args.eventID = eventID; if (dom) { @@ -5608,9 +5466,8 @@ static int remoteDomainQemuMonitorCommand(virDomainPtr domain, const char *cmd, char **result, unsigned int flags) { - int rv = -1; qemu_domain_monitor_command_args args; - qemu_domain_monitor_command_ret ret = {0}; + g_auto(qemu_domain_monitor_command_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -5623,13 +5480,9 @@ remoteDomainQemuMonitorCommand(virDomainPtr domain, const char *cmd, (xdrproc_t) xdr_qemu_domain_monitor_command_ret, (char *) &ret) == -1) return -1; - *result = g_strdup(ret.result); - - rv = 0; - - xdr_free((xdrproc_t) xdr_qemu_domain_monitor_command_ret, (char *) &ret); + *result = g_steal_pointer(&ret.result); - return rv; + return 0; } @@ -5644,7 +5497,7 @@ remoteDomainQemuMonitorCommandWithFiles(virDomainPtr domain, unsigned int flags) { qemu_domain_monitor_command_with_files_args args; - qemu_domain_monitor_command_with_files_ret ret = {0}; + g_auto(qemu_domain_monitor_command_with_files_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; size_t rpc_noutfiles = 0; g_autofree int *rpc_outfiles = NULL; @@ -5668,9 +5521,7 @@ remoteDomainQemuMonitorCommandWithFiles(virDomainPtr domain, if (noutfiles) *noutfiles = rpc_noutfiles; - *result = g_strdup(ret.result); - - xdr_free((xdrproc_t) xdr_qemu_domain_monitor_command_with_files_ret, (char *) &ret); + *result = g_steal_pointer(&ret.result); if (rpc_outfiles) { for (i = 0; i < rpc_noutfiles; i++) { @@ -5691,9 +5542,8 @@ remoteDomainMigrateBegin3(virDomainPtr domain, const char *dname, unsigned long resource) { - char *rv = NULL; remote_domain_migrate_begin3_args args = {0}; - remote_domain_migrate_begin3_ret ret = {0}; + g_auto(remote_domain_migrate_begin3_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -5712,20 +5562,14 @@ remoteDomainMigrateBegin3(virDomainPtr domain, if (!cookieout || !cookieoutlen) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("caller ignores cookieout or cookieoutlen")); - goto error; + return NULL; } - *cookieout = ret.cookie_out.cookie_out_val; /* Caller frees. */ + *cookieout = g_steal_pointer(&ret.cookie_out.cookie_out_val); /* Caller frees. */ *cookieoutlen = ret.cookie_out.cookie_out_len; + ret.cookie_out.cookie_out_len = 0; } - rv = ret.xml; /* caller frees */ - - done: - return rv; - - error: - VIR_FREE(ret.cookie_out.cookie_out_val); - goto done; + return g_steal_pointer(&ret.xml); /* caller frees */ } @@ -5742,9 +5586,8 @@ remoteDomainMigratePrepare3(virConnectPtr dconn, unsigned long resource, const char *dom_xml) { - int rv = -1; remote_domain_migrate_prepare3_args args = {0}; - remote_domain_migrate_prepare3_ret ret = {0}; + g_auto(remote_domain_migrate_prepare3_ret) ret = {0}; struct private_data *priv = dconn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -5765,30 +5608,22 @@ remoteDomainMigratePrepare3(virConnectPtr dconn, if (!cookieout || !cookieoutlen) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("caller ignores cookieout or cookieoutlen")); - goto error; + return -1; } - *cookieout = ret.cookie_out.cookie_out_val; /* Caller frees. */ + *cookieout = g_steal_pointer(&ret.cookie_out.cookie_out_val); /* Caller frees. */ *cookieoutlen = ret.cookie_out.cookie_out_len; + ret.cookie_out.cookie_out_len = 0; } if (ret.uri_out) { if (!uri_out) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("caller ignores uri_out")); - goto error; + return -1; } - *uri_out = *ret.uri_out; /* Caller frees. */ + *uri_out = g_steal_pointer(ret.uri_out); /* Caller frees. */ } - rv = 0; - - done: - VIR_FREE(ret.uri_out); - return rv; - error: - VIR_FREE(ret.cookie_out.cookie_out_val); - if (ret.uri_out) - VIR_FREE(*ret.uri_out); - goto done; + return 0; } @@ -5806,7 +5641,7 @@ remoteDomainMigratePrepareTunnel3(virConnectPtr dconn, { struct private_data *priv = dconn->privateData; remote_domain_migrate_prepare_tunnel3_args args = {0}; - remote_domain_migrate_prepare_tunnel3_ret ret = {0}; + g_auto(remote_domain_migrate_prepare_tunnel3_ret) ret = {0}; virNetClientStream *netst; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -5844,17 +5679,14 @@ remoteDomainMigratePrepareTunnel3(virConnectPtr dconn, if (!cookieout || !cookieoutlen) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("caller ignores cookieout or cookieoutlen")); - goto error; + return -1; } - *cookieout = ret.cookie_out.cookie_out_val; /* Caller frees. */ + *cookieout = g_steal_pointer(&ret.cookie_out.cookie_out_val); /* Caller frees. */ *cookieoutlen = ret.cookie_out.cookie_out_len; + ret.cookie_out.cookie_out_len = 0; } return 0; - - error: - VIR_FREE(ret.cookie_out.cookie_out_val); - return -1; } @@ -5872,7 +5704,7 @@ remoteDomainMigratePerform3(virDomainPtr dom, unsigned long resource) { remote_domain_migrate_perform3_args args = {0}; - remote_domain_migrate_perform3_ret ret = {0}; + g_auto(remote_domain_migrate_perform3_ret) ret = {0}; struct private_data *priv = dom->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -5896,17 +5728,14 @@ remoteDomainMigratePerform3(virDomainPtr dom, if (!cookieout || !cookieoutlen) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("caller ignores cookieout or cookieoutlen")); - goto error; + return -1; } - *cookieout = ret.cookie_out.cookie_out_val; /* Caller frees. */ + *cookieout = g_steal_pointer(&ret.cookie_out.cookie_out_val); /* Caller frees. */ *cookieoutlen = ret.cookie_out.cookie_out_len; + ret.cookie_out.cookie_out_len = 0; } return 0; - - error: - VIR_FREE(ret.cookie_out.cookie_out_val); - return -1; } @@ -5923,9 +5752,8 @@ remoteDomainMigrateFinish3(virConnectPtr dconn, int cancelled) { remote_domain_migrate_finish3_args args = {0}; - remote_domain_migrate_finish3_ret ret = {0}; + g_auto(remote_domain_migrate_finish3_ret) ret = {0}; struct private_data *priv = dconn->privateData; - virDomainPtr rv = NULL; VIR_LOCK_GUARD lock = remoteDriverLock(priv); args.cookie_in.cookie_in_val = (char *)cookiein; @@ -5945,22 +5773,14 @@ remoteDomainMigrateFinish3(virConnectPtr dconn, if (!cookieout || !cookieoutlen) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("caller ignores cookieout or cookieoutlen")); - goto error; + return NULL; } *cookieout = g_steal_pointer(&ret.cookie_out.cookie_out_val); /* Caller frees. */ *cookieoutlen = ret.cookie_out.cookie_out_len; ret.cookie_out.cookie_out_len = 0; } - rv = get_nonnull_domain(dconn, ret.dom); - - xdr_free((xdrproc_t) &xdr_remote_domain_migrate_finish3_ret, (char *) &ret); - - return rv; - - error: - VIR_FREE(ret.cookie_out.cookie_out_val); - return NULL; + return get_nonnull_domain(dconn, ret.dom); } @@ -5996,11 +5816,10 @@ remoteConnectGetCPUModelNames(virConnectPtr conn, char ***models, unsigned int flags) { - int rv = -1; size_t i; g_auto(GStrv) retmodels = NULL; remote_connect_get_cpu_model_names_args args = {0}; - remote_connect_get_cpu_model_names_ret ret = {0}; + g_auto(remote_connect_get_cpu_model_names_ret) ret = {0}; struct private_data *priv = conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -6021,7 +5840,7 @@ remoteConnectGetCPUModelNames(virConnectPtr conn, _("Too many model names '%d' for limit '%d'"), ret.models.models_len, REMOTE_CONNECT_CPU_MODELS_MAX); - goto cleanup; + return -1; } if (models) { @@ -6033,12 +5852,7 @@ remoteConnectGetCPUModelNames(virConnectPtr conn, *models = g_steal_pointer(&retmodels); } - rv = ret.ret; - - cleanup: - xdr_free((xdrproc_t) xdr_remote_connect_get_cpu_model_names_ret, (char *) &ret); - - return rv; + return ret.ret; } @@ -6161,10 +5975,9 @@ remoteDomainGetDiskErrors(virDomainPtr dom, unsigned int maxerrors, unsigned int flags) { - int rv = -1; struct private_data *priv = dom->conn->privateData; remote_domain_get_disk_errors_args args = {0}; - remote_domain_get_disk_errors_ret ret = {0}; + g_auto(remote_domain_get_disk_errors_ret) ret = {0}; VIR_LOCK_GUARD lock = remoteDriverLock(priv); make_nonnull_domain(&args.dom, dom); @@ -6183,13 +5996,9 @@ remoteDomainGetDiskErrors(virDomainPtr dom, REMOTE_DOMAIN_DISK_ERRORS_MAX, errors, maxerrors) < 0) - goto cleanup; - - rv = ret.nerrors; + return -1; - cleanup: - xdr_free((xdrproc_t) xdr_remote_domain_get_disk_errors_ret, (char *) &ret); - return rv; + return ret.nerrors; } #include "remote_client_bodies.h" @@ -6267,9 +6076,8 @@ remoteDomainGetInterfaceParameters(virDomainPtr domain, virTypedParameterPtr params, int *nparams, unsigned int flags) { - int rv = -1; remote_domain_get_interface_parameters_args args = {0}; - remote_domain_get_interface_parameters_ret ret = {0}; + g_auto(remote_domain_get_interface_parameters_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -6288,8 +6096,7 @@ remoteDomainGetInterfaceParameters(virDomainPtr domain, */ if (*nparams == 0) { *nparams = ret.nparams; - rv = 0; - goto cleanup; + return 0; } if (virTypedParamsDeserialize((struct _virTypedParameterRemote *) ret.params.params_val, @@ -6297,14 +6104,9 @@ remoteDomainGetInterfaceParameters(virDomainPtr domain, REMOTE_DOMAIN_INTERFACE_PARAMETERS_MAX, ¶ms, nparams) < 0) - goto cleanup; - - rv = 0; + return -1; - cleanup: - xdr_free((xdrproc_t) xdr_remote_domain_get_interface_parameters_ret, - (char *) &ret); - return rv; + return 0; } @@ -6314,9 +6116,8 @@ remoteNodeGetMemoryParameters(virConnectPtr conn, int *nparams, unsigned int flags) { - int rv = -1; remote_node_get_memory_parameters_args args = {0}; - remote_node_get_memory_parameters_ret ret = {0}; + g_auto(remote_node_get_memory_parameters_ret) ret = {0}; struct private_data *priv = conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -6333,8 +6134,7 @@ remoteNodeGetMemoryParameters(virConnectPtr conn, */ if (*nparams == 0) { *nparams = ret.nparams; - rv = 0; - goto cleanup; + return 0; } if (virTypedParamsDeserialize((struct _virTypedParameterRemote *) ret.params.params_val, @@ -6342,14 +6142,9 @@ remoteNodeGetMemoryParameters(virConnectPtr conn, REMOTE_NODE_MEMORY_PARAMETERS_MAX, ¶ms, nparams) < 0) - goto cleanup; - - rv = 0; + return -1; - cleanup: - xdr_free((xdrproc_t) xdr_remote_node_get_memory_parameters_ret, - (char *) &ret); - return rv; + return 0; } @@ -6359,9 +6154,8 @@ remoteNodeGetSEVInfo(virConnectPtr conn, int *nparams, unsigned int flags) { - int rv = -1; remote_node_get_sev_info_args args = {0}; - remote_node_get_sev_info_ret ret = {0}; + g_auto(remote_node_get_sev_info_ret) ret = {0}; struct private_data *priv = conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -6377,13 +6171,9 @@ remoteNodeGetSEVInfo(virConnectPtr conn, REMOTE_NODE_SEV_INFO_MAX, params, nparams) < 0) - goto cleanup; - - rv = 0; + return -1; - cleanup: - xdr_free((xdrproc_t) xdr_remote_node_get_sev_info_ret, (char *) &ret); - return rv; + return 0; } @@ -6393,9 +6183,8 @@ remoteNodeGetCPUMap(virConnectPtr conn, unsigned int *online, unsigned int flags) { - int rv = -1; remote_node_get_cpu_map_args args = {0}; - remote_node_get_cpu_map_ret ret = {0}; + g_auto(remote_node_get_cpu_map_ret) ret = {0}; struct private_data *priv = conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -6411,7 +6200,7 @@ remoteNodeGetCPUMap(virConnectPtr conn, return -1; if (ret.ret < 0) - goto cleanup; + return -1; if (cpumap) { *cpumap = g_new0(unsigned char, ret.cpumap.cpumap_len); @@ -6421,11 +6210,7 @@ remoteNodeGetCPUMap(virConnectPtr conn, if (online) *online = ret.online; - rv = ret.ret; - - cleanup: - xdr_free((xdrproc_t) xdr_remote_node_get_cpu_map_ret, (char *) &ret); - return rv; + return ret.ret; } @@ -6462,9 +6247,8 @@ remoteDomainGetJobStats(virDomainPtr domain, int *nparams, unsigned int flags) { - int rv = -1; remote_domain_get_job_stats_args args = {0}; - remote_domain_get_job_stats_ret ret = {0}; + g_auto(remote_domain_get_job_stats_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -6482,14 +6266,9 @@ remoteDomainGetJobStats(virDomainPtr domain, ret.params.params_len, REMOTE_DOMAIN_JOB_STATS_MAX, params, nparams) < 0) - goto cleanup; - - rv = 0; + return -1; - cleanup: - xdr_free((xdrproc_t) xdr_remote_domain_get_job_stats_ret, - (char *) &ret); - return rv; + return 0; } @@ -6503,7 +6282,7 @@ remoteDomainMigrateBegin3Params(virDomainPtr domain, { char *rv = NULL; remote_domain_migrate_begin3_params_args args = {0}; - remote_domain_migrate_begin3_params_ret ret = {0}; + g_auto(remote_domain_migrate_begin3_params_ret) ret = {0}; struct private_data *priv = domain->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -6514,9 +6293,8 @@ remoteDomainMigrateBegin3Params(virDomainPtr domain, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX, (struct _virTypedParameterRemote **) &args.params.params_val, &args.params.params_len, - VIR_TYPED_PARAM_STRING_OKAY) < 0) { - goto cleanup; - } + VIR_TYPED_PARAM_STRING_OKAY) < 0) + return NULL; if (call(domain->conn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_BEGIN3_PARAMS, (xdrproc_t) xdr_remote_domain_migrate_begin3_params_args, @@ -6529,22 +6307,19 @@ remoteDomainMigrateBegin3Params(virDomainPtr domain, if (!cookieout || !cookieoutlen) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("caller ignores cookieout or cookieoutlen")); - goto error; + goto cleanup; } - *cookieout = ret.cookie_out.cookie_out_val; /* Caller frees. */ + *cookieout = g_steal_pointer(&ret.cookie_out.cookie_out_val); /* Caller frees. */ *cookieoutlen = ret.cookie_out.cookie_out_len; + ret.cookie_out.cookie_out_len = 0; } - rv = ret.xml; /* caller frees */ + rv = g_steal_pointer(&ret.xml); /* caller frees */ cleanup: virTypedParamsRemoteFree((struct _virTypedParameterRemote *) args.params.params_val, args.params.params_len); return rv; - - error: - VIR_FREE(ret.cookie_out.cookie_out_val); - goto cleanup; } @@ -6561,7 +6336,7 @@ remoteDomainMigratePrepare3Params(virConnectPtr dconn, { int rv = -1; remote_domain_migrate_prepare3_params_args args = {0}; - remote_domain_migrate_prepare3_params_ret ret = {0}; + g_auto(remote_domain_migrate_prepare3_params_ret) ret = {0}; struct private_data *priv = dconn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -6569,9 +6344,8 @@ remoteDomainMigratePrepare3Params(virConnectPtr dconn, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX, (struct _virTypedParameterRemote **) &args.params.params_val, &args.params.params_len, - VIR_TYPED_PARAM_STRING_OKAY) < 0) { - goto cleanup; - } + VIR_TYPED_PARAM_STRING_OKAY) < 0) + return -1; args.cookie_in.cookie_in_val = (char *)cookiein; args.cookie_in.cookie_in_len = cookieinlen; @@ -6588,18 +6362,19 @@ remoteDomainMigratePrepare3Params(virConnectPtr dconn, if (!cookieout || !cookieoutlen) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("caller ignores cookieout or cookieoutlen")); - goto error; + goto cleanup; } - *cookieout = ret.cookie_out.cookie_out_val; /* Caller frees. */ + *cookieout = g_steal_pointer(&ret.cookie_out.cookie_out_val); /* Caller frees. */ *cookieoutlen = ret.cookie_out.cookie_out_len; + ret.cookie_out.cookie_out_len = 0; } if (ret.uri_out) { if (!uri_out) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("caller ignores uri_out")); - goto error; + goto cleanup; } - *uri_out = *ret.uri_out; /* Caller frees. */ + *uri_out = g_steal_pointer(ret.uri_out); /* Caller frees. */ } rv = 0; @@ -6607,14 +6382,7 @@ remoteDomainMigratePrepare3Params(virConnectPtr dconn, cleanup: virTypedParamsRemoteFree((struct _virTypedParameterRemote *) args.params.params_val, args.params.params_len); - VIR_FREE(ret.uri_out); return rv; - - error: - VIR_FREE(ret.cookie_out.cookie_out_val); - if (ret.uri_out) - VIR_FREE(*ret.uri_out); - goto cleanup; } @@ -6632,7 +6400,7 @@ remoteDomainMigratePrepareTunnel3Params(virConnectPtr dconn, struct private_data *priv = dconn->privateData; int rv = -1; remote_domain_migrate_prepare_tunnel3_params_args args = {0}; - remote_domain_migrate_prepare_tunnel3_params_ret ret = {0}; + g_auto(remote_domain_migrate_prepare_tunnel3_params_ret) ret = {0}; virNetClientStream *netst; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -6644,9 +6412,8 @@ remoteDomainMigratePrepareTunnel3Params(virConnectPtr dconn, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX, (struct _virTypedParameterRemote **) &args.params.params_val, &args.params.params_len, - VIR_TYPED_PARAM_STRING_OKAY) < 0) { - goto cleanup; - } + VIR_TYPED_PARAM_STRING_OKAY) < 0) + return -1; if (!(netst = virNetClientStreamNew(priv->remoteProgram, REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL3_PARAMS, @@ -6677,10 +6444,11 @@ remoteDomainMigratePrepareTunnel3Params(virConnectPtr dconn, if (!cookieout || !cookieoutlen) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("caller ignores cookieout or cookieoutlen")); - goto error; + goto cleanup; } - *cookieout = ret.cookie_out.cookie_out_val; /* Caller frees. */ + *cookieout = g_steal_pointer(&ret.cookie_out.cookie_out_val); /* Caller frees. */ *cookieoutlen = ret.cookie_out.cookie_out_len; + ret.cookie_out.cookie_out_len = 0; } rv = 0; @@ -6689,10 +6457,6 @@ remoteDomainMigratePrepareTunnel3Params(virConnectPtr dconn, virTypedParamsRemoteFree((struct _virTypedParameterRemote *) args.params.params_val, args.params.params_len); return rv; - - error: - VIR_FREE(ret.cookie_out.cookie_out_val); - goto cleanup; } @@ -6709,7 +6473,7 @@ remoteDomainMigratePerform3Params(virDomainPtr dom, { int rv = -1; remote_domain_migrate_perform3_params_args args = {0}; - remote_domain_migrate_perform3_params_ret ret = {0}; + g_auto(remote_domain_migrate_perform3_params_ret) ret = {0}; struct private_data *priv = dom->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -6723,9 +6487,8 @@ remoteDomainMigratePerform3Params(virDomainPtr dom, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX, (struct _virTypedParameterRemote **) &args.params.params_val, &args.params.params_len, - VIR_TYPED_PARAM_STRING_OKAY) < 0) { - goto cleanup; - } + VIR_TYPED_PARAM_STRING_OKAY) < 0) + return -1; if (call(dom->conn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_PERFORM3_PARAMS, (xdrproc_t) xdr_remote_domain_migrate_perform3_params_args, @@ -6738,10 +6501,11 @@ remoteDomainMigratePerform3Params(virDomainPtr dom, if (!cookieout || !cookieoutlen) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("caller ignores cookieout or cookieoutlen")); - goto error; + goto cleanup; } - *cookieout = ret.cookie_out.cookie_out_val; /* Caller frees. */ + *cookieout = g_steal_pointer(&ret.cookie_out.cookie_out_val); /* Caller frees. */ *cookieoutlen = ret.cookie_out.cookie_out_len; + ret.cookie_out.cookie_out_len = 0; } rv = 0; @@ -6750,10 +6514,6 @@ remoteDomainMigratePerform3Params(virDomainPtr dom, virTypedParamsRemoteFree((struct _virTypedParameterRemote *) args.params.params_val, args.params.params_len); return rv; - - error: - VIR_FREE(ret.cookie_out.cookie_out_val); - goto cleanup; } @@ -6769,7 +6529,7 @@ remoteDomainMigrateFinish3Params(virConnectPtr dconn, int cancelled) { remote_domain_migrate_finish3_params_args args = {0}; - remote_domain_migrate_finish3_params_ret ret = {0}; + g_auto(remote_domain_migrate_finish3_params_ret) ret = {0}; struct private_data *priv = dconn->privateData; virDomainPtr rv = NULL; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -6783,9 +6543,8 @@ remoteDomainMigrateFinish3Params(virConnectPtr dconn, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX, (struct _virTypedParameterRemote **) &args.params.params_val, &args.params.params_len, - VIR_TYPED_PARAM_STRING_OKAY) < 0) { - goto cleanup; - } + VIR_TYPED_PARAM_STRING_OKAY) < 0) + return NULL; if (call(dconn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_FINISH3_PARAMS, (xdrproc_t) xdr_remote_domain_migrate_finish3_params_args, @@ -6798,7 +6557,7 @@ remoteDomainMigrateFinish3Params(virConnectPtr dconn, if (!cookieout || !cookieoutlen) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("caller ignores cookieout or cookieoutlen")); - goto error; + goto cleanup; } *cookieout = g_steal_pointer(&ret.cookie_out.cookie_out_val); /* Caller frees. */ *cookieoutlen = ret.cookie_out.cookie_out_len; @@ -6806,18 +6565,10 @@ remoteDomainMigrateFinish3Params(virConnectPtr dconn, } rv = get_nonnull_domain(dconn, ret.dom); - - xdr_free((xdrproc_t) &xdr_remote_domain_migrate_finish3_params_ret, - (char *) &ret); - cleanup: virTypedParamsRemoteFree((struct _virTypedParameterRemote *) args.params.params_val, args.params.params_len); return rv; - - error: - VIR_FREE(ret.cookie_out.cookie_out_val); - goto cleanup; } @@ -6845,9 +6596,8 @@ remoteDomainMigrateConfirm3Params(virDomainPtr domain, REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX, (struct _virTypedParameterRemote **) &args.params.params_val, &args.params.params_len, - VIR_TYPED_PARAM_STRING_OKAY) < 0) { - goto cleanup; - } + VIR_TYPED_PARAM_STRING_OKAY) < 0) + return -1; if (call(domain->conn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_CONFIRM3_PARAMS, (xdrproc_t) xdr_remote_domain_migrate_confirm3_params_args, @@ -6867,10 +6617,9 @@ static virDomainPtr remoteDomainCreateXMLWithFiles(virConnectPtr conn, const char *xml_desc, unsigned int nfiles, int *files, unsigned int flags) { - virDomainPtr rv = NULL; struct private_data *priv = conn->privateData; remote_domain_create_xml_with_files_args args = {0}; - remote_domain_create_xml_with_files_ret ret = {0}; + g_auto(remote_domain_create_xml_with_files_ret) ret = {0}; VIR_LOCK_GUARD lock = remoteDriverLock(priv); args.xml_desc = (char *)xml_desc; @@ -6884,10 +6633,7 @@ remoteDomainCreateXMLWithFiles(virConnectPtr conn, const char *xml_desc, (xdrproc_t)xdr_remote_domain_create_xml_with_files_ret, (char *)&ret) == -1) return NULL; - rv = get_nonnull_domain(conn, ret.dom); - xdr_free((xdrproc_t)xdr_remote_domain_create_xml_with_files_ret, (char *)&ret); - - return rv; + return get_nonnull_domain(conn, ret.dom); } @@ -6898,7 +6644,7 @@ remoteDomainCreateWithFiles(virDomainPtr dom, { struct private_data *priv = dom->conn->privateData; remote_domain_create_with_files_args args = {0}; - remote_domain_create_with_files_ret ret = {0}; + g_auto(remote_domain_create_with_files_ret) ret = {0}; VIR_LOCK_GUARD lock = remoteDriverLock(priv); make_nonnull_domain(&args.dom, dom); @@ -6913,7 +6659,6 @@ remoteDomainCreateWithFiles(virDomainPtr dom, return -1; dom->id = ret.dom.id; - xdr_free((xdrproc_t) &xdr_remote_domain_create_with_files_ret, (char *) &ret); return 0; } @@ -6925,7 +6670,7 @@ remoteDomainGetTime(virDomainPtr dom, { struct private_data *priv = dom->conn->privateData; remote_domain_get_time_args args = {0}; - remote_domain_get_time_ret ret = {0}; + g_auto(remote_domain_get_time_ret) ret = {0}; VIR_LOCK_GUARD lock = remoteDriverLock(priv); make_nonnull_domain(&args.dom, dom); @@ -6940,7 +6685,6 @@ remoteDomainGetTime(virDomainPtr dom, *seconds = ret.seconds; *nseconds = ret.nseconds; - xdr_free((xdrproc_t) &xdr_remote_domain_get_time_ret, (char *) &ret); return 0; } @@ -6955,7 +6699,7 @@ remoteNodeGetFreePages(virConnectPtr conn, unsigned int flags) { remote_node_get_free_pages_args args = {0}; - remote_node_get_free_pages_ret ret = {0}; + g_auto(remote_node_get_free_pages_ret) ret = {0}; struct private_data *priv = conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -6979,8 +6723,6 @@ remoteNodeGetFreePages(virConnectPtr conn, memcpy(counts, ret.counts.counts_val, ret.counts.counts_len * sizeof(*counts)); - xdr_free((xdrproc_t) xdr_remote_node_get_free_pages_ret, (char *) &ret); - return ret.counts.counts_len; } @@ -7035,7 +6777,7 @@ remoteNetworkGetDHCPLeases(virNetworkPtr net, size_t i; struct private_data *priv = net->conn->privateData; remote_network_get_dhcp_leases_args args = {0}; - remote_network_get_dhcp_leases_ret ret = {0}; + g_auto(remote_network_get_dhcp_leases_ret) ret = {0}; virNetworkDHCPLeasePtr *leases_ret = NULL; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -7053,7 +6795,7 @@ remoteNetworkGetDHCPLeases(virNetworkPtr net, virReportError(VIR_ERR_INTERNAL_ERROR, _("Number of leases is %d, which exceeds max limit: %d"), ret.leases.leases_len, REMOTE_NETWORK_DHCP_LEASES_MAX); - goto cleanup; + return -1; } if (leases) { @@ -7078,8 +6820,6 @@ remoteNetworkGetDHCPLeases(virNetworkPtr net, virNetworkDHCPLeaseFree(leases_ret[i]); VIR_FREE(leases_ret); } - xdr_free((xdrproc_t)xdr_remote_network_get_dhcp_leases_ret, - (char *) &ret); return rv; } @@ -7097,7 +6837,7 @@ remoteConnectGetAllDomainStats(virConnectPtr conn, int rv = -1; size_t i; remote_connect_get_all_domain_stats_args args = {0}; - remote_connect_get_all_domain_stats_ret ret = {0}; + g_auto(remote_connect_get_all_domain_stats_ret) ret = {0}; virDomainStatsRecordPtr elem = NULL; virDomainStatsRecordPtr *tmpret = NULL; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -7158,8 +6898,6 @@ remoteConnectGetAllDomainStats(virConnectPtr conn, } virDomainStatsRecordListFree(tmpret); VIR_FREE(args.doms.doms_val); - xdr_free((xdrproc_t)xdr_remote_connect_get_all_domain_stats_ret, - (char *) &ret); return rv; } @@ -7175,7 +6913,7 @@ remoteNodeAllocPages(virConnectPtr conn, unsigned int flags) { remote_node_alloc_pages_args args = {0}; - remote_node_alloc_pages_ret ret = {0}; + g_auto(remote_node_alloc_pages_ret) ret = {0}; struct private_data *priv = conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -7208,11 +6946,10 @@ remoteDomainGetFSInfo(virDomainPtr dom, virDomainFSInfoPtr **info, unsigned int flags) { - int rv = -1; size_t i, j, len; struct private_data *priv = dom->conn->privateData; remote_domain_get_fsinfo_args args = {0}; - remote_domain_get_fsinfo_ret ret = {0}; + g_auto(remote_domain_get_fsinfo_ret) ret = {0}; remote_domain_fsinfo *src; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -7229,7 +6966,7 @@ remoteDomainGetFSInfo(virDomainPtr dom, virReportError(VIR_ERR_INTERNAL_ERROR, _("Too many mountpoints in fsinfo: %d for limit %d"), ret.info.info_len, REMOTE_DOMAIN_FSINFO_MAX); - goto cleanup; + return -1; } if (info) { @@ -7237,8 +6974,7 @@ remoteDomainGetFSInfo(virDomainPtr dom, if (!ret.info.info_len) { *info = NULL; - rv = ret.ret; - goto cleanup; + return ret.ret; } info_ret = g_new0(virDomainFSInfoPtr, ret.info.info_len); @@ -7266,12 +7002,7 @@ remoteDomainGetFSInfo(virDomainPtr dom, *info = info_ret; } - rv = ret.ret; - - cleanup: - xdr_free((xdrproc_t)xdr_remote_domain_get_fsinfo_ret, - (char *) &ret); - return rv; + return ret.ret; } @@ -7286,7 +7017,7 @@ remoteDomainInterfaceAddresses(virDomainPtr dom, virDomainInterfacePtr *ifaces_ret = NULL; remote_domain_interface_addresses_args args = {0}; - remote_domain_interface_addresses_ret ret = {0}; + g_auto(remote_domain_interface_addresses_ret) ret = {0}; struct private_data *priv = dom->conn->privateData; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -7305,7 +7036,7 @@ remoteDomainInterfaceAddresses(virDomainPtr dom, virReportError(VIR_ERR_INTERNAL_ERROR, _("Number of interfaces, %d exceeds the max limit: %d"), ret.ifaces.ifaces_len, REMOTE_DOMAIN_INTERFACE_MAX); - goto cleanup; + return -1; } if (ret.ifaces.ifaces_len) @@ -7358,8 +7089,6 @@ remoteDomainInterfaceAddresses(virDomainPtr dom, virDomainInterfaceFree(ifaces_ret[i]); VIR_FREE(ifaces_ret); } - xdr_free((xdrproc_t)xdr_remote_domain_interface_addresses_ret, - (char *) &ret); return rv; } @@ -7418,7 +7147,7 @@ remoteDomainRename(virDomainPtr dom, const char *new_name, unsigned int flags) int rv = -1; struct private_data *priv = dom->conn->privateData; remote_domain_rename_args args = {0}; - remote_domain_rename_ret ret = {0}; + g_auto(remote_domain_rename_ret) ret = {0}; char *tmp = NULL; VIR_LOCK_GUARD lock = remoteDriverLock(priv); @@ -7452,7 +7181,7 @@ remoteStorageVolGetInfoFlags(virStorageVolPtr vol, { struct private_data *priv = vol->conn->privateData; remote_storage_vol_get_info_flags_args args = {0}; - remote_storage_vol_get_info_flags_ret ret = {0}; + g_auto(remote_storage_vol_get_info_flags_ret) ret = {0}; VIR_LOCK_GUARD lock = remoteDriverLock(priv); make_nonnull_storage_vol(&args.vol, vol); @@ -7479,10 +7208,9 @@ remoteNetworkPortGetParameters(virNetworkPortPtr port, int *nparams, unsigned int flags) { - int rv = -1; struct private_data *priv = port->net->conn->privateData; remote_network_port_get_parameters_args args = {0}; - remote_network_port_get_parameters_ret ret = {0}; + g_auto(remote_network_port_get_parameters_ret) ret = {0}; VIR_LOCK_GUARD lock = remoteDriverLock(priv); make_nonnull_network_port(&args.port, port); @@ -7498,13 +7226,9 @@ remoteNetworkPortGetParameters(virNetworkPortPtr port, REMOTE_NETWORK_PORT_PARAMETERS_MAX, params, nparams) < 0) - goto cleanup; - - rv = 0; + return -1; - cleanup: - xdr_free((xdrproc_t) xdr_remote_network_port_get_parameters_ret, (char *) &ret); - return rv; + return 0; } static int @@ -7514,10 +7238,9 @@ remoteDomainGetGuestInfo(virDomainPtr dom, int *nparams, unsigned int flags) { - int rv = -1; struct private_data *priv = dom->conn->privateData; remote_domain_get_guest_info_args args = {0}; - remote_domain_get_guest_info_ret ret = {0}; + g_auto(remote_domain_get_guest_info_ret) ret = {0}; VIR_LOCK_GUARD lock = remoteDriverLock(priv); make_nonnull_domain(&args.dom, dom); @@ -7535,14 +7258,9 @@ remoteDomainGetGuestInfo(virDomainPtr dom, REMOTE_DOMAIN_GUEST_INFO_PARAMS_MAX, params, nparams) < 0) - goto cleanup; - - rv = 0; + return -1; - cleanup: - xdr_free((xdrproc_t)xdr_remote_domain_get_guest_info_ret, - (char *) &ret); - return rv; + return 0; } static int @@ -7551,11 +7269,10 @@ remoteDomainAuthorizedSSHKeysGet(virDomainPtr domain, char ***keys, unsigned int flags) { - int rv = -1; size_t i; struct private_data *priv = domain->conn->privateData; remote_domain_authorized_ssh_keys_get_args args = {0}; - remote_domain_authorized_ssh_keys_get_ret ret = {0}; + g_auto(remote_domain_authorized_ssh_keys_get_ret) ret = {0}; VIR_LOCK_GUARD lock = remoteDriverLock(priv); make_nonnull_domain(&args.dom, domain); @@ -7571,19 +7288,14 @@ remoteDomainAuthorizedSSHKeysGet(virDomainPtr domain, virReportError(VIR_ERR_RPC, "%s", _("remoteDomainAuthorizedSSHKeysGet: " "returned number of keys exceeds limit")); - goto cleanup; + return -1; } *keys = g_new0(char *, ret.keys.keys_len + 1); for (i = 0; i < ret.keys.keys_len; i++) - (*keys)[i] = g_strdup(ret.keys.keys_val[i]); - - rv = ret.keys.keys_len; + (*keys)[i] = g_steal_pointer(&ret.keys.keys_val[i]); - cleanup: - xdr_free((xdrproc_t)xdr_remote_domain_authorized_ssh_keys_get_ret, - (char *) &ret); - return rv; + return ret.keys.keys_len; } static int @@ -7624,11 +7336,10 @@ remoteDomainGetMessages(virDomainPtr domain, char ***msgs, unsigned int flags) { - int rv = -1; size_t i; struct private_data *priv = domain->conn->privateData; remote_domain_get_messages_args args = {0}; - remote_domain_get_messages_ret ret = {0}; + g_auto(remote_domain_get_messages_ret) ret = {0}; VIR_LOCK_GUARD lock = remoteDriverLock(priv); make_nonnull_domain(&args.dom, domain); @@ -7637,26 +7348,21 @@ remoteDomainGetMessages(virDomainPtr domain, if (call(domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_MESSAGES, (xdrproc_t) xdr_remote_domain_get_messages_args, (char *)&args, (xdrproc_t) xdr_remote_domain_get_messages_ret, (char *)&ret) == -1) { - goto cleanup; + return -1; } if (ret.msgs.msgs_len > REMOTE_DOMAIN_MESSAGES_MAX) { virReportError(VIR_ERR_RPC, "%s", _("remoteDomainGetMessages: " "returned number of msgs exceeds limit")); - goto cleanup; + return -1; } *msgs = g_new0(char *, ret.msgs.msgs_len + 1); for (i = 0; i < ret.msgs.msgs_len; i++) - (*msgs)[i] = g_strdup(ret.msgs.msgs_val[i]); + (*msgs)[i] = g_steal_pointer(&ret.msgs.msgs_val[i]); - rv = ret.msgs.msgs_len; - - cleanup: - xdr_free((xdrproc_t)xdr_remote_domain_get_messages_ret, - (char *) &ret); - return rv; + return ret.msgs.msgs_len; } -- 2.39.1

As preparation for eliminating the use of the XDR library, introduce helpers for (de)serializing XDR types from/to the virNetMessage object. In contrast to the XDR APIs, when encoding data our helpers can dynamically resize the virNetMessage buffer. Our decode helpers also exhibit delayed error reporting, so that callers can deserialize a bunch of data and check for errors once at the end. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/rpc/virnetmessage.c | 704 ++++++++++++++++++++++++++++++++++++++++ src/rpc/virnetmessage.h | 88 +++++ 2 files changed, 792 insertions(+) diff --git a/src/rpc/virnetmessage.c b/src/rpc/virnetmessage.c index c9698fb263..df9a1aea71 100644 --- a/src/rpc/virnetmessage.c +++ b/src/rpc/virnetmessage.c @@ -593,3 +593,707 @@ int virNetMessageAddFD(virNetMessage *msg, VIR_FORCE_CLOSE(newfd); return -1; } + +static void virNetMessageEncodePrealloc(virNetMessage *msg, size_t len) +{ + if ((msg->bufferLength - msg->bufferOffset) > len) + return; + + /* + * Over allocate by 64kb, since we'll almost certainly + * have more fields written soon + */ + msg->bufferLength += len + (1024 * 64); + msg->buffer = g_realloc_n(msg->buffer, 1, msg->bufferLength); +} + +static bool virNetMessageDecodePending(virNetMessage *msg, size_t len) +{ + if ((msg->bufferLength - msg->bufferOffset) < len) { + msg->decodeErrno = ENOSPC; + } + + /* Always return msg->decodeErrno, even if we didn't set it, + * because we allow multiple decode calls to be run without + * the caller checking for errors + */ + return msg->decodeErrno == 0; +} + +#define VIR_NET_MESSAGE_ENCODE_UINT32 \ + uint32_t p = htonl((uint32_t)v); \ + virNetMessageEncodePrealloc(msg, sizeof(uint32_t)); \ + memcpy(msg->buffer + msg->bufferOffset, &p, sizeof(p)); \ + msg->bufferOffset += sizeof(p) + +#define VIR_NET_MESSAGE_DECODE_UINT32(t) \ + uint32_t p; \ + if (!virNetMessageDecodePending(msg, sizeof(uint32_t))) \ + return; \ + memcpy(&p, msg->buffer + msg->bufferOffset, sizeof(p)); \ + msg->bufferOffset += sizeof(p); \ + *v = (t)ntohl((uint32_t)p); + +#define VIR_NET_MESSAGE_ENCODE_UINT64 \ + uint32_t p[2] = { \ + htonl((uint32_t)(((uint64_t)v >> 32) & 0xffffffff)), \ + htonl((uint32_t)((uint64_t)v & 0xffffffff)), \ + }; \ + virNetMessageEncodePrealloc(msg, sizeof(uint64_t)); \ + memcpy(msg->buffer + msg->bufferOffset, p, sizeof(p)); \ + msg->bufferOffset += sizeof(p) + +#define VIR_NET_MESSAGE_DECODE_UINT64(t) \ + uint32_t p[2]; \ + if (!virNetMessageDecodePending(msg, sizeof(uint64_t))) \ + return; \ + memcpy(&p, msg->buffer + msg->bufferOffset, sizeof(p)); \ + msg->bufferOffset += sizeof(p); \ + *v = (t)((((uint64_t)ntohl(p[0])) << 32) + ntohl(p[1])); + + +void virNetMessageEncodeInt8(virNetMessage *msg, int8_t v) +{ + VIR_NET_MESSAGE_ENCODE_UINT32; +} + +void virNetMessageDecodeInt8(virNetMessage *msg, int8_t *v) +{ + VIR_NET_MESSAGE_DECODE_UINT32(int8_t); +} + +void virNetMessageEncodeUInt8(virNetMessage *msg, uint8_t v) +{ + VIR_NET_MESSAGE_ENCODE_UINT32; +} + +void virNetMessageDecodeUInt8(virNetMessage *msg, uint8_t *v) +{ + VIR_NET_MESSAGE_DECODE_UINT32(uint8_t); +} + +void virNetMessageEncodeInt16(virNetMessage *msg, int16_t v) +{ + VIR_NET_MESSAGE_ENCODE_UINT32; +} + +void virNetMessageDecodeInt16(virNetMessage *msg, int16_t *v) +{ + VIR_NET_MESSAGE_DECODE_UINT32(int16_t); +} + +void virNetMessageEncodeUInt16(virNetMessage *msg, uint16_t v) +{ + VIR_NET_MESSAGE_ENCODE_UINT32; +} + +void virNetMessageDecodeUInt16(virNetMessage *msg, uint16_t *v) +{ + VIR_NET_MESSAGE_DECODE_UINT32(uint16_t); +} + +void virNetMessageEncodeInt32(virNetMessage *msg, int32_t v) +{ + VIR_NET_MESSAGE_ENCODE_UINT32; +} + +void virNetMessageDecodeInt32(virNetMessage *msg, int32_t *v) +{ + VIR_NET_MESSAGE_DECODE_UINT32(int32_t); +} + +void virNetMessageEncodeUInt32(virNetMessage *msg, uint32_t v) +{ + VIR_NET_MESSAGE_ENCODE_UINT32; +} + +void virNetMessageDecodeUInt32(virNetMessage *msg, uint32_t *v) +{ + VIR_NET_MESSAGE_DECODE_UINT32(uint32_t); +} + +void virNetMessageEncodeInt64(virNetMessage *msg, int64_t v) +{ + VIR_NET_MESSAGE_ENCODE_UINT64; +} + +void virNetMessageDecodeInt64(virNetMessage *msg, int64_t *v) +{ + VIR_NET_MESSAGE_DECODE_UINT64(int64_t); +} + +void virNetMessageEncodeUInt64(virNetMessage *msg, uint64_t v) +{ + VIR_NET_MESSAGE_ENCODE_UINT64; +} + +void virNetMessageDecodeUInt64(virNetMessage *msg, uint64_t *v) +{ + VIR_NET_MESSAGE_DECODE_UINT64(uint64_t); +} + +G_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t)); +void virNetMessageEncodeFloat(virNetMessage *msg, float v) +{ + VIR_NET_MESSAGE_ENCODE_UINT32; +} + +void virNetMessageDecodeFloat(virNetMessage *msg, float *v) +{ + VIR_NET_MESSAGE_DECODE_UINT32(float); +} + +G_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t)); +void virNetMessageEncodeDouble(virNetMessage *msg, double v) +{ + /* XXXX check I'm doing byte order right here */ + VIR_NET_MESSAGE_ENCODE_UINT64; +} + +void virNetMessageDecodeDouble(virNetMessage *msg, double *v) +{ + /* XXXX check I'm doing byte order right here */ + VIR_NET_MESSAGE_DECODE_UINT64(double); +} + +void virNetMessageEncodeBool(virNetMessage *msg, bool v) +{ + uint32_t p = htonl(v ? 1 : 0); + virNetMessageEncodePrealloc(msg, sizeof(p)); + memcpy(msg->buffer + msg->bufferOffset, &p, sizeof(p)); + msg->bufferOffset += sizeof(p); +} + +void virNetMessageDecodeBool(virNetMessage *msg, bool *v) +{ + uint32_t p; + if (!virNetMessageDecodePending(msg, sizeof(uint32_t))) + return; + memcpy(&p, msg->buffer + msg->bufferOffset, sizeof(p)); + msg->bufferOffset += sizeof(p); + *v = ntohl((uint32_t)p) == 1 ? true : false; +} + +#define VIR_NET_MESSAGE_ENCODE_FIXED_ARRAY_UINT32 \ + do { \ + g_assert(len < (G_MAXUINT32 - 1)); \ + g_assert((G_MAXSIZE / sizeof(uint32_t)) > len); \ + virNetMessageEncodePrealloc(msg, sizeof(uint32_t) * len); \ + while (len) { \ + uint32_t p = htonl((uint32_t)*v); \ + memcpy(msg->buffer + msg->bufferOffset, &p, sizeof(p)); \ + msg->bufferOffset += sizeof(p); \ + v++; \ + len--; \ + } \ + } while (0) + +#define VIR_NET_MESSAGE_DECODE_FIXED_ARRAY_UINT32(t) \ + do { \ + t *vp; \ + g_assert(len < (G_MAXUINT32 - 1)); \ + g_assert((G_MAXSIZE / sizeof(uint32_t)) > len); \ + if (!virNetMessageDecodePending(msg, sizeof(uint32_t) * len)) \ + return; \ + *v = vp = g_new0(t, len); \ + while (len) { \ + uint32_t p; \ + memcpy(&p, msg->buffer + msg->bufferOffset, sizeof(p)); \ + msg->bufferOffset += sizeof(p); \ + *vp = (t)ntohl(p); \ + vp++; \ + len--; \ + } \ + } while (0) + +#define VIR_NET_MESSAGE_ENCODE_FIXED_ARRAY_UINT64 \ + do { \ + g_assert(len < (G_MAXUINT32 - 1)); \ + g_assert((G_MAXSIZE / sizeof(uint64_t)) > len); \ + virNetMessageEncodePrealloc(msg, sizeof(uint32_t) * len); \ + while (len) { \ + uint32_t p[2] = { \ + htonl((uint32_t)(((uint64_t)*v >> 32) & 0xffffffff)), \ + htonl((uint32_t)((uint64_t)*v & 0xffffffff)), \ + }; \ + memcpy(msg->buffer + msg->bufferOffset, p, sizeof(p)); \ + msg->bufferOffset += sizeof(p); \ + v++; \ + len--; \ + } \ + } while (0) + +#define VIR_NET_MESSAGE_DECODE_FIXED_ARRAY_UINT64(t) \ + do { \ + t *vp; \ + g_assert(len < (G_MAXUINT32 - 1)); \ + g_assert((G_MAXSIZE / sizeof(uint64_t)) > len); \ + if (!virNetMessageDecodePending(msg, sizeof(uint64_t) * len)) \ + return; \ + *v = vp = g_new0(t, len); \ + while (len) { \ + uint32_t p[2]; \ + memcpy(p, msg->buffer + msg->bufferOffset, sizeof(p)); \ + msg->bufferOffset += sizeof(p); \ + *vp = (t)((((uint64_t)ntohl(p[0])) << 32) + ntohl(p[1])); \ + vp++; \ + len--; \ + } \ + } while (0) + +void virNetMessageEncodeInt8FixedArray(virNetMessage *msg, int8_t *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_FIXED_ARRAY_UINT32; +} + +void virNetMessageDecodeInt8FixedArray(virNetMessage *msg, int8_t **v, size_t len) +{ + VIR_NET_MESSAGE_DECODE_FIXED_ARRAY_UINT32(int8_t); +} + +void virNetMessageEncodeUInt8FixedArray(virNetMessage *msg, uint8_t *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_FIXED_ARRAY_UINT32; +} + +void virNetMessageDecodeUInt8FixedArray(virNetMessage *msg, uint8_t **v, size_t len) +{ + VIR_NET_MESSAGE_DECODE_FIXED_ARRAY_UINT32(uint8_t); +} + +void virNetMessageEncodeInt16FixedArray(virNetMessage *msg, int16_t *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_FIXED_ARRAY_UINT32; +} + +void virNetMessageDecodeInt16FixedArray(virNetMessage *msg, int16_t **v, size_t len) +{ + VIR_NET_MESSAGE_DECODE_FIXED_ARRAY_UINT32(int16_t); +} + +void virNetMessageEncodeUInt16FixedArray(virNetMessage *msg, uint16_t *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_FIXED_ARRAY_UINT32; +} + +void virNetMessageDecodeUInt16FixedArray(virNetMessage *msg, uint16_t **v, size_t len) +{ + VIR_NET_MESSAGE_DECODE_FIXED_ARRAY_UINT32(uint16_t); +} + +void virNetMessageEncodeInt32FixedArray(virNetMessage *msg, int32_t *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_FIXED_ARRAY_UINT32; +} + +void virNetMessageDecodeInt32FixedArray(virNetMessage *msg, int32_t **v, size_t len) +{ + VIR_NET_MESSAGE_DECODE_FIXED_ARRAY_UINT32(int32_t); +} + +void virNetMessageEncodeUInt32FixedArray(virNetMessage *msg, uint32_t *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_FIXED_ARRAY_UINT32; +} + +void virNetMessageDecodeUInt32FixedArray(virNetMessage *msg, uint32_t **v, size_t len) +{ + VIR_NET_MESSAGE_DECODE_FIXED_ARRAY_UINT32(uint32_t); +} + +void virNetMessageEncodeInt64FixedArray(virNetMessage *msg, int64_t *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_FIXED_ARRAY_UINT64; +} + +void virNetMessageDecodeInt64FixedArray(virNetMessage *msg, int64_t **v, size_t len) +{ + VIR_NET_MESSAGE_DECODE_FIXED_ARRAY_UINT64(int64_t); +} + +void virNetMessageEncodeUInt64FixedArray(virNetMessage *msg, uint64_t *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_FIXED_ARRAY_UINT64; +} + +void virNetMessageDecodeUInt64FixedArray(virNetMessage *msg, uint64_t **v, size_t len) +{ + VIR_NET_MESSAGE_DECODE_FIXED_ARRAY_UINT64(uint64_t); +} + +void virNetMessageEncodeFloatFixedArray(virNetMessage *msg, float *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_FIXED_ARRAY_UINT32; +} + +void virNetMessageDecodeFloatFixedArray(virNetMessage *msg, float **v, size_t len) +{ + VIR_NET_MESSAGE_DECODE_FIXED_ARRAY_UINT32(float); +} + +void virNetMessageEncodeDoubleFixedArray(virNetMessage *msg, double *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_FIXED_ARRAY_UINT64; +} + +void virNetMessageDecodeDoubleFixedArray(virNetMessage *msg, double **v, size_t len) +{ + VIR_NET_MESSAGE_DECODE_FIXED_ARRAY_UINT64(double); +} + +#define VIR_NET_MESSAGE_ENCODE_DYN_ARRAY_UINT32 \ + do { \ + uint32_t lenp = htonl(len); \ + g_assert(len < (G_MAXUINT32 - 1)); \ + g_assert(((G_MAXSIZE - sizeof(uint32_t))/ sizeof(uint32_t)) > len); \ + virNetMessageEncodePrealloc(msg, sizeof(uint32_t) + (sizeof(uint32_t) * len)); \ + memcpy(msg->buffer + msg->bufferOffset, &lenp, sizeof(lenp)); \ + msg->bufferOffset += sizeof(lenp); \ + while (len) { \ + uint32_t p = htonl((uint32_t)*v); \ + memcpy(msg->buffer + msg->bufferOffset, &p, sizeof(p)); \ + msg->bufferOffset += sizeof(p); \ + v++; \ + len--; \ + } \ + } while (0) + +#define VIR_NET_MESSAGE_DECODE_DYN_ARRAY_UINT32(t) \ + do { \ + t *vp; \ + uint32_t lentmp; \ + virNetMessageDecodeUInt32(msg, &lentmp); \ + if (msg->decodeErrno != 0) { \ + return; \ + } \ + if (lentmp > maxlen) { \ + msg->decodeErrno = EFBIG; \ + return; \ + } \ + g_assert(lentmp < (G_MAXUINT32 - 1)); \ + /* g_assert((G_MAXSIZE / sizeof(uint32_t)) > lentmp);*/ \ + if (!virNetMessageDecodePending(msg, sizeof(uint32_t) * lentmp)) \ + return; \ + *v = vp = g_new0(t, lentmp); \ + *len = lentmp; \ + while (lentmp) { \ + uint32_t p; \ + memcpy(&p, msg->buffer + msg->bufferOffset, sizeof(p)); \ + msg->bufferOffset += sizeof(p); \ + *vp = (t)ntohl(p); \ + vp++; \ + lentmp--; \ + } \ + } while (0) + +#define VIR_NET_MESSAGE_ENCODE_DYN_ARRAY_UINT64 \ + do { \ + uint32_t lenp = htonl(len); \ + g_assert(len < (G_MAXUINT32 - 1)); \ + g_assert(((G_MAXSIZE - sizeof(uint32_t))/ sizeof(uint64_t)) > len); \ + virNetMessageEncodePrealloc(msg, sizeof(uint32_t) + (sizeof(uint64_t) * len)); \ + memcpy(msg->buffer + msg->bufferOffset, &lenp, sizeof(lenp)); \ + msg->bufferOffset += sizeof(lenp); \ + while (len) { \ + uint32_t p[2] = { \ + htonl((uint32_t)(((uint64_t)*v >> 32) & 0xffffffff)), \ + htonl((uint32_t)((uint64_t)*v & 0xffffffff)), \ + }; \ + memcpy(msg->buffer + msg->bufferOffset, p, sizeof(p)); \ + msg->bufferOffset += sizeof(p); \ + v++; \ + len--; \ + } \ + } while (0) + +#define VIR_NET_MESSAGE_DECODE_DYN_ARRAY_UINT64(t) \ + do { \ + t *vp; \ + uint32_t lentmp; \ + virNetMessageDecodeUInt32(msg, &lentmp); \ + if (msg->decodeErrno != 0) { \ + return; \ + } \ + if (lentmp > maxlen) { \ + msg->decodeErrno = EFBIG; \ + return; \ + } \ + g_assert(lentmp < (G_MAXUINT32 - 1)); \ + /* g_assert((G_MAXSIZE / sizeof(uint32_t)) > lentmp);*/ \ + if (!virNetMessageDecodePending(msg, sizeof(uint32_t) * lentmp)) \ + return; \ + *v = vp = g_new0(t, lentmp); \ + *len = lentmp; \ + while (lentmp) { \ + uint32_t p[2]; \ + memcpy(p, msg->buffer + msg->bufferOffset, sizeof(p)); \ + msg->bufferOffset += sizeof(p); \ + *vp = (t)((((uint64_t)ntohl(p[0])) << 32) + ntohl(p[1])); \ + vp++; \ + lentmp--; \ + } \ + } while (0) + + +void virNetMessageEncodeInt8DynArray(virNetMessage *msg, int8_t *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_DYN_ARRAY_UINT32; +} + +void virNetMessageDecodeInt8DynArray(virNetMessage *msg, size_t maxlen, int8_t **v, size_t *len) +{ + VIR_NET_MESSAGE_DECODE_DYN_ARRAY_UINT32(int8_t); +} + +void virNetMessageEncodeUInt8DynArray(virNetMessage *msg, uint8_t *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_DYN_ARRAY_UINT32; +} + +void virNetMessageDecodeUInt8DynArray(virNetMessage *msg, size_t maxlen, uint8_t **v, size_t *len) +{ + VIR_NET_MESSAGE_DECODE_DYN_ARRAY_UINT32(uint8_t); +} + +void virNetMessageEncodeInt16DynArray(virNetMessage *msg, int16_t *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_DYN_ARRAY_UINT32; +} + +void virNetMessageDecodeInt16DynArray(virNetMessage *msg, size_t maxlen, int16_t **v, size_t *len) +{ + VIR_NET_MESSAGE_DECODE_DYN_ARRAY_UINT32(int16_t); +} + +void virNetMessageEncodeUInt16DynArray(virNetMessage *msg, uint16_t *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_DYN_ARRAY_UINT32; +} + +void virNetMessageDecodeUInt16DynArray(virNetMessage *msg, size_t maxlen, uint16_t **v, size_t *len) +{ + VIR_NET_MESSAGE_DECODE_DYN_ARRAY_UINT32(uint16_t); +} + +void virNetMessageEncodeInt32DynArray(virNetMessage *msg, int32_t *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_DYN_ARRAY_UINT32; +} + +void virNetMessageDecodeInt32DynArray(virNetMessage *msg, size_t maxlen, int32_t **v, size_t *len) +{ + VIR_NET_MESSAGE_DECODE_DYN_ARRAY_UINT32(int32_t); +} + +void virNetMessageEncodeUInt32DynArray(virNetMessage *msg, uint32_t *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_DYN_ARRAY_UINT32; +} + +void virNetMessageDecodeUInt32DynArray(virNetMessage *msg, size_t maxlen, uint32_t **v, size_t *len) +{ + VIR_NET_MESSAGE_DECODE_DYN_ARRAY_UINT32(uint32_t); +} + +void virNetMessageEncodeInt64DynArray(virNetMessage *msg, int64_t *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_DYN_ARRAY_UINT64; +} + +void virNetMessageDecodeInt64DynArray(virNetMessage *msg, size_t maxlen, int64_t **v, size_t *len) +{ + VIR_NET_MESSAGE_DECODE_DYN_ARRAY_UINT64(int64_t); +} + +void virNetMessageEncodeUInt64DynArray(virNetMessage *msg, uint64_t *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_DYN_ARRAY_UINT64; +} + +void virNetMessageDecodeUInt64DynArray(virNetMessage *msg, size_t maxlen, uint64_t **v, size_t *len) +{ + VIR_NET_MESSAGE_DECODE_DYN_ARRAY_UINT64(uint64_t); +} + +void virNetMessageEncodeFloatDynArray(virNetMessage *msg, float *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_DYN_ARRAY_UINT32; +} + +void virNetMessageDecodeFloatDynArray(virNetMessage *msg, size_t maxlen, float **v, size_t *len) +{ + VIR_NET_MESSAGE_DECODE_DYN_ARRAY_UINT32(float); +} + +void virNetMessageEncodeDoubleDynArray(virNetMessage *msg, double *v, size_t len) +{ + VIR_NET_MESSAGE_ENCODE_DYN_ARRAY_UINT64; +} + +void virNetMessageDecodeDoubleDynArray(virNetMessage *msg, size_t maxlen, double **v, size_t *len) +{ + VIR_NET_MESSAGE_DECODE_DYN_ARRAY_UINT64(double); +} + +void virNetMessageEncodeString(virNetMessage *msg, char *v) +{ + virNetMessageEncodeOpaqueDynArray(msg, (uint8_t *)v, strlen(v)); +} + +void virNetMessageDecodeString(virNetMessage *msg, size_t maxlen, char **v) +{ + size_t len; + virNetMessageDecodeOpaqueDynArray(msg, maxlen, (uint8_t **)v, &len); +} + +void virNetMessageEncodeOpaqueFixedArray(virNetMessage *msg, uint8_t *v, size_t len) +{ + size_t pad = 4 - (len % 4); + + g_assert(len < (G_MAXUINT32 - 1)); + g_assert((G_MAXSIZE - len) > pad); + + virNetMessageEncodePrealloc(msg, len + pad); + memcpy(msg->buffer + msg->bufferOffset, v, len); + msg->bufferOffset += len; + memset(msg->buffer + msg->bufferOffset, 0, pad); + msg->bufferOffset += pad; +} + +void virNetMessageDecodeOpaqueFixedArray(virNetMessage *msg, uint8_t **v, size_t len) +{ + size_t pad = 4 - (len % 4); + + g_assert(len < (G_MAXUINT32 - 1)); + g_assert((G_MAXSIZE - len) > pad); + + if (!virNetMessageDecodePending(msg, len + pad)) + return; + + memcpy(*v, msg->buffer + msg->bufferOffset, len); + msg->bufferOffset += len + pad; +} + +void virNetMessageEncodeOpaqueDynArray(virNetMessage *msg, uint8_t *v, size_t len) +{ + uint32_t lenp = htonl(len); + size_t pad = 4 - (len % 4); + + g_assert(len < (G_MAXUINT32 - 1)); + g_assert((G_MAXSIZE - len) > (pad + 4)); + + virNetMessageEncodePrealloc(msg, len + pad + sizeof(lenp)); + memcpy(msg->buffer + msg->bufferOffset, &lenp, sizeof(lenp)); + msg->bufferOffset += sizeof(lenp); + memcpy(msg->buffer + msg->bufferOffset, v, len); + msg->bufferOffset += len; + memset(msg->buffer + msg->bufferOffset, 0, pad); + msg->bufferOffset += pad; +} + +void virNetMessageDecodeOpaqueDynArray(virNetMessage *msg, size_t maxlen, uint8_t **v, size_t *len) +{ + uint32_t lentmp; + size_t pad; + + g_assert(maxlen < (G_MAXUINT32 - 1)); + + virNetMessageDecodeUInt32(msg, &lentmp); + if (msg->decodeErrno != 0) + return; + + if (lentmp > maxlen) { + msg->decodeErrno = EFBIG; + return; + } + + pad = 4 - (lentmp % 4); + + if ((G_MAXSIZE - lentmp) <= pad) { + msg->decodeErrno = EFBIG; + return; + } + + if (!virNetMessageDecodePending(msg, lentmp + pad)) + return; + + *v = g_new0(uint8_t, lentmp); + *len = lentmp; + memcpy(*v, msg->buffer + msg->bufferOffset, lentmp); + msg->bufferOffset += lentmp + pad; +} + + +void virNetMessageEncodeAnyFixedArray(virNetMessage *msg, void *v, size_t len, size_t size, + virNetMessageEncoder encoder) +{ + char *vp = v; + while (len) { + encoder(msg, vp); + vp += size; + len--; + } +} + +void virNetMessageDecodeAnyFixedArray(virNetMessage *msg, void **v, size_t len, size_t size, + virNetMessageDecoder decoder) +{ + char *val = g_malloc0_n(size, len); + *v = val; + while (len) { + decoder(msg, (void **)&val); + val += size; + len--; + } +} + +void virNetMessageEncodeAnyDynArray(virNetMessage *msg, void *v, size_t len, size_t size, + virNetMessageEncoder encoder) +{ + char *vp = v; + uint32_t lenp = htonl(len); + g_assert(len < (G_MAXUINT32 - 1)); + g_assert(((G_MAXSIZE - sizeof(uint32_t))/size) > len); + virNetMessageEncodePrealloc(msg, sizeof(uint32_t)); + memcpy(msg->buffer + msg->bufferOffset, &lenp, sizeof(lenp)); + msg->bufferOffset += sizeof(lenp); + while (len) { + encoder(msg, vp); + vp += size; + len--; + } +} + +void virNetMessageDecodeAnyDynArray(virNetMessage *msg, size_t maxlen, size_t size, + virNetMessageDecoder decoder, void **v, size_t *len) +{ + uint32_t lentmp; + char *vp; + virNetMessageDecodeUInt32(msg, &lentmp); + if (msg->decodeErrno != 0) { + return; + } + if (lentmp > maxlen) { + msg->decodeErrno = EFBIG; + return; + } + g_assert(lentmp < (G_MAXUINT32 - 1)); + /* g_assert((G_MAXSIZE / size) > lentmp);*/ + *v = vp = g_malloc0_n(lentmp, size); + *len = lentmp; + while (lentmp) { + decoder(msg, (void**)&vp); + vp += size; + lentmp--; + } +} + +int virNetMessageHasDecodeError(virNetMessage *msg) +{ + if (msg->decodeErrno) { + virReportSystemError(msg->decodeErrno, "%s", + _("Message terminated unexpectedly")); + return -1; + } + return 0; +} diff --git a/src/rpc/virnetmessage.h b/src/rpc/virnetmessage.h index 849674fa53..264ddd3c05 100644 --- a/src/rpc/virnetmessage.h +++ b/src/rpc/virnetmessage.h @@ -20,6 +20,7 @@ #pragma once +#include <rpc/rpc.h> #include "virnetprotocol.h" typedef struct _virNetMessage virNetMessage; @@ -28,6 +29,7 @@ typedef void (*virNetMessageFreeCallback)(virNetMessage *msg, void *opaque); struct _virNetMessage { bool tracked; + int decodeErrno; char *buffer; /* Initially VIR_NET_MESSAGE_INITIAL + VIR_NET_MESSAGE_LEN_MAX */ /* Maximum VIR_NET_MESSAGE_MAX + VIR_NET_MESSAGE_LEN_MAX */ @@ -94,3 +96,89 @@ int virNetMessageDupFD(virNetMessage *msg, int virNetMessageAddFD(virNetMessage *msg, int fd); + +void virNetMessageEncodeInt8(virNetMessage *msg, int8_t v); +void virNetMessageDecodeInt8(virNetMessage *msg, int8_t *v); +void virNetMessageEncodeUInt8(virNetMessage *msg, uint8_t v); +void virNetMessageDecodeUInt8(virNetMessage *msg, uint8_t *v); +void virNetMessageEncodeInt16(virNetMessage *msg, int16_t v); +void virNetMessageDecodeInt16(virNetMessage *msg, int16_t *v); +void virNetMessageEncodeUInt16(virNetMessage *msg, uint16_t v); +void virNetMessageDecodeUInt16(virNetMessage *msg, uint16_t *v); +void virNetMessageEncodeInt32(virNetMessage *msg, int32_t v); +void virNetMessageDecodeInt32(virNetMessage *msg, int32_t *v); +void virNetMessageEncodeUInt32(virNetMessage *msg, uint32_t v); +void virNetMessageDecodeUInt32(virNetMessage *msg, uint32_t *v); +void virNetMessageEncodeInt64(virNetMessage *msg, int64_t v); +void virNetMessageDecodeInt64(virNetMessage *msg, int64_t *v); +void virNetMessageEncodeUInt64(virNetMessage *msg, uint64_t v); +void virNetMessageDecodeUInt64(virNetMessage *msg, uint64_t *v); + +void virNetMessageEncodeFloat(virNetMessage *msg, float v); +void virNetMessageDecodeFloat(virNetMessage *msg, float *v); +void virNetMessageEncodeDouble(virNetMessage *msg, double v); +void virNetMessageDecodeDouble(virNetMessage *msg, double *v); +void virNetMessageEncodeBool(virNetMessage *msg, bool v); +void virNetMessageDecodeBool(virNetMessage *msg, bool *v); + +void virNetMessageEncodeInt8FixedArray(virNetMessage *msg, int8_t *v, size_t len); +void virNetMessageDecodeInt8FixedArray(virNetMessage *msg, int8_t **v, size_t len); +void virNetMessageEncodeUInt8FixedArray(virNetMessage *msg, uint8_t *v, size_t len); +void virNetMessageDecodeUInt8FixedArray(virNetMessage *msg, uint8_t **v, size_t len); +void virNetMessageEncodeInt16FixedArray(virNetMessage *msg, int16_t *v, size_t len); +void virNetMessageDecodeInt16FixedArray(virNetMessage *msg, int16_t **v, size_t len); +void virNetMessageEncodeUInt16FixedArray(virNetMessage *msg, uint16_t *v, size_t len); +void virNetMessageDecodeUInt16FixedArray(virNetMessage *msg, uint16_t **v, size_t len); +void virNetMessageEncodeInt32FixedArray(virNetMessage *msg, int32_t *v, size_t len); +void virNetMessageDecodeInt32FixedArray(virNetMessage *msg, int32_t **v, size_t len); +void virNetMessageEncodeUInt32FixedArray(virNetMessage *msg, uint32_t *v, size_t len); +void virNetMessageDecodeUInt32FixedArray(virNetMessage *msg, uint32_t **v, size_t len); +void virNetMessageEncodeInt64FixedArray(virNetMessage *msg, int64_t *v, size_t len); +void virNetMessageDecodeInt64FixedArray(virNetMessage *msg, int64_t **v, size_t len); +void virNetMessageEncodeUInt64FixedArray(virNetMessage *msg, uint64_t *v, size_t len); +void virNetMessageDecodeUInt64FixedArray(virNetMessage *msg, uint64_t **v, size_t len); +void virNetMessageEncodeFloatFixedArray(virNetMessage *msg, float *v, size_t len); +void virNetMessageDecodeFloatFixedArray(virNetMessage *msg, float **v, size_t len); +void virNetMessageEncodeDoubleFixedArray(virNetMessage *msg, double *v, size_t len); +void virNetMessageDecodeDoubleFixedArray(virNetMessage *msg, double **v, size_t len); + +void virNetMessageEncodeInt8DynArray(virNetMessage *msg, int8_t *v, size_t len); +void virNetMessageDecodeInt8DynArray(virNetMessage *msg, size_t maxlen, int8_t **v, size_t *len); +void virNetMessageEncodeUInt8DynArray(virNetMessage *msg, uint8_t *v, size_t len); +void virNetMessageDecodeUInt8DynArray(virNetMessage *msg, size_t maxlen, uint8_t **v, size_t *len); +void virNetMessageEncodeInt16DynArray(virNetMessage *msg, int16_t *v, size_t len); +void virNetMessageDecodeInt16DynArray(virNetMessage *msg, size_t maxlen, int16_t **v, size_t *len); +void virNetMessageEncodeUInt16DynArray(virNetMessage *msg, uint16_t *v, size_t len); +void virNetMessageDecodeUInt16DynArray(virNetMessage *msg, size_t maxlen, uint16_t **v, size_t *len); +void virNetMessageEncodeInt32DynArray(virNetMessage *msg, int32_t *v, size_t len); +void virNetMessageDecodeInt32DynArray(virNetMessage *msg, size_t maxlen, int32_t **v, size_t *len); +void virNetMessageEncodeUInt32DynArray(virNetMessage *msg, uint32_t *v, size_t len); +void virNetMessageDecodeUInt32DynArray(virNetMessage *msg, size_t maxlen, uint32_t **v, size_t *len); +void virNetMessageEncodeInt64DynArray(virNetMessage *msg, int64_t *v, size_t len); +void virNetMessageDecodeInt64DynArray(virNetMessage *msg, size_t maxlen, int64_t **v, size_t *len); +void virNetMessageEncodeUInt64DynArray(virNetMessage *msg, uint64_t *v, size_t len); +void virNetMessageDecodeUInt64DynArray(virNetMessage *msg, size_t maxlen, uint64_t **v, size_t *len); +void virNetMessageEncodeFloatDynArray(virNetMessage *msg, float *v, size_t len); +void virNetMessageDecodeFloatDynArray(virNetMessage *msg, size_t maxlen, float **v, size_t *len); +void virNetMessageEncodeDoubleDynArray(virNetMessage *msg, double *v, size_t len); +void virNetMessageDecodeDoubleDynArray(virNetMessage *msg, size_t maxlen, double **v, size_t *len); + +void virNetMessageEncodeString(virNetMessage *msg, char *v); +void virNetMessageDecodeString(virNetMessage *msg, size_t maxlen, char **v); +void virNetMessageEncodeOpaqueFixedArray(virNetMessage *msg, uint8_t *v, size_t len); +void virNetMessageDecodeOpaqueFixedArray(virNetMessage *msg, uint8_t **v, size_t len); +void virNetMessageEncodeOpaqueDynArray(virNetMessage *msg, uint8_t *v, size_t len); +void virNetMessageDecodeOpaqueDynArray(virNetMessage *msg, size_t maxlen, uint8_t **v, size_t *len); + +typedef void (*virNetMessageEncoder)(virNetMessage *msg, void *v); +typedef void (*virNetMessageDecoder)(virNetMessage *msg, void **v); +void virNetMessageEncodeAnyFixedArray(virNetMessage *msg, void *v, size_t len, size_t size, + virNetMessageEncoder encoder); +void virNetMessageDecodeAnyFixedArray(virNetMessage *msg, void **v, size_t len, size_t size, + virNetMessageDecoder decoder); +void virNetMessageEncodeAnyDynArray(virNetMessage *msg, void *v, size_t len, size_t size, + virNetMessageEncoder encoder); +void virNetMessageDecodeAnyDynArray(virNetMessage *msg, size_t maxlen, size_t size, + virNetMessageDecoder decoder, void **v, size_t *len); + +int virNetMessageHasDecodeError(virNetMessage *msg); -- 2.39.1

On 3/8/23 17:39, Daniel P. Berrangé wrote:
As preparation for eliminating the use of the XDR library, introduce helpers for (de)serializing XDR types from/to the virNetMessage object.
In contrast to the XDR APIs, when encoding data our helpers can dynamically resize the virNetMessage buffer. Our decode helpers also exhibit delayed error reporting, so that callers can deserialize a bunch of data and check for errors once at the end.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/rpc/virnetmessage.c | 704 ++++++++++++++++++++++++++++++++++++++++ src/rpc/virnetmessage.h | 88 +++++ 2 files changed, 792 insertions(+)
These new symbols should be listed in src/libvirt_remote.syms. But apparently, you have some more cleanups pending, because none of these functions you are introducing are used. You can count with my ACK, but I'd rather not merge it for now, because it's effectively a dead code. Michal

On Thu, Mar 09, 2023 at 04:11:53PM +0100, Michal Prívozník wrote:
On 3/8/23 17:39, Daniel P. Berrangé wrote:
As preparation for eliminating the use of the XDR library, introduce helpers for (de)serializing XDR types from/to the virNetMessage object.
In contrast to the XDR APIs, when encoding data our helpers can dynamically resize the virNetMessage buffer. Our decode helpers also exhibit delayed error reporting, so that callers can deserialize a bunch of data and check for errors once at the end.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/rpc/virnetmessage.c | 704 ++++++++++++++++++++++++++++++++++++++++ src/rpc/virnetmessage.h | 88 +++++ 2 files changed, 792 insertions(+)
These new symbols should be listed in src/libvirt_remote.syms. But apparently, you have some more cleanups pending, because none of these functions you are introducing are used. You can count with my ACK, but I'd rather not merge it for now, because it's effectively a dead code.
Yes, this is an dependancy of the future work that would enable removal of libtirpc.so and thus direct call to virNetMessage APIs shown ni this patch. I should have tagged this one 'POC' as its not intended to merge on its own yet. With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

On 3/8/23 17:38, Daniel P. Berrangé wrote:
Daniel P. Berrangé (16): rpcgen: drop type-puning workarounds build-aux: skip E203 and W503 flake8 checks build-aux: introduce 'black' tool for python formatting rpcgen: add an XDR protocol lexer rpcgen: add an XDR protocol abstract syntax tree rpcgen: add an XDR protocol parser rpcgen: define a visitor API for XDR protocol specs rpcgen: add a C code generator for XDR protocol specs rpcgen: add test case for XDR serialization rpcgen: define entrypoint for running new rpcgen impl build: switch over to new rpc generator code rpcgen: add g_auto function support rpc: use g_auto for client RPC return parameters admin: use g_auto for client RPC return parameters remote: use g_auto for client RPC return parameters rpc: add helpers for XDR type serialization
72 files changed, 4897 insertions(+), 771 deletions(-)
Reviewed-by: Michal Privoznik <mprivozn@redhat.com> but please do see individual replies before pushing. I'm suggesting some squash-ins. Michal

FYI, this series was fully acked and I completely forgot to then push it. Todays' fix for rpcgen on macOS reminded me about this. I've tested that with this series applied, macOS is fine, and the only rebase conflicts were trivial on meson.build and syntax-check.mk. So I'm intending to push this series, minus the last patch. On Wed, Mar 08, 2023 at 11:38:57AM -0500, Daniel P. Berrangé wrote:
This series something I was hacking on a little while back in an attempt to make our RPC layer more maintainable. There are many aspects I'm unhappy about with current code
* When serializing a message we have no clue how big it will be, but xdrmem_create wants a fixed size, so we have to keep trying to serialize in a loop making it bigger each time
* We don't control memory allocation/free'ing directly so we can't do a virSecureErase on fields inside the RPC message struct that handle secrets.
* The XDR API is generally unpleasant to use as it is outside our virNetMessage object. Ideally we would be reading/writing directly from/to the virNetMessage buffer with APIs on virNetMessage,instead of indirectly via a XDR object.
* We want more from XDR than it actually gives us. Our XDR protocol files have annotations to express what we want our code generator todo, or for ACLs. The relationship between the structs and the message numbers is implicit. Essentially we've defined our own language indirectly via comments, and then parse this with regexes which is horrid.
* The code rpcgen creates is poor quality which we have to post-process to fix bugs/problems. It also lacks support for modern features like g_auto.
Anyway, in a fit of rage I looked at the XDR RFC and thought..
This language is trivial, why do we need to outsource to rpcgen and libtirpc instead of dealing with it directly.
This small series moves in that direction. It creates an XDR language lexer and parser, and then a code generator which emits code that is (nearly) identical to what rpcgen would emit. This is sufficient to eliminate rpcgen usage and support g_auto. Since we're still using libtirpc at this stage we can be confident we're still doing the same thing on the wire. I've got some unit tests too with the rpcgen generation to validate stuff.
The next step is to change the code generator so that instead of generating code for libtirpc APIs, it will instead directly speak virNetMessage APIs. That would give us full control over our RPC stack guaranteed to be platform portable instead of fighting slight differences in RPC libraries (eg xdr_quad vs xdr_int64 madness).
I was going to wait until I had written such code before sending this series, but I've got diverted onto other more important tasks. So here at least is what I have so far.
After that foundation is done, we are in a place where we can actually do more innovative things. For example we can directly extend the XDR protocol language if we like, turning our magic comments into properly parsable constructs.
With this, we would be in a position to replace our Perl RPC client/server dispatch code generators with something that is more supportable in Python. The python code would work with properly represented objects and formal parsers and not regexes and anonymous complex perl data structures.
Daniel P. Berrangé (16): rpcgen: drop type-puning workarounds build-aux: skip E203 and W503 flake8 checks build-aux: introduce 'black' tool for python formatting rpcgen: add an XDR protocol lexer rpcgen: add an XDR protocol abstract syntax tree rpcgen: add an XDR protocol parser rpcgen: define a visitor API for XDR protocol specs rpcgen: add a C code generator for XDR protocol specs rpcgen: add test case for XDR serialization rpcgen: define entrypoint for running new rpcgen impl build: switch over to new rpc generator code rpcgen: add g_auto function support rpc: use g_auto for client RPC return parameters admin: use g_auto for client RPC return parameters remote: use g_auto for client RPC return parameters rpc: add helpers for XDR type serialization
build-aux/Makefile.in | 1 + build-aux/meson.build | 5 + build-aux/syntax-check.mk | 42 +- libvirt.spec.in | 2 +- meson.build | 13 +- scripts/meson.build | 2 + scripts/rpcgen/main.py | 90 ++ scripts/rpcgen/meson.build | 16 + scripts/rpcgen/rpcgen/ast.py | 270 ++++++ scripts/rpcgen/rpcgen/generator.py | 509 ++++++++++++ scripts/rpcgen/rpcgen/lexer.py | 213 +++++ scripts/rpcgen/rpcgen/meson.build | 7 + scripts/rpcgen/rpcgen/parser.py | 497 +++++++++++ scripts/rpcgen/rpcgen/visitor.py | 156 ++++ scripts/rpcgen/tests/demo.c | 495 +++++++++++ scripts/rpcgen/tests/demo.h | 264 ++++++ scripts/rpcgen/tests/demo.x | 127 +++ scripts/rpcgen/tests/meson.build | 20 + scripts/rpcgen/tests/simple.x | 35 + scripts/rpcgen/tests/test_demo.c | 782 ++++++++++++++++++ scripts/rpcgen/tests/test_demo_enum.bin | Bin 0 -> 4 bytes .../tests/test_demo_enum_fixed_array.bin | Bin 0 -> 52 bytes .../tests/test_demo_enum_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_enum_pointer_set.bin | Bin 0 -> 8 bytes .../rpcgen/tests/test_demo_enum_scalar.bin | Bin 0 -> 4 bytes .../test_demo_enum_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_enum_variable_array_set.bin | Bin 0 -> 16 bytes .../tests/test_demo_int_fixed_array.bin | Bin 0 -> 12 bytes .../tests/test_demo_int_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_int_pointer_set.bin | Bin 0 -> 8 bytes scripts/rpcgen/tests/test_demo_int_scalar.bin | Bin 0 -> 4 bytes .../test_demo_int_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_int_variable_array_set.bin | Bin 0 -> 16 bytes .../tests/test_demo_opaque_fixed_array.bin | Bin 0 -> 12 bytes .../test_demo_opaque_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_opaque_variable_array_set.bin | Bin 0 -> 8 bytes .../test_demo_string_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_string_variable_array_set.bin | Bin 0 -> 12 bytes scripts/rpcgen/tests/test_demo_struct.bin | Bin 0 -> 8 bytes .../tests/test_demo_struct_fixed_array.bin | Bin 0 -> 136 bytes .../tests/test_demo_struct_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_struct_pointer_set.bin | Bin 0 -> 12 bytes .../rpcgen/tests/test_demo_struct_scalar.bin | 1 + .../test_demo_struct_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_struct_variable_array_set.bin | Bin 0 -> 28 bytes .../tests/test_demo_test_struct_all_types.bin | Bin 0 -> 1752 bytes scripts/rpcgen/tests/test_demo_union_case.bin | Bin 0 -> 8 bytes .../rpcgen/tests/test_demo_union_default.bin | Bin 0 -> 8 bytes .../tests/test_demo_union_fixed_array.bin | Bin 0 -> 168 bytes .../tests/test_demo_union_no_default_case.bin | Bin 0 -> 8 bytes .../tests/test_demo_union_pointer_null.bin | Bin 0 -> 4 bytes .../tests/test_demo_union_pointer_set.bin | Bin 0 -> 12 bytes .../rpcgen/tests/test_demo_union_scalar.bin | Bin 0 -> 8 bytes .../test_demo_union_variable_array_empty.bin | Bin 0 -> 4 bytes .../test_demo_union_variable_array_set.bin | Bin 0 -> 28 bytes .../test_demo_union_void_default_case.bin | Bin 0 -> 8 bytes .../test_demo_union_void_default_default.bin | 1 + scripts/rpcgen/tests/test_generator.py | 60 ++ scripts/rpcgen/tests/test_lexer.py | 116 +++ scripts/rpcgen/tests/test_parser.py | 91 ++ src/admin/admin_remote.c | 50 +- src/admin/meson.build | 8 +- src/locking/meson.build | 8 +- src/logging/meson.build | 8 +- src/lxc/meson.build | 12 +- src/remote/meson.build | 8 +- src/remote/remote_driver.c | 754 ++++++----------- src/rpc/gendispatch.pl | 60 +- src/rpc/genprotocol.pl | 144 ---- src/rpc/meson.build | 9 +- src/rpc/virnetmessage.c | 704 ++++++++++++++++ src/rpc/virnetmessage.h | 88 ++ 72 files changed, 4897 insertions(+), 771 deletions(-) create mode 100755 scripts/rpcgen/main.py create mode 100644 scripts/rpcgen/meson.build create mode 100644 scripts/rpcgen/rpcgen/ast.py create mode 100644 scripts/rpcgen/rpcgen/generator.py create mode 100644 scripts/rpcgen/rpcgen/lexer.py create mode 100644 scripts/rpcgen/rpcgen/meson.build create mode 100644 scripts/rpcgen/rpcgen/parser.py create mode 100644 scripts/rpcgen/rpcgen/visitor.py create mode 100644 scripts/rpcgen/tests/demo.c create mode 100644 scripts/rpcgen/tests/demo.h create mode 100644 scripts/rpcgen/tests/demo.x create mode 100644 scripts/rpcgen/tests/meson.build create mode 100644 scripts/rpcgen/tests/simple.x create mode 100644 scripts/rpcgen/tests/test_demo.c create mode 100644 scripts/rpcgen/tests/test_demo_enum.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_enum_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_int_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_opaque_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_opaque_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_opaque_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_string_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_string_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_struct_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_test_struct_all_types.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_case.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_default.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_fixed_array.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_no_default_case.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_pointer_null.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_pointer_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_scalar.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_variable_array_empty.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_variable_array_set.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_void_default_case.bin create mode 100644 scripts/rpcgen/tests/test_demo_union_void_default_default.bin create mode 100644 scripts/rpcgen/tests/test_generator.py create mode 100644 scripts/rpcgen/tests/test_lexer.py create mode 100644 scripts/rpcgen/tests/test_parser.py delete mode 100755 src/rpc/genprotocol.pl
-- 2.39.1
With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
participants (3)
-
Daniel P. Berrangé
-
Ján Tomko
-
Michal Prívozník