diff --git a/configure.ac b/configure.ac index b2ba930d48a9b2e59326713955d8ef0b0800d5a4..62cd17742a2eb95189f1d651903b5a7d9110f2b3 100644 --- a/configure.ac +++ b/configure.ac @@ -117,6 +117,7 @@ if test "x$have_cpuid" = xyes; then fi AC_MSG_RESULT([$have_cpuid]) +AC_CHECK_SIZEOF([long]) dnl Availability of various common functions (non-fatal if missing), dnl and various less common threadsafe functions diff --git a/daemon/remote.c b/daemon/remote.c index 1897be8b50eaac9009e3ef3f1fcac0a4ec028c5b..64478cc7a2674749c3be02367a4a6417b3e03e24 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -68,6 +68,24 @@ virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \ __FUNCTION__, __LINE__, __VA_ARGS__) +#if SIZEOF_LONG < 8 +# define HYPER_TO_TYPE(_type, _to, _from) \ + do { \ + if ((_from) != (_type)(_from)) { \ + virNetError(VIR_ERR_INTERNAL_ERROR, \ + _("conversion from hyper to %s overflowed"), #_type); \ + goto cleanup; \ + } \ + (_to) = (_from); \ + } while (0) + +# define HYPER_TO_LONG(_to, _from) HYPER_TO_TYPE(long, _to, _from) +# define HYPER_TO_ULONG(_to, _from) HYPER_TO_TYPE(unsigned long, _to, _from) +#else +# define HYPER_TO_LONG(_to, _from) (_to) = (_from) +# define HYPER_TO_ULONG(_to, _from) (_to) = (_from) +#endif + static virDomainPtr get_nonnull_domain(virConnectPtr conn, remote_nonnull_domain domain); static virNetworkPtr get_nonnull_network(virConnectPtr conn, remote_nonnull_network network); static virInterfacePtr get_nonnull_interface(virConnectPtr conn, remote_nonnull_interface iface); diff --git a/daemon/remote_generator.pl b/daemon/remote_generator.pl index ac808fb0c69023fac91b9a8db2d9a32615cf68c8..f85cc6b04b12e01e4242f1954a34a3ca7ef60585 100755 --- a/daemon/remote_generator.pl +++ b/daemon/remote_generator.pl @@ -174,6 +174,58 @@ while (<PROTOCOL>) { close(PROTOCOL); +# this hash contains the procedures that are allowed to map [unsigned] hyper +# to [unsigned] long for legacy reasons in their signature and return type. +# this list is fixed. new procedures and public APIs have to map [unsigned] +# hyper to [unsigned] long long +my $long_legacy = { + DomainGetMaxMemory => { ret => { memory => 1 } }, + DomainGetInfo => { ret => { maxMem => 1, memory => 1 } }, + DomainMigrate => { arg => { flags => 1, resource => 1 } }, + DomainMigrate2 => { arg => { flags => 1, resource => 1 } }, + DomainMigrateBegin3 => { arg => { flags => 1, resource => 1 } }, + DomainMigrateConfirm3 => { arg => { flags => 1, resource => 1 } }, + DomainMigrateDirect => { arg => { flags => 1, resource => 1 } }, + DomainMigrateFinish => { arg => { flags => 1 } }, + DomainMigrateFinish2 => { arg => { flags => 1 } }, + DomainMigrateFinish3 => { arg => { flags => 1 } }, + DomainMigratePeer2Peer => { arg => { flags => 1, resource => 1 } }, + DomainMigratePerform => { arg => { flags => 1, resource => 1 } }, + DomainMigratePerform3 => { arg => { flags => 1, resource => 1 } }, + DomainMigratePrepare => { arg => { flags => 1, resource => 1 } }, + DomainMigratePrepare2 => { arg => { flags => 1, resource => 1 } }, + DomainMigratePrepare3 => { arg => { flags => 1, resource => 1 } }, + DomainMigratePrepareTunnel => { arg => { flags => 1, resource => 1 } }, + DomainMigratePrepareTunnel3 => { arg => { flags => 1, resource => 1 } }, + DomainMigrateToURI => { arg => { flags => 1, resource => 1 } }, + DomainMigrateToURI2 => { arg => { flags => 1, resource => 1 } }, + DomainMigrateVersion1 => { arg => { flags => 1, resource => 1 } }, + DomainMigrateVersion2 => { arg => { flags => 1, resource => 1 } }, + DomainMigrateVersion3 => { arg => { flags => 1, resource => 1 } }, + DomainMigrateSetMaxSpeed => { arg => { bandwidth => 1 } }, + DomainSetMaxMemory => { arg => { memory => 1 } }, + DomainSetMemory => { arg => { memory => 1 } }, + DomainSetMemoryFlags => { arg => { memory => 1 } }, + GetLibVersion => { ret => { lib_ver => 1 } }, + GetVersion => { ret => { hv_ver => 1 } }, + NodeGetInfo => { ret => { memory => 1 } }, +}; + +sub hyper_to_long +{ + my $proc_name = shift; + my $ret_or_arg = shift; + my $member = shift; + + if ($long_legacy->{$proc_name} and + $long_legacy->{$proc_name}->{$ret_or_arg} and + $long_legacy->{$proc_name}->{$ret_or_arg}->{$member}) { + return 1; + } else { + return 0 + } +} + #---------------------------------------------------------------------- # Output @@ -378,12 +430,29 @@ elsif ($opt_b) { } push(@args_list, "args->$1"); - } elsif ($args_member =~ m/^(unsigned )?(int|hyper) (\S+);/) { + } elsif ($args_member =~ m/^(unsigned )?int (\S+);/) { if (! @args_list) { push(@args_list, "conn"); } - push(@args_list, "args->$3"); + push(@args_list, "args->$2"); + } elsif ($args_member =~ m/^(unsigned )?hyper (\S+);/) { + if (! @args_list) { + push(@args_list, "conn"); + } + + my $arg_name = $2; + + if (hyper_to_long($call->{ProcName}, "arg", $arg_name)) { + my $type_name = $1; $type_name .= "long"; + my $sign = ""; $sign = "U" if ($1); + + push(@vars_list, "$type_name $arg_name"); + push(@getters_list, " HYPER_TO_${sign}LONG($arg_name, args->$arg_name);\n"); + push(@args_list, "$arg_name"); + } else { + push(@args_list, "args->$arg_name"); + } } elsif ($args_member =~ m/^(\/)?\*/) { # ignore comments } else { @@ -411,6 +480,10 @@ elsif ($opt_b) { foreach my $ret_member (@{$call->{ret_members}}) { if ($multi_ret) { if ($ret_member =~ m/^(unsigned )?(char|short|int|hyper) (\S+)\[\S+\];/) { + if ($2 eq "hyper" and hyper_to_long($call->{ProcName}, "ret", $3)) { + die "legacy [u]long hyper arrays aren't supported"; + } + push(@ret_list, "memcpy(ret->$3, tmp.$3, sizeof ret->$3);"); } elsif ($ret_member =~ m/^(unsigned )?(char|short|int|hyper) (\S+);/) { push(@ret_list, "ret->$3 = tmp.$3;"); @@ -502,6 +575,10 @@ elsif ($opt_b) { } } } elsif ($ret_member =~ m/^(?:unsigned )?hyper (\S+)<(\S+)>;\s*\/\*\s*insert@(\d+)\s*\*\//) { + if (hyper_to_long($call->{ProcName}, "ret", $1)) { + die "legacy [u]long hyper arrays aren't supported"; + } + push(@vars_list, "int len"); push(@ret_list, "ret->$1.$1_len = len;"); push(@free_list_on_error, "VIR_FREE(ret->$1.$1_val);"); @@ -523,14 +600,22 @@ elsif ($opt_b) { # error out on unannotated arrays die "hyper array without insert@<offset> annotation: $ret_member"; } elsif ($ret_member =~ m/^(unsigned )?hyper (\S+);/) { - my $type_name; + my $type_name = $1; my $ret_name = $2; + my $ret_assign; - $type_name = $1 if ($1); - $type_name .= "long"; + if (hyper_to_long($call->{ProcName}, "ret", $ret_name)) { + my $sign = ""; $sign = "U" if ($1); + + $type_name .= "long"; + $ret_assign = "HYPER_TO_${sign}LONG(ret->$ret_name, $ret_name);"; + } else { + $type_name .= "long long"; + $ret_assign = "ret->$ret_name = $ret_name;"; + } push(@vars_list, "$type_name $ret_name"); - push(@ret_list, "ret->$ret_name = $ret_name;"); + push(@ret_list, $ret_assign); $single_ret_var = $ret_name; if ($call->{ProcName} eq "DomainGetMaxMemory" or @@ -888,22 +973,20 @@ elsif ($opt_k) { push(@setters_list, "args.$arg_name.${arg_name}_val = (char *)$arg_name;"); push(@setters_list, "args.$arg_name.${arg_name}_len = ${arg_name}len;"); push(@args_check_list, { name => "\"$arg_name\"", arg => "${arg_name}len", limit => $limit }); - } elsif ($args_member =~ m/^(unsigned )?(int|hyper) (\S+);/) { - my $type_name; - my $arg_name = $3; - - $type_name = $1 if ($1); - $type_name .= $2; - $type_name =~ s/hyper/long/; - - # SPECIAL: some hyper parameters map to long longs - if (($call->{ProcName} eq "DomainMigrateSetMaxDowntime" and - $arg_name eq "downtime") or - ($call->{ProcName} eq "StorageVolUpload" and - ($arg_name eq "offset" or $arg_name eq "length")) or - ($call->{ProcName} eq "StorageVolDownload" and - ($arg_name eq "offset" or $arg_name eq "length"))) { - $type_name .= " long"; + } elsif ($args_member =~ m/^(unsigned )?int (\S+);/) { + my $type_name = $1; $type_name .= "int"; + my $arg_name = $2; + + push(@args_list, "$type_name $arg_name"); + push(@setters_list, "args.$arg_name = $arg_name;"); + } elsif ($args_member =~ m/^(unsigned )?hyper (\S+);/) { + my $type_name = $1; + my $arg_name = $2; + + if (hyper_to_long($call->{ProcName}, "arg", $arg_name)) { + $type_name .= "long"; + } else { + $type_name .= "long long"; } push(@args_list, "$type_name $arg_name"); @@ -961,13 +1044,23 @@ elsif ($opt_k) { foreach my $ret_member (@{$call->{ret_members}}) { if ($multi_ret) { if ($ret_member =~ m/^(unsigned )?(char|short|int|hyper) (\S+)\[\S+\];/) { + if ($2 eq "hyper" and hyper_to_long($call->{ProcName}, "ret", $3)) { + die "legacy [u]long hyper arrays aren't supported"; + } + push(@ret_list, "memcpy(result->$3, ret.$3, sizeof result->$3);"); } elsif ($ret_member =~ m/<\S+>;/ or $ret_member =~ m/\[\S+\];/) { # just make all other array types fail die "unhandled type for multi-return-value for " . "procedure $call->{name}: $ret_member"; } elsif ($ret_member =~ m/^(unsigned )?(char|short|int|hyper) (\S+);/) { - push(@ret_list, "result->$3 = ret.$3;"); + if ($2 eq "hyper" and hyper_to_long($call->{ProcName}, "ret", $3)) { + my $sign = ""; $sign = "U" if ($1); + + push(@ret_list, "HYPER_TO_${sign}LONG(result->$3, ret.$3);"); + } else { + push(@ret_list, "result->$3 = ret.$3;"); + } } else { die "unhandled type for multi-return-value for " . "procedure $call->{name}: $ret_member"; @@ -1039,22 +1132,22 @@ elsif ($opt_k) { $single_ret_var = "int rv = -1"; $single_ret_type = "int"; } elsif ($ret_member =~ m/^unsigned hyper (\S+);/) { - my $arg_name = $1; + my $ret_name = $1; if ($call->{ProcName} =~ m/Get(Lib)?Version/) { - push(@args_list, "unsigned long *$arg_name"); - push(@ret_list, "if ($arg_name) *$arg_name = ret.$arg_name;"); + push(@args_list, "unsigned long *$ret_name"); + push(@ret_list, "if ($ret_name) HYPER_TO_ULONG(*$ret_name, ret.$ret_name);"); push(@ret_list, "rv = 0;"); $single_ret_var = "int rv = -1"; $single_ret_type = "int"; - } elsif ($call->{ProcName} eq "NodeGetFreeMemory") { - push(@ret_list, "rv = ret.$arg_name;"); - $single_ret_var = "unsigned long long rv = 0"; - $single_ret_type = "unsigned long long"; - } else { - push(@ret_list, "rv = ret.$arg_name;"); + } elsif (hyper_to_long($call->{ProcName}, "ret", $ret_name)) { + push(@ret_list, "HYPER_TO_ULONG(rv, ret.$ret_name);"); $single_ret_var = "unsigned long rv = 0"; $single_ret_type = "unsigned long"; + } else { + push(@ret_list, "rv = ret.$ret_name;"); + $single_ret_var = "unsigned long long rv = 0"; + $single_ret_type = "unsigned long long"; } } elsif ($ret_member =~ m/^(\/)?\*/) { # ignore comments diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 8e3cd89bf22eb5eea4954333fc4252ef3abe3891..ac0c6f7aeff1074414a9082a01db265b32553ff0 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -87,6 +87,24 @@ #define VIR_FROM_THIS VIR_FROM_REMOTE +#if SIZEOF_LONG < 8 +# define HYPER_TO_TYPE(_type, _to, _from) \ + do { \ + if ((_from) != (_type)(_from)) { \ + remoteError(VIR_ERR_INTERNAL_ERROR, \ + _("conversion from hyper to %s overflowed"), #_type); \ + goto done; \ + } \ + (_to) = (_from); \ + } while (0) + +# define HYPER_TO_LONG(_to, _from) HYPER_TO_TYPE(long, _to, _from) +# define HYPER_TO_ULONG(_to, _from) HYPER_TO_TYPE(unsigned long, _to, _from) +#else +# define HYPER_TO_LONG(_to, _from) (_to) = (_from) +# define HYPER_TO_ULONG(_to, _from) (_to) = (_from) +#endif + static int inside_daemon = 0; struct remote_thread_call;