diff --git a/src/communicator/comm.c b/src/communicator/comm.c index 6e84e48e00..d1c25e4b8e 100644 --- a/src/communicator/comm.c +++ b/src/communicator/comm.c @@ -25,6 +25,7 @@ #include "threads/mutex.h" #include "util/bit_ops.h" #include "util/output.h" +#include "util/convert.h" #include "mca/topo/topo.h" #include "mca/topo/base/base.h" #include "mca/ns/ns.h" @@ -829,7 +830,8 @@ ompi_proc_t **ompi_comm_get_rprocs ( ompi_communicator_t *local_comm, int local_rank, local_size; ompi_proc_t **rprocs=NULL; char *rnamebuf=NULL; - int len, rlen; + size_t size_len; + int int_len, rlen; orte_buffer_t *sbuf=NULL, *rbuf=NULL; void *sendbuf; char *recvbuf; @@ -849,18 +851,22 @@ ompi_proc_t **ompi_comm_get_rprocs ( ompi_communicator_t *local_comm, if ( OMPI_SUCCESS != rc ) { goto err_exit; } - if (ORTE_SUCCESS != (rc = orte_dps.unload(sbuf, &sendbuf, (size_t*)&len))) { + if (ORTE_SUCCESS != (rc = orte_dps.unload(sbuf, &sendbuf, &size_len))) { goto err_exit; - } + } /* send the remote_leader the length of the buffer */ rc = MCA_PML_CALL(irecv (&rlen, 1, MPI_INT, remote_leader, tag, - bridge_comm, &req )); + bridge_comm, &req )); if ( OMPI_SUCCESS != rc ) { goto err_exit; } - rc = MCA_PML_CALL(send (&len, 1, MPI_INT, remote_leader, tag, - MCA_PML_BASE_SEND_STANDARD, bridge_comm )); + if (OMPI_SUCCESS != (rc = ompi_sizet2int(size_len, &int_len, true))) { + goto err_exit; + } + printf("Got sizet len: %ld, int %d\n", size_len, int_len); + rc = MCA_PML_CALL(send (&int_len, 1, MPI_INT, remote_leader, tag, + MCA_PML_BASE_SEND_STANDARD, bridge_comm )); if ( OMPI_SUCCESS != rc ) { goto err_exit; } @@ -901,7 +907,7 @@ ompi_proc_t **ompi_comm_get_rprocs ( ompi_communicator_t *local_comm, if ( OMPI_SUCCESS != rc ) { goto err_exit; } - rc = MCA_PML_CALL(send(sendbuf, len, MPI_BYTE, remote_leader, tag, + rc = MCA_PML_CALL(send(sendbuf, int_len, MPI_BYTE, remote_leader, tag, MCA_PML_BASE_SEND_STANDARD, bridge_comm )); if ( OMPI_SUCCESS != rc ) { goto err_exit; diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 46f19d9ee0..54f2d88c17 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -29,6 +29,7 @@ headers = \ basename.h \ bit_ops.h \ cmd_line.h \ + convert.h \ ompi_environ.h \ few.h \ if.h \ @@ -57,6 +58,7 @@ libompiutil_la_SOURCES = \ argv.c \ basename.c \ cmd_line.c \ + convert.c \ few.c \ if.c \ malloc.c \ diff --git a/src/util/convert.c b/src/util/convert.c new file mode 100644 index 0000000000..9744f25670 --- /dev/null +++ b/src/util/convert.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2004-2005 The Trustees of Indiana University. + * All rights reserved. + * Copyright (c) 2004-2005 The Trustees of the University of Tennessee. + * All rights reserved. + * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * Copyright (c) 2004-2005 The Regents of the University of California. + * All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#include "ompi_config.h" + +#include +#include + +#include "include/constants.h" +#include "util/convert.h" + + +static bool init_done = false; +static unsigned int int_pos = -1; + + +static void ompi_sizet2int_init(void); +static void warn(void); + + +int ompi_sizet2int(size_t in, int *out, bool want_check) +{ +#if SIZEOF_SIZE_T <= SIZEOF_INT + *out = in; + return OMPI_SUCCESS; +#else + int *pos = (int *) ∈ + unsigned int i; + + if (!init_done) { + ompi_sizet2int_init(); + } + + *out = pos[int_pos]; + if (want_check) { + /* Remember that size_t is signed, so we don't need to check + for when in < 0 (in which case the internal checks would be + slightly different) */ + for (i = 0; i < (sizeof(in) / sizeof(*out)); ++i) { + if (i != int_pos) { + if (pos[i] != 0) { + warn(); + return OMPI_ERR_NOT_IMPLEMENTED; + } + } + } + } + + return OMPI_SUCCESS; +#endif +} + + +static void ompi_sizet2int_init(void) +{ + size_t bogus = 1; + int *i = (int *) &bogus; + + for (int_pos = 0; int_pos < (sizeof(bogus) / sizeof(int)); ++int_pos) { + if (i[int_pos] == 1) { + break; + } + } + + init_done = true; +} + + +static void warn(void) +{ +#if OMPI_ENABLE_DEBUG + /* Developer builds */ + fprintf(stderr, "WARNING: A size_t value was attempted to be cast to an int (sizeof(size_t) == %ld, sizeof(int) == %ld), but data was lost in the conversion. This should never happen (i.e., we should never try to convert a value that will be 'too big'). Since this is a developer build, I'm going to abort, and you can check the corefile. Enjoy.\n", sizeof(size_t), sizeof(int)); + abort(); +#else + static bool warned = false; + + if (!warned) { + fprintf(stderr, "Open MPI WARNING: A bad cast (size_t->int) occurred.\n"); + fprintf(stderr, "Please inform the Open MPI developers. This message will not repeat.\n"); + fprintf(stderr, "Attempting to continue (no guarantees about correctness...\n"); + warned = true; + } +#endif +} diff --git a/src/util/convert.h b/src/util/convert.h new file mode 100644 index 0000000000..c802e98a8c --- /dev/null +++ b/src/util/convert.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2004-2005 The Trustees of Indiana University. + * All rights reserved. + * Copyright (c) 2004-2005 The Trustees of the University of Tennessee. + * All rights reserved. + * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, + * University of Stuttgart. All rights reserved. + * Copyright (c) 2004-2005 The Regents of the University of California. + * All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ +/** + * @file + * + * This file will hopefully not last long in the tree, but it's + * unfortunately necessary for now. + * + * There are multiple places in the code base where we need to safely + * convert from a size_t to an int. However, on some platforms, + * sizeof(size_t) is larger than sizeof(int), so casting from size_t + * -> int will result in a compiler warning and potentially data + * truncation. + * + * But, unfortunately, we still need to do it. But we definitely do + * not want compiler warnings. So when sizeof(size_t)>sizeof(int), + * the solution is the treat the size_t value like an array and + * dereference the appropriate nibble and cast that to an int (which + * accounts for both big and little endian machines). + * + * Most places in the code where this casting must occur are because + * collision of APIs (e.g., one API requires a size_t and another API + * requires an int. And in most places, we're not going to overflow + * the int when casting down into it (e.g., it's the result of a + * strlen, or the length of the buffer in an ompi_buffer_t -- if that + * buffer is larger than MAX_INT, we've got other problems!). + * + * BUT -- the whole premise of casting down to an int is dangerous. + * So we provide extra protection here to detect overflow situations + * and print out appropriate warnings. So if this situation ever + * occurs, we'll still overflow, but we'll have a good indication that + * it's happening, and where. + */ + +#ifndef OPAL_CONVERT_H +#define OPAL_CONVERT_H + +#include "ompi_config.h" + +/** + * Convert a size_t to an int. + * + * @param in The size_t value to be converted + * @param out The output int value. + * @param want_check Whether to check for truncation or not + * + * @returns OMPI_SUCESS If all went well + * @returns OMPI_NOT_SUPPORTED if the size_t value was truncated + * + * The conversion will always occur. However, if the size_t value was + * truncated (i.e., sizeof(size_t) > sizeof(int), and the cast down to + * the int actually changed the value), OMPI_NOT_SUPPORTED will be + * returned. + * + * On platforms where sizeof(size_t) <= sizeof(int), this function + * will aways return OMPI_SUCCESS. + */ +int ompi_sizet2int(size_t in, int *out, bool want_check); + +#endif