[Proj] PROJ.4 thread-safety issues detailed

Patrick Mézard pmezard at gmail.com
Mon Feb 28 13:20:43 EST 2005


Hello, 
I have looked for static variables in PROJ.4 code and found the
following potential problems :

1-rtodms.c: 
RES, RES60, CONV, format, do_long are non-const globals.

2- pj_strerrno.c:
note is static in pj_strerrno.

3- pj_open_lib.c : 
pj_finder, path_count, search_path are non-const globals.

4- pj_init.c
start is a non-const global.

5- Many globals in grid stuff. Not listed
6- Some globals in geodesic stuff. Not listed.
7- Many globals in projection approximation code. Not listed.

My point of view : 
- Evidently, everything (related to globals) can be solved by using
thread-local storage.
- I do not use 1, 5, 6, 7 and I will not try to edit them. 1 can be
changed easily by adding a format description structure to function
calls.
- 2 is like the problem with pj_errno, and I will solve it with
thread-local storage. It is hard to code something else without using
callbacks or allocating memory which would make the whole think much
more complicated to use.
- 3 is used in pj_init. I do not use this feature, and I will just
disable the +init and default parameters options.
- 4 is critical but easily corrected by changing start into a local
variable and passing it to every other function. See the attached
patch.

Hope this helps.

Patrick Mézard
-------------- next part --------------
*** proj.4-prev\src\pj_init.c	Wed Sep 08 11:23:38 2004
--- proj.4\src\pj_init.c	Mon Feb 28 19:14:48 2005
***************
*** 68,81 ****
  
  PJ_CVSID("$Id: pj_init.c,v 1.16 2004/09/08 15:23:37 warmerda Exp $");
  
- static paralist *start;
  extern FILE *pj_open_lib(char *, char *);
  
  /************************************************************************/
  /*                              get_opt()                               */
  /************************************************************************/
  static paralist *
! get_opt(FILE *fid, char *name, paralist *next) {
      char sword[302], *word = sword+1;
      int first = 1, len, c;
  
--- 68,80 ----
  
  PJ_CVSID("$Id: pj_init.c,v 1.16 2004/09/08 15:23:37 warmerda Exp $");
  
  extern FILE *pj_open_lib(char *, char *);
  
  /************************************************************************/
  /*                              get_opt()                               */
  /************************************************************************/
  static paralist *
! get_opt(FILE *fid, char *name, paralist *start, paralist *next) {
      char sword[302], *word = sword+1;
      int first = 1, len, c;
  
***************
*** 117,129 ****
  /*                            get_defaults()                            */
  /************************************************************************/
  static paralist *
! get_defaults(paralist *next, char *name) {
  	FILE *fid;
  
  	if (fid = pj_open_lib("proj_def.dat", "rt")) {
! 		next = get_opt(fid, "general", next);
  		rewind(fid);
! 		next = get_opt(fid, name, next);
  		(void)fclose(fid);
  	}
  	if (errno)
--- 116,128 ----
  /*                            get_defaults()                            */
  /************************************************************************/
  static paralist *
! get_defaults(paralist *start, paralist *next, char *name) {
  	FILE *fid;
  
  	if (fid = pj_open_lib("proj_def.dat", "rt")) {
! 		next = get_opt(fid, "general", start, next);
  		rewind(fid);
! 		next = get_opt(fid, name, start, next);
  		(void)fclose(fid);
  	}
  	if (errno)
***************
*** 135,141 ****
  /*                              get_init()                              */
  /************************************************************************/
  static paralist *
! get_init(paralist *next, char *name) {
  	char fname[MAX_PATH_FILENAME+ID_TAG_MAX+3], *opt;
  	FILE *fid;
  
--- 134,140 ----
  /*                              get_init()                              */
  /************************************************************************/
  static paralist *
! get_init(paralist *start, paralist *next, char *name) {
  	char fname[MAX_PATH_FILENAME+ID_TAG_MAX+3], *opt;
  	FILE *fid;
  
***************
*** 144,150 ****
  		*opt++ = '\0';
  	else { pj_errno = -3; return(0); }
  	if (fid = pj_open_lib(fname, "rt"))
! 		next = get_opt(fid, opt, next);
  	else
  		return(0);
  	(void)fclose(fid);
--- 143,149 ----
  		*opt++ = '\0';
  	else { pj_errno = -3; return(0); }
  	if (fid = pj_open_lib(fname, "rt"))
! 		next = get_opt(fid, opt, start, next);
  	else
  		return(0);
  	(void)fclose(fid);
***************
*** 226,237 ****
  pj_init(int argc, char **argv) {
  	char *s, *name;
  	PJ *(*proj)(PJ *);
! 	paralist *curr;
  	int i;
  	PJ *PIN = 0;
  
  	errno = pj_errno = 0;
-         start = NULL;
  
  	/* put arguments into internal linked list */
  	if (argc <= 0) { pj_errno = -1; goto bum_call; }
--- 225,236 ----
  pj_init(int argc, char **argv) {
  	char *s, *name;
  	PJ *(*proj)(PJ *);
! 	paralist *curr = 0;
  	int i;
  	PJ *PIN = 0;
+ 	paralist* start = NULL;
  
  	errno = pj_errno = 0;
  
  	/* put arguments into internal linked list */
  	if (argc <= 0) { pj_errno = -1; goto bum_call; }
***************
*** 246,252 ****
  	if (pj_param(start, "tinit").i) {
  		paralist *last = curr;
  
! 		if (!(curr = get_init(curr, pj_param(start, "sinit").s)))
  			goto bum_call;
  		if (curr == last) { pj_errno = -2; goto bum_call; }
  	}
--- 245,251 ----
  	if (pj_param(start, "tinit").i) {
  		paralist *last = curr;
  
! 		if (!(curr = get_init(start, curr, pj_param(start, "sinit").s)))
  			goto bum_call;
  		if (curr == last) { pj_errno = -2; goto bum_call; }
  	}
***************
*** 259,265 ****
  
  	/* set defaults, unless inhibited */
  	if (!pj_param(start, "bno_defs").i)
! 		curr = get_defaults(curr, name);
  	proj = (PJ *(*)(PJ *)) pj_list[i].proj;
  
  	/* allocate projection structure */
--- 258,264 ----
  
  	/* set defaults, unless inhibited */
  	if (!pj_param(start, "bno_defs").i)
! 		curr = get_defaults(start, curr, name);
  	proj = (PJ *(*)(PJ *)) pj_list[i].proj;
  
  	/* allocate projection structure */


More information about the Proj mailing list