CGI "c" functions for 4gl
Posted in 1999
Topics: High Availability & Replication, Connectivity: ESQL/C, 4GL & Embedded SQL
I downloaded the source of the CGI functions (before it was withdrawn) and we have used them successfully on SCO Open Server 5 for the past two years. Now I want to port the same application to SCO UnixWare 7 but I am having trouble compiling the cgi functions. This library compiles fine (with a few warnings that don't affect it at runtime) on Open Server 5.0.4 using the standard development system but when I move the source to my Unixware 7.0 system and compiled it with the included UDK I got the following warnings. Any program I try and run that includes these functions crashes with a memory violation. :-( I have tried to identify what to fix - but it's beyond my c knowledge. Any help would be appreciated! UX:ar: INFO: Creating lib4glcgi.a UX:acomp: WARNING: "cgisetenv.c", line 253: argument is incompatible with prototype: arg #4 UX:acomp: WARNING: "cgisetenv.c", line 337: argument is incompatible with prototype: arg #5 UX:acomp: WARNING: "cgisetenv.c", line 518: Function illegally defined in hosted mode: getenv Code fragments that include the above sections (and related declarations, etc.) follow: /* -- Include Files */ #include <stdio.h> #include <ctype.h> #include <string.h> /* ** Redefine getenv so that there is no conflict (e.g., in ANSI compilation ** mode) with the local definition of getenv (in cgiusr.h). */ #define getenv getenvStd #include <stdlib.h> #undef getenv #include <assert.h> #include "cgiusr.h" . . . /* function prototypes */ #ifdef RADICAL_SETENV static int env_compare(); static int env_cmp(); . . . /* Environment comparison -- for use by bsearch/qsort */ static int env_cmp(vp1, vp2) void *vp1; void *vp2; { return (env_compare(*(char **) vp1, *(char **) vp2)); } . . . /* Sort the environment (and check that the sort worked) */ static void env_sort(env, count) char **env; size_t count; { qsort(env, count, sizeof(char **), env_cmp); /* <<<-- line 253 */ ENV_CHECK(); } . . . /* Find pointer to environment variable in environment */ static char ** find_env(newval) char *newval; { char **env = (char **) 0; if (env_base == (char **) 0) env_alloc(); /* <<<- line 337 below - >>>> env = bsearch(&newval, environ, env_used, sizeof(char **), env_cmp); return (env); } . . . /* Simulate getenv(3) if setenv(3) has complete control over the environment */ char * getenv(env) char *env; { /* <<<-- line 518 */ char **envp; char *val; envp = find_env(env); if (envp == (char **) 0) val = (char *) 0; else val = *envp + strlen(env) + 1; return (val); } -- { Kelvin Burton Mercy Ships International Office } { Development Manager P.O. Box 2020, Garden Valley, Texas 75771 } { burtonk@MercyShips.ORG ph 903-882-0887 fax 903-963-5029 } { www.mercyships.org }
Kelvin Burton wrote: > I downloaded the source of the CGI functions (before it was withdrawn) > and we have used them successfully on SCO Open Server 5 for the past > two years. > > Now I want to port the same application to SCO UnixWare 7 but I am > having trouble compiling the cgi functions. > > This library compiles fine (with a few warnings that don't > affect it at runtime) on Open Server 5.0.4 using the standard > development system but when I move the source to my Unixware 7.0 > system and compiled it with the included UDK I got the following > warnings. Any program I try and run that includes these functions > crashes with a memory violation. :-( > > I have tried to identify what to fix - but it's beyond my c knowledge. > > Any help would be appreciated! > > UX:ar: INFO: Creating lib4glcgi.a > UX:acomp: WARNING: "cgisetenv.c", line 253: argument is incompatible > with prototype: arg #4 The problem is that the env_cmp() function should be taking const void * arguments, not void * arguments. Probably. > UX:acomp: WARNING: "cgisetenv.c", line 337: argument is incompatible > with prototype: arg #5 Same problem. > UX:acomp: WARNING: "cgisetenv.c", line 518: Function illegally defined > in hosted mode: getenv This is probably the cause of the problems. The code in the source file (which I wrote) is treading on thin ice. It usurps the standard defined function getenv(), and provides an implementation of the semi-standard function putenv(), and it adds the normally non-standard function setenv(). The problem with putenv() is that it is easy to abuse it. For example, you can't pass it a local variable. If you pass it malloc'd data, then you can never release it. If you reset the environment variable, you have a memory leak, probably. Using the setenv() function avoids those problems. At a cost. Two costs, in fact. (1) Usurping getenv() may or may not work. It does on many Unix systems; the fact that Unixware is warning about it means that it may not work on Unixware. (2) Linux has a setenv() with a very different interface. I'm surprised the code is in K&R format; I am almost sure I wrote it in ANSI C with prototypes -- I've not been writing K&R code for quite a while except under duress. The K&R-ization of the code would lose the const-ness and then moving it back to an ANSI environment would lead to problems with const-ness. OK; enough analysis. What to do about it? You have a variety of options. (1) You can ask me for the latest version of the setenv.c code - which got renamed to cgisetenv.c when it was incorporated in the CGI Webkits. This should fix the first two warnings - I'd double check before sending it to you. (2) You can find all occurrences of setenv() and/or putenv() in the CGI code, and modify them to work safely with the standard putenv() function. Basically, you'll need to duplicate any non-static, non-allocated strings passed to setenv() or putenv() and pass the malloc'd string to the standard putenv() function. (3) Consider compiling with CONSERVATIVE_SETENV defined. This uses the system supplied putenv() and getenv() functions rather than the home-brew implementations. It should be OK. If you need the updated setenv.c/setenv.h, contact me at my work email address. > Code fragments that include the above sections (and related > declarations, etc.) follow: > > /* -- Include Files */ > #include <stdio.h> > #include <ctype.h> > #include <string.h> > > /* > ** Redefine getenv so that there is no conflict (e.g., in ANSI > compilation > ** mode) with the local definition of getenv (in cgiusr.h). > */ > #define getenv getenvStd > #include <stdlib.h> > #undef getenv > > #include <assert.h> > > #include "cgiusr.h" > . > . > . > /* function prototypes */ > > #ifdef RADICAL_SETENV > static int env_compare(); > static int env_cmp(); > . > . > . > /* Environment comparison -- for use by bsearch/qsort */ > static int > env_cmp(vp1, vp2) > void *vp1; > void *vp2; > { > return (env_compare(*(char **) vp1, *(char **) vp2)); > } > . > . > . > /* Sort the environment (and check that the sort worked) */ > static void > env_sort(env, count) > char **env; > size_t count; > { > qsort(env, count, sizeof(char **), env_cmp); /* <<<-- line > > 253 */ > ENV_CHECK(); > } > . > . > . > /* Find pointer to environment variable in environment */ > static char ** > find_env(newval) > char *newval; > { > char **env = (char **) 0; > > if (env_base == (char **) 0) > env_alloc(); > /* <<<- line 337 below - >>>> > env = bsearch(&newval, environ, env_used, sizeof(char **), env_cmp); > > return (env); > } > . > . > . > /* Simulate getenv(3) if setenv(3) has complete control over the > environment */ > char * > getenv(env) > char *env; > { /* <<<-- line 518 */ > char **envp; > char *val; > > envp = find_env(env); > if (envp == (char **) 0) > val = (char *) 0; > else > val = *envp + strlen(env) + 1; > > return (val); > } > > -- > { Kelvin Burton Mercy Ships International Office } > { Development Manager P.O. Box 2020, Garden Valley, Texas 75771 } > { burtonk@MercyShips.ORG ph 903-882-0887 fax 903-963-5029 } > { www.mercyships.org } -- Jonathan Leffler (jleffler@informix.com, jleffler@earthlink.net) Guardian of DBD::Informix v0.60 -- see http://www.perl.com/CPAN #include <disclaimer.h>
Jonathan Leffler wrote: > (3) Consider > compiling with CONSERVATIVE_SETENV defined. > That worked! The application now runs fine on UnixWare 7! I'm a little uncertain whether I'm now exposed to the original memory leak you were trying to avoid. Should I still look at getting the updated source from you (I think I'd like to have it on hand if you don't mind sending it)? Regards, Kelvin > Kelvin Burton wrote: > > I downloaded the source of the CGI functions (before it was withdrawn) > > and we have used them successfully on SCO Open Server 5 for the past > > two years. > > > > Now I want to port the same application to SCO UnixWare 7 but I am > > having trouble compiling the cgi functions. > > > > This library compiles fine (with a few warnings that don't > > affect it at runtime) on Open Server 5.0.4 using the standard > > development system but when I move the source to my Unixware 7.0 > > system and compiled it with the included UDK I got the following > > warnings. Any program I try and run that includes these functions > > crashes with a memory violation. :-( > > > > I have tried to identify what to fix - but it's beyond my c knowledge. > > > > Any help would be appreciated! > > > > UX:ar: INFO: Creating lib4glcgi.a > > UX:acomp: WARNING: "cgisetenv.c", line 253: argument is incompatible > > with prototype: arg #4 > > The problem is that the env_cmp() function should be taking > const void * arguments, not void * arguments. Probably. > > > UX:acomp: WARNING: "cgisetenv.c", line 337: argument is incompatible > > with prototype: arg #5 > > Same problem. > > > UX:acomp: WARNING: "cgisetenv.c", line 518: Function illegally defined > > in hosted mode: getenv > > This is probably the cause of the problems. The code in the source > file (which I wrote) is treading on thin ice. It usurps the standard > defined function getenv(), and provides an implementation of the > semi-standard function putenv(), and it adds the normally non-standard > function setenv(). The problem with putenv() is that it is easy to > abuse it. For example, you can't pass it a local variable. If you > pass it malloc'd data, then you can never release it. If you reset > the environment variable, you have a memory leak, probably. Using > the setenv() function avoids those problems. At a cost. Two costs, > in fact. (1) Usurping getenv() may or may not work. It does on many > Unix systems; the fact that Unixware is warning about it means that it > may not work on Unixware. (2) Linux has a setenv() with a very > different interface. > > I'm surprised the code is in K&R format; I am almost sure I wrote it > in ANSI C with prototypes -- I've not been writing K&R code for quite > a while except under duress. The K&R-ization of the code would lose > the const-ness and then moving it back to an ANSI environment would > lead to problems with const-ness. > > OK; enough analysis. What to do about it? > > You have a variety of options. (1) You can ask me for the latest > version of the setenv.c code - which got renamed to cgisetenv.c when > it was incorporated in the CGI Webkits. This should fix the first > two warnings - I'd double check before sending it to you. (2) You > can find all occurrences of setenv() and/or putenv() in the CGI > code, and modify them to work safely with the standard putenv() > function. Basically, you'll need to duplicate any non-static, > non-allocated strings passed to setenv() or putenv() and pass the > malloc'd string to the standard putenv() function. (3) Consider > compiling with CONSERVATIVE_SETENV defined. This uses the system > supplied putenv() and getenv() functions rather than the home-brew > implementations. It should be OK. > > If you need the updated setenv.c/setenv.h, contact me at my work > email address. > > > Code fragments that include the above sections (and related > > declarations, etc.) follow: > > > > /* -- Include Files */ > > #include <stdio.h> > > #include <ctype.h> > > #include <string.h> > > > > /* > > ** Redefine getenv so that there is no conflict (e.g., in ANSI > > compilation > > ** mode) with the local definition of getenv (in cgiusr.h). > > */ > > #define getenv getenvStd > > #include <stdlib.h> > > #undef getenv > > > > #include <assert.h> > > > > #include "cgiusr.h" > > . > > . > > . > > /* function prototypes */ > > > > #ifdef RADICAL_SETENV > > static int env_compare(); > > static int env_cmp(); > > . > > . > > . > > /* Environment comparison -- for use by bsearch/qsort */ > > static int > > env_cmp(vp1, vp2) > > void *vp1; > > void *vp2; > > { > > return (env_compare(*(char **) vp1, *(char **) vp2)); > > } > > . > > . > > . > > /* Sort the environment (and check that the sort worked) */ > > static void > > env_sort(env, count) > > char **env; > > size_t count; > > { > > qsort(env, count, sizeof(char **), env_cmp); /* <<<-- line > > > > 253 */ > > ENV_CHECK(); > > } > > . > > . > > . > > /* Find pointer to environment variable in environment */ > > static char ** > > find_env(newval) > > char *newval; > > { > > char **env = (char **) 0; > > > > if (env_base == (char **) 0) > > env_alloc(); > > /* <<<- line 337 below - >>>> > > env = bsearch(&newval, environ, env_used, sizeof(char **), env_cmp); > > > > return (env); > > } > > . > > . > > . > > /* Simulate getenv(3) if setenv(3) has complete control over the > > environment */ > > char * > > getenv(env) > > char *env; > > { /* <<<-- line 518 */ > > char **envp; > > char *val; > > > > envp = find_env(env); > > if (envp == (char **) 0) > > val = (char *) 0; > > else > > val = *envp + strlen(env) + 1; > > > > return (val); > > } > > > > -- > > { Kelvin Burton Mercy Ships International Office } > > { Development Manager P.O. Box 2020, Garden Valley, Texas 75771 } > > { burtonk@MercyShips.ORG ph 903-882-0887 fax 903-963-5029 } > > { www.mercyships.org } > > -- > Jonathan Leffler (jleffler@informix.com, jleffler@earthlink.net) > Guardian of DBD::Informix v0.60 -- see http://www.perl.com/CPAN > #include <disclaimer.h> -- { Kelvin Burton Mercy Ships International Office } { Development Manager P.O. Box 2020, Garden Valley, Texas 75771 } { burtonk@MercyShips.ORG ph 903-882-0887 fax 903-963-5029 } { www.mercyships.org }