Q: FICS code and 64-bit (va_list)

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

User avatar
hgm
Posts: 27787
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Q: FICS code and 64-bit (va_list)

Post by hgm »

I only have 32-bit machines.

Recently I was contacted by someoe who met with grave difficulties when he tried to install my version of the FICS code on his machine (a VPS, actually), running 64-bit CentOS 5.8. The symptoms are basically that after starting the FICS binary, a few error messages are printed to complain that certain files could not be created, after which it exits. In the current directory there are then a number of files with unintelligible names consisting of garbage characters.

I could trace the problem to the use of routines with a variable number of parameters, which are then converted to a va_list, which is passed to vsnprintf, to print the filename into an (allocated) string, which is then used in fopen(). There is a call

vsnprintf(buf, len, "%s", va)

where va is the va_list supposed to contain the filename, and after that buf is filled with garbage.

So it looks like the C-library routine vsnprintf doesn't work, or that somehow the creation of the va_list from the variable arguments of an earlier function call through the standard macro va_start completely messed up, and passes garbage.

I don't know if this is a compiler error, and why I do't have the same problem when I compile on my own Ubuntu 10.04 on a 32-bit machine. Perhaps the FICS code is simply not compatible with a 64-bit compile.

Would it be possible to force a 32-bit compile on a 64-bit system, and run the resulting binary on CentOS? If so, how can that be done?
User avatar
Evert
Posts: 2929
Joined: Sat Jan 22, 2011 12:42 am
Location: NL

Re: Q: FICS code and 64-bit (va_list)

Post by Evert »

You can make a 32 bit executable on a 64 bit system by passing -m32.

Would be better to fix the problem instead of trying to work around it though. My first guess would be that somehow the header file for the function declaration is not included, so the compiler makes an implicit assumption that a point is an int, which is fine if both are 32 bit (on a 32 bit system) but not on many 64 bit systems (where one is 32 bit and one is 64 bit).
Checking whether things compile with -Wall -Werror might help narrow down the problem.
User avatar
hgm
Posts: 27787
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Q: FICS code and 64-bit (va_list)

Post by hgm »

Problem is that I normally get thousands of compiler warnings, when doing "make". :cry: I will try to see if the -m32 helps, though.

This CentOS is a bit fishy anyway: make install did crash on it not being case sensitive in file names, so that the command "cp [a-z]* ..." also tried to copy the directory CVS, which produced a fatal error.
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Q: FICS code and 64-bit (va_list)

Post by bob »

hgm wrote:Problem is that I normally get thousands of compiler warnings, when doing "make". :cry: I will try to see if the -m32 helps, though.

This CentOS is a bit fishy anyway: make install did crash on it not being case sensitive in file names, so that the command "cp [a-z]* ..." also tried to copy the directory CVS, which produced a fatal error.
Something is broken. Unix has always been case-sensitive. the regular expression "[a-z]*" should NEVER match a file name that does not start with a lowercase alphabetic character, and doesn't on my fedora systems. We did run centos on our lab machines that use unix and I never noticed that being broken, so something is definitely wrong.
Pablo Vazquez
Posts: 154
Joined: Thu May 31, 2007 9:05 pm
Location: Madrid, Spain

Re: Q: FICS code and 64-bit (va_list)

Post by Pablo Vazquez »

http://pubs.opengroup.org/onlinepubs/00 ... rintf.html

"As these functions invoke the va_arg macro, the value of ap after the return is unspecified."

Maybe you are calling two or more of these functions without calling va_start again.
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Q: FICS code and 64-bit (va_list)

Post by bob »

I wonder if there is some environment variable one might be able to set to change this default behavior? That could certainly explain part of your difficulty... I've never wanted to disable case sensitivity so have never looked for such a capability.
User avatar
hgm
Posts: 27787
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Q: FICS code and 64-bit (va_list)

Post by hgm »

Hmm, this could be the case. I lifted the relevant routines out of the code, to show them below. Indeed vsnprintf is called twice, once to find the required size of the buffer it writes in, the second time to do the actual writing. If the first call would destroy ap, the second call would produce garbage.

It is not so obvious how this can be fixed, because the va_start call takes place in the caller, and I have no idea from how many other places m_vasprintf is called. It does not get the info passed that has to be passed to va_start, and it is not even clear it could be passed (because va_start probably takes the address of what you pass to it).

Code: Select all

253 /* a vasprintf wrapper */
254 int m_vasprintf(char **strp, const char *fmt, va_list ap)
255 {
256         int n;
257 
258         (*strp) = NULL;
259 
260         n = vsnprintf(NULL, 0, fmt, ap);
261         if (n == 0) return 0;
262 
263         (*strp) = m_malloc(n+1);
264         n = vsnprintf(*strp, n+1, fmt, ap);
265         
266         return n;
267 }

#define vasprintf m_vasprintf

1061 /*
1062   like fopen() but uses printf style arguments for the file name
1063 */
1064 FILE *fopen_p(const char *fmt, const char *mode, ...)
1065 {
1066         char *s = NULL;
1067         FILE *f;
1068         va_list ap;
1069         va_start(ap, mode);
1070         vasprintf(&s, fmt, ap);
1071         va_end(ap);
1072         if (!s) return NULL;
1073         if (strstr(s, "..")) {
1074                 d_printf("Invalid filename [%s]\n", s);
1075                 free(s);
1076                 return NULL;
1077         }
1078         f = fopen(s, mode);
1079         free(s);
1080         return f;
1081 }
1082 
1083 /*
1084   like fopen() but doesn't allow opening of filenames containing '..'
1085 */
1086 FILE *fopen_s(const char *fname, const char *mode)
1087 {
1088         return fopen_p("%s", mode, fname);
1089 }

#define ADHELP_DIR "./data/admin"

990         afp = fopen_s(ADHELP_DIR "/commands", "w");
991         if (!afp) {
992                 d_printf( "CHESSD: Could not write admin commands help file.\n");
993                 fclose(fp);
994                 return;
995         }
Daniel White
Posts: 33
Joined: Wed Mar 07, 2012 4:15 pm
Location: England

Re: Q: FICS code and 64-bit (va_list)

Post by Daniel White »

hgm wrote:Hmm, this could be the case. I lifted the relevant routines out of the code, to show them below. Indeed vsnprintf is called twice, once to find the required size of the buffer it writes in, the second time to do the actual writing. If the first call would destroy ap, the second call would produce garbage.

It is not so obvious how this can be fixed, because the va_start call takes place in the caller, and I have no idea from how many other places m_vasprintf is called. It does not get the info passed that has to be passed to va_start, and it is not even clear it could be passed (because va_start probably takes the address of what you pass to it).

Code: Select all

253 /* a vasprintf wrapper */
254 int m_vasprintf(char **strp, const char *fmt, va_list ap)
255 {
256         int n;
257 
258         (*strp) = NULL;
259 
260         n = vsnprintf(NULL, 0, fmt, ap);
261         if (n == 0) return 0;
262 
263         (*strp) = m_malloc(n+1);
264         n = vsnprintf(*strp, n+1, fmt, ap);
265         
266         return n;
267 }

#define vasprintf m_vasprintf

1061 /*
1062   like fopen() but uses printf style arguments for the file name
1063 */
1064 FILE *fopen_p(const char *fmt, const char *mode, ...)
1065 {
1066         char *s = NULL;
1067         FILE *f;
1068         va_list ap;
1069         va_start(ap, mode);
1070         vasprintf(&s, fmt, ap);
1071         va_end(ap);
1072         if (!s) return NULL;
1073         if (strstr(s, "..")) {
1074                 d_printf("Invalid filename [%s]\n", s);
1075                 free(s);
1076                 return NULL;
1077         }
1078         f = fopen(s, mode);
1079         free(s);
1080         return f;
1081 }
1082 
1083 /*
1084   like fopen() but doesn't allow opening of filenames containing '..'
1085 */
1086 FILE *fopen_s(const char *fname, const char *mode)
1087 {
1088         return fopen_p("%s", mode, fname);
1089 }

#define ADHELP_DIR "./data/admin"

990         afp = fopen_s(ADHELP_DIR "/commands", "w");
991         if (!afp) {
992                 d_printf( "CHESSD: Could not write admin commands help file.\n");
993                 fclose(fp);
994                 return;
995         }
Checking the man page it seems this is your problem:
If ap is passed to a function that uses va_arg(ap,type) then the value of ap is undefined after the return of that function.
However perhaps you can use the following (defined in C99):

Code: Select all

void va_copy(va_list dest, va_list src);
Note: This does require a matching va_end(dest) as well as va_end(src).
Last edited by Daniel White on Mon Aug 27, 2012 6:45 pm, edited 1 time in total.
User avatar
jshriver
Posts: 1342
Joined: Wed Mar 08, 2006 9:41 pm
Location: Morgantown, WV, USA

Re: Q: FICS code and 64-bit (va_list)

Post by jshriver »

Try compiling with gcc-4.4 I had a lot of troubles myself getting it to work with gcc-4.6 after many tries and some code alteration.

Worse case I have a tarball of a 32-bit build (fresh) I could try and send you if you want. I moved that over to my current 64-bit system and haven't had many problems.

-Josh
User avatar
hgm
Posts: 27787
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Q: FICS code and 64-bit (va_list)

Post by hgm »

Pablo Vazquez wrote:"As these functions invoke the va_arg macro, the value of ap after the return is unspecified."

Maybe you are calling two or more of these functions without calling va_start again.
This was exacly the problem. Thanks for pointing me in the right direction!

I removed the first call to vsnprintf, and just set the size n+1 to 8000. Now the ICS starts without errors, and I could logon to it.

Could of course be that similar problems exist elsewhere in the code; I will meticulously go through it for uses of va_lists to make sure they are only used once.