Build failed in Jenkins: cyrus-imapd-master #717

Greg Banks gnb at fastmail.fm
Wed Jul 18 22:02:34 EDT 2012



On Wed, Jul 18, 2012, at 11:42 PM, Bron Gondwana wrote:
> On Wed, Jul 18, 2012, at 05:03 PM, Jenkins wrote:
> > Running unit tests
> > ./cunit-to-junit.pl: ran 278 tests, 2 failed
> > make[3]: *** [check-local] Error 1
> > make[3]: Leaving directory `<http://ci.cyrusimap.org/job/cyrus-imapd-master/ws/imapd'>
> > make[2]: *** [check-am] Error 2
> > make[2]: Leaving directory `<http://ci.cyrusimap.org/job/cyrus-imapd-master/ws/imapd'>
> > make[1]: *** [check-recursive] Error 1
> > make[1]: Leaving directory `<http://ci.cyrusimap.org/job/cyrus-imapd-master/ws/imapd'>
> > make: *** [check] Error 2
> > + fatal 'Can'\''t make check'
> > + echo 'imapd/tools/jenkins-build.sh: Can'\''t make check'
> > imapd/tools/jenkins-build.sh: Can't make check
> 
> Of course it bloody runs clean on my machine.  Short of logging in and...
> 
> ./cunit/byteorder64.testc:12: CU_ASSERT_EQUAL(ntohll(*((uint64_t
> *)(b64)))=72057594037927936,1=1)
> 
> Oh shit.
> 
> So what's different from my machine?  The architecture certainly isn't. 
> This means that cmu/master is super-dangerous right now for anyone not
> building on the same platform as me.
> 
> Greg - any ideas??  It should be using be64toh from endian.h on Linux
> according to the code.

Hmm.

static void test_byteorder(void)
{
    const char b64[8] = { 0, 0, 0, 0, 0, 0, 0, 1 };
    const char b32[4] = { 0, 0, 0, 1 };

    char i64[8];
    char i32[4];

Here's your first problem, the alignment of all these variables is
uncontrolled.  The code is only working by accident because the C
runtime environment gives you an aligned stack, and also because x86
doesn't care so much about alignment.

    /* test 64 bit */
    CU_ASSERT_EQUAL(ntohll(*((uint64_t *)(b64))), 1);
    *((uint64_t *)i64) = htonll(1);
    CU_ASSERT_EQUAL(memcmp((char *)i64, b64, 8), 0);

    /* test 32 bit */
    CU_ASSERT_EQUAL(ntohl(*((uint32_t *)(b32))), 1);
    *((uint32_t *)i32) = htonl(1);
    CU_ASSERT_EQUAL(memcmp((char *)i32, b32, 4), 0);
}

In the header file lib/byteorder64.h

/* http://stackoverflow.com/a/4410728/94253 */

#if defined(__linux__)
#  include <endian.h>
#elif defined(__FreeBSD__) || defined(__NetBSD__)
#  include <sys/endian.h>
#elif defined(__OpenBSD__)
#  include <sys/types.h>
#  define be16toh(x) betoh16(x)
#  define be32toh(x) betoh32(x)
#  define be64toh(x) betoh64(x)
#elif defined(WORDS_BIGENDIAN)
#define CYRUS_BYTESWAP
#endif

That could do with some improvement.

Solaris also has an optimised ntohll() in libc which uses the 64b bswap
instruction, although it's not inlined.

http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/lib/libc/amd64/gen/byteorder.s

and gcc has a builtin which uses the instruction on platforms which have
it

http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-g_t_005f_005fbuiltin_005fbswap64-3333

which presumably will work on some platforms where Linux's <endian.h>
(which re-implements the same thing differently) is not available.

Disassembling cunit/byteorder64.o, I don't see any bswap instructions in
there, but nm shows undefined symbols for libc's htonl and ntohl. 
Writing a function that calls ntohll() and nothing else, it seems that
ntohll() expands to a no-op.  Running gcc -E confirms this.

Aha..

#ifdef be64toh
#define htonll(x) htobe64(x)
#define ntohll(x) be64toh(x)
#elif defined (CYRUS_BYTESWAP)
/* little-endian 64-bit host/network byte-order swap functions */
extern unsigned long long _htonll(unsigned long long);
extern unsigned long long _ntohll(unsigned long long);
#define htonll(x) _htonll(x)
#define ntohll(x) _ntohll(x)
#else
#define htonll(x) (x)
#define ntohll(x) (x)
#endif

The <endian.h> on my desktop defines a be64toh().  The same header on
ci.cyrusimap.org doesn't.

-- 
Greg.


More information about the Cyrus-devel mailing list