On Wed, Feb 22, 2023 at 11:24:04AM +0100, Ales Musil wrote:
> On Wed, Feb 22, 2023 at 10:59 AM Simon Horman <simon.hor...@corigine.com>
> wrote:

...

Hi Ales,

> Hi Simon,
> thank you for your review.

you are welcome.

> > > ---
> > >  utilities/ovn-dbctl.c | 76 +++++++++++++++++++++++++++----------------
> > >  1 file changed, 48 insertions(+), 28 deletions(-)
> > >
> > > diff --git a/utilities/ovn-dbctl.c b/utilities/ovn-dbctl.c
> > > index f0ee0ba05..f96cab64e 100644
> > > --- a/utilities/ovn-dbctl.c
> > > +++ b/utilities/ovn-dbctl.c
> > > @@ -109,6 +109,15 @@ static void server_loop(const struct
> > ovn_dbctl_options *dbctl_options,
> > >                          struct ovsdb_idl *idl, int argc, char *argv[]);
> > >  static void ovn_dbctl_exit(int status);
> > >
> > > +static void
> > > +destroy_argv(int argc, char **argv)
> > > +{
> > > +    for (int i = 0; i < argc; i++) {
> > > +        free(argv[i]);
> > > +    }
> > > +    free(argv);
> > > +}
> > > +
> >
> > This destroy_argv seems to be the dual of ovs_cmdl_env_parse_all(),
> > does it belong in lib/command-line.c ?
> >
> 
> It might fit more into command-line.c however getting something into ovs
> and then
> reflect that in ovn is way longer process.

Fair enough.
I agree it makes sense to start with an OVN fix.

> > Also, do all other users of ovs_cmdl_env_parse_all() - in both OVS and OVN
> > -
> > unwind correctly on error?
> >
> 
> I can see only single usage and that's here. So before this patch the
> answer would be no.

Great, thanks for checking.

> > >  int
> > >  ovn_dbctl_main(int argc, char *argv[],
> > >                 const struct ovn_dbctl_options *dbctl_options)
> > > @@ -151,6 +160,7 @@ ovn_dbctl_main(int argc, char *argv[],
> > >      char *error_s = ovs_cmdl_parse_all(argc, argv_, get_all_options(),
> > >                                         &parsed_options,
> > &n_parsed_options);
> > >      if (error_s) {
> > > +        destroy_argv(argc, argv_);
> > >          ctl_fatal("%s", error_s);
> > >      }
> > >
> > > @@ -179,6 +189,7 @@ ovn_dbctl_main(int argc, char *argv[],
> > >      bool daemon_mode = false;
> > >      if (get_detach()) {
> > >          if (argc != optind) {
> > > +            destroy_argv(argc, argv_);
> > >              ctl_fatal("non-option arguments not supported with --detach
> > "
> > >                        "(use --help for help)");
> > >          }
> > > @@ -206,11 +217,8 @@ ovn_dbctl_main(int argc, char *argv[],
> > >          if (error) {
> > >              ovsdb_idl_destroy(idl);
> > >              idl = the_idl = NULL;
> > > +            destroy_argv(argc, argv_);
> > >
> > > -            for (int i = 0; i < argc; i++) {
> > > -                free(argv_[i]);
> > > -            }
> > > -            free(argv_);
> > >              ctl_fatal("%s", error);
> > >          }
> > >
> > > @@ -239,21 +247,15 @@ cleanup:
> > >          }
> > >          free(commands);
> > >          if (error) {
> > > -            for (int i = 0; i < argc; i++) {
> > > -                free(argv_[i]);
> > > -            }
> > > -            free(argv_);
> > > +            destroy_argv(argc, argv_);
> > >              ctl_fatal("%s", error);
> > >          }
> > >      }
> > >
> > >      ovsdb_idl_destroy(idl);
> > >      idl = the_idl = NULL;
> > > +    destroy_argv(argc, argv_);
> > >
> > > -    for (int i = 0; i < argc; i++) {
> > > -        free(argv_[i]);
> > > -    }
> > > -    free(argv_);
> > >      exit(EXIT_SUCCESS);
> > >  }
> > >
> > > @@ -1240,27 +1242,31 @@ dbctl_client(const struct ovn_dbctl_options
> > *dbctl_options,
> > >
> > >      ctl_timeout_setup(timeout);
> > >
> > > +    char *err = NULL;
> >
> > perhaps error_str is a nicer name for this?
> >
> > > +    char *cmd_error = NULL;
> > > +    char *cmd_result = NULL;
> > > +    int exit_status = EXIT_SUCCESS;
> > >      struct jsonrpc *client;
> >
> > I'm not sure if reverse xmas tree - longest line to shortest - is
> > a thing for local variable declarations in ovn.
> >
> 
> I don't think it's strictly held, but it shouldn't hurt.

Yeah, that's what I was thinking too.

> > > +
> > >      int error = unixctl_client_create(socket_name, &client);
> > >      if (error) {
> > > -        ctl_fatal("%s: could not connect to %s daemon (%s); "
> > > -                  "unset %s to avoid using daemon",
> > > -                  socket_name, program_name, ovs_strerror(error),
> > > -                  dbctl_options->daemon_env_var_name);
> > > +        err = xasprintf("%s: could not connect to %s daemon (%s); "
> > > +                        "unset %s to avoid using daemon",
> > > +                        socket_name, program_name, ovs_strerror(error),
> > > +                        dbctl_options->daemon_env_var_name);
> > > +        goto cleanup;
> > >      }
> > >
> > > -    char *cmd_result;
> > > -    char *cmd_error;
> > > +
> > >      error = unixctl_client_transact(client, "run",
> > >                                      args.n, args.names,
> > >                                      &cmd_result, &cmd_error);
> > >      if (error) {
> > > -        ctl_fatal("%s: transaction error (%s)",
> > > -                  socket_name, ovs_strerror(error));
> > > +        err = xasprintf("%s: transaction error (%s)",
> > > +                        socket_name, ovs_strerror(error));
> > > +        goto cleanup;
> > >      }
> > > -    svec_destroy(&args);
> > >
> > > -    int exit_status;
> > >      if (cmd_error) {
> > >          exit_status = EXIT_FAILURE;
> > >          fprintf(stderr, "%s: %s", program_name, cmd_error);
> > > @@ -1268,12 +1274,26 @@ dbctl_client(const struct ovn_dbctl_options
> > *dbctl_options,
> > >          exit_status = EXIT_SUCCESS;
> > >          fputs(cmd_result, stdout);
> > >      }
> > > -    free(cmd_result);
> > > -    free(cmd_error);
> > > -    jsonrpc_close(client);
> > > -    for (int i = 0; i < argc; i++) {
> > > -        free(argv[i]);
> > > +
> > > +cleanup:
> > > +    if (err) {
> > > +        exit_status = EXIT_FAILURE;
> > > +        VLOG_ERR("%s", err);
> > > +        ovs_error(0, "%s", err);
> > > +        free(err);
> > >      }
> > > -    free(argv);
> > > +
> > > +    if (cmd_result) {
> > > +        free(cmd_result);
> > > +    }
> > > +
> > > +    if (cmd_error) {
> > > +        free(cmd_error);
> > > +    }
> >
> > I don't think the cmd_result and cmd_error conditions are required
> > as free should do nothing when passed NULL.
> >
> 
> Isn't free behavior for NULL platform dependent? I was under the impression
> that it is.
> But I might be mistaken.

Maybe: not so secret fact is that I'm a Linux person.

In any case, perhaps goto labels can be arranged to avoid
the conditionals.

> > > +
> > > +    jsonrpc_close(client);
> > > +    svec_destroy(&args);
> > > +    destroy_argv(argc, argv);
> > > +
> > >      exit(exit_status);
> > >  }
> >
> > Overall, I think it would be nice to re-arrange things a bit so that:
> >
> > 1. Non-error paths are not covered by conditionals.
> > 2. The code covered by goto labels(s) does not include conditionals.
> > 3. exit_status is always set explicitly, rather than
> >    relying on overriding a default value.
> >
> > Something like this (*compile tested only!*).
> > And if so, perhaps a cleanup patch is warranted before the
> > patch to fix the problem at hand.
> >
> >     char *cmd_result = NULL;
> >     char *cmd_error = NULL;
> >     struct jsonrpc *client;
> >     int exit_status;
> >     char *error_str;
> >
> >     int error = unixctl_client_create(socket_name, &client);
> >     if (error) {
> >         error_str = xasprintf("%s: could not connect to %s daemon (%s); "
> >                               "unset %s to avoid using daemon",
> >                               socket_name, program_name,
> > ovs_strerror(error),
> >                               dbctl_options->daemon_env_var_name);
> >         goto log_error;
> >     }
> >
> >
> >     error = unixctl_client_transact(client, "run",
> >                                     args.n, args.names,
> >                                     &cmd_result, &cmd_error);
> >     if (error) {
> >         error_str = xasprintf("%s: transaction error (%s)",
> >                               socket_name, ovs_strerror(error));
> >         goto log_error;
> >     }
> >
> >     if (cmd_error) {
> >         fprintf(stderr, "%s: %s", program_name, cmd_error);
> >         goto error;
> >     }
> >
> >     fputs(cmd_result, stdout);
> >     exit_status = EXIT_SUCCESS;
> >     goto cleanup;
> >
> > log_error:
> >     VLOG_ERR("%s", error_str);
> >     ovs_error(0, "%s", error_str);
> >     free(error_str);
> >
> > error:
> >     exit_status = EXIT_FAILURE;
> >
> > cleanup:
> >     free(cmd_result);
> >     free(cmd_error);
> >     jsonrpc_close(client);
> >     svec_destroy(&args);
> >     destroy_argv(argc, argv);
> >
> >     exit(exit_status);
> >
> >
> >
> >
> That looks way better, the initial idea was to do that without too big of a
> change which did not
> work very well.

Understood. And for a fix perhaps a minimal approach is better.
But, OTOH, perhaps the overall delta is similar. I'm not sure.
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to