[freetds] win64

Frediano Ziglio freddy77 at gmail.com
Mon Jan 19 04:18:05 EST 2009


2009/1/17 James K. Lowden <jklowden at freetds.org>:
> Sometimes work guides The Work.  I built FreeTDS for 64-bit Windows this
> week with VS 2005.  I modified libtds to emit fewer warnings -- I left
> some that are pretty egregious -- and added a .sln and .vcproj files to
> the src directories.
>

good.. I would have put in win32 directory but it's ok.

> As far as I know, I'm the first one to do this.  There was barely any
> support for it.  For example, the winsock stuff was defined only for
> WIN32.  It's a big patch.
>

???
are you sure ?? Do you know WIN32 is defined even for win64 ??

> What follows are some notes on what I did in case it helps anyone else.
>
> Win64 is an LLP64 architecture, whereas Linux uses LP64.  The major
> difference is that a Win64 long integer is still 32 bits while a Linux
> long is 64 bits  (cf.
> http://www.ibm.com/developerworks/library/l-port64.html and
> http://www.unix.org/version2/whatsnew/lp64_wp.html).  size_t can hold the
> maximum difference between two pointers.  In Linux, size_t is the same as
> an unsigned long.  In Win64 there's no standard type equivalent to size_t.
>

intptr_t perhaps or something like that. There is also TDS_INTPTR !

>
> There's an inherent tension in the C standard library between integers and
> sizes.  For example, strlen(3) returns size_t and sprintf(3) returns int.
> To be meaninful, the values being compared have to fit within both
> datatype's domains (which typically they do, but the compiler can't know
> that and the handling of the atypical case will likely hurt). .
>
> To squelch the warnings, we add a cast.  To be safe, that cast really
> should be inside a conversion function that uses assert(3) to verify the
> size_t values fits in 31 bits.  I didn't do that, but it would be IMO a
> worthwhile exercise.
>
> Simlilarly, libtds plays fast and loose with int and unsigned int.  Most
> of the time it's really OK: how often will a column name length need more
> than 2^31 bits?  I find myself wondering if we shouldn't have a function
> strleni() that returns an int after checking the size.  .
>
> Another way to handle this would be to make widespread use of a union,
>
>        typedef union tds_length {
>                unsigned long  ulong;
>                size_t  size;
>                int     len;
>        } TDS_LENGTH;
>
> and use checking functions (or macros)
>
>        size_t
>        as_size( TDS_LENGTH L )
>        {
>                assert(L.len > 0);
>                return L.size;
>        }
>
>        int
>        as_int( TDS_LENGTH L )
>        {
>                assert(L.size <= INT_MAX);
>                return L.len;
>        }
>
>        unsigned long
>        as_ulong( TDS_LENGTH L )
>        {
>                assert(L.len > 0);
>                return L.ulong;
>        }
>
> to write such code as
>
>        TDS_LENGTH a;
>        a.len = sprintf(...);
>        if( as_size(a) != strlen(...) )
>                return FAIL;
>

it can't work !!! Think about endianess !!!

> That would constrain TDS_LENGTH to use values <= 2^31 is most cases.  The
> functions *assume* you're using the structure for type-punning.  Short of
> C++'s operator overloading, there's no easy way to check.
>
> There are many places in libtds particularly where int is used where
> size_t would have been more in keeping with the standard library.  (I'm as
> guilty as anyone else; old habits are hard to break.)  Often, the type is
> chosen to match a corresponding part of the TDS data strea, e.g.
> TDSRESULTINFO::row_size is TDS_INT because that's how column widths are
> defined in the TDS_ROWFMT2 packet.  (But it's not used that way in
> practice.  tds_alloc_row() defines its local row_size as TDS_UINT,
> accumulates the sizes of the columns, and assigns the sum to
> TDSRESULTINFO::row_size.  It would have been better to use size_t after
> all.)
>

Ok, size_t is correct, however see how packet is readed from network
and how row is allocated. Column number is a 16 bit so there can be at
maximun 2^16 = 65536 columns so each column can contains up to 2^31 /
2^16 = 2^15. Considering that BLOBs occupy just few bytes and variable
columns occupy at maximun 8000 bytes... there is no limit... 31 bits
are sufficient for every rowset.

> I think it would be better to use standard C types within the library and
> as much as possible reserve casts to deal with TDS packets or API calls.
> I wonder what others have done.  It's not an easy question to research.
>

Personally I think this patch it too big and contains a lot of changes
grouped in a single one:
- new defines for sybdb.h just to make some windows programs happy...
nothing related to win64
- use of newer _fseeki64 which break compatibility with old VS and even mingw
- changed inclusion styles. Are you sure that client programs works as
expected ??
- a lot of warning removed just adding casts
- added a log and a strange string copy in tds_put_login_string (with
a possible buffer overflow... I'll check it)
- winsocket initialization (why in mem.c and not in net.c ??)
- other minor styles changes

freddy77



More information about the FreeTDS mailing list