[GRASS-dev] Re: ctypes problem with Vect_open_old

Glynn Clements glynn at gclements.plus.com
Thu Jul 28 16:40:53 EDT 2011


Martin Landa wrote:

> Hi,
> 
> 2011/7/23 Glynn Clements <glynn at gclements.plus.com>:
> 
> [...]
> 
> >> *** glibc detected *** /usr/bin/python: malloc(): memory corruption:
> >> 0x09ba9fe8 ***
> >
> > Does calling G_gisinit() first change anything?
> 
> unfortunately it didn't help, still corrupted memory, now

I think I've found it. Here, vector.py has:

	# /usr/include/bits/types.h: 62
	class struct_anon_1(Structure):
	    pass
	
	struct_anon_1.__slots__ = [
	    '__val',
	]
	struct_anon_1._fields_ = [
	    ('__val', c_long * 2),
	]

	__quad_t = struct_anon_1 # /usr/include/bits/types.h: 62
	...
	__off64_t = __quad_t # /usr/include/bits/types.h: 142
	...
	off_t = __off64_t # /usr/include/stdio.h: 93

Vect_write_line() returns an off_t. With the above definitions, this
is a structure containing a pair of 32-bit integers.

On Linux-x86, structure return values are implemented by having the
caller pass a pointer to where to store the return value as the first
(zeroth?) argument.

If I add:

	Vect_write_line.restype = c_longlong

then the script works.

The <bits/types.h> header file defines __quad_t as:

	/* quad_t is also 64 bits.  */
	#if __WORDSIZE == 64
	typedef long int __quad_t;
	typedef unsigned long int __u_quad_t;
	#elif defined __GLIBC_HAVE_LONG_LONG
	__extension__ typedef long long int __quad_t;
	__extension__ typedef unsigned long long int __u_quad_t;
	#else
	typedef struct
	{
	  long __val[2];
	} __quad_t;
	typedef struct
	{
	  __u_long __val[2];
	} __u_quad_t;
	#endif

I.e. as "long int" if that type is 64-bit, else "long long int" if
__GLIBC_HAVE_LONG_LONG is defined, else the structure.

__GLIBC_HAVE_LONG_LONG is defined in <features.h> as:

	/* Decide whether a compiler supports the long long datatypes.  */
	#if defined __GNUC__ \
	    || (defined __PGI && defined __i386__ ) \
	    || (defined __INTEL_COMPILER && (defined __i386__ || defined __ia64__)) \
	    || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
	# define __GLIBC_HAVE_LONG_LONG	1
	#endif

And ctypesgen.py specifically undefines __GNUC__ when running the
preprocessor. (__STDC_VERSION__ is only defined if you use e.g. 
-std=c99 or -std=gnu99, not for C89)

This causes ctypes to pass an incorrect argument list for any function
which returns a 64-bit off_t, and Vect_write_line() is just such a
function.

The simplest fix is probably to add -D__GLIBC_HAVE_LONG_LONG to
CTYPESFLAGS in lib/python/ctypes/Makefile. That macro is unlikely to
be understood by anything other than glibc, and any system using glibc
is almost certain to be using a compiler which supports "long long".

However, I wouldn't be surprised if there are other situations where
undefining __GNUC__ has consequences for the ABI, but we'll just have
to deal with those as we find them.

-- 
Glynn Clements <glynn at gclements.plus.com>


More information about the grass-dev mailing list