[comp.windows.x] Very clear evidence of a memory leak in R4 server

rlk@THINK.COM (Robert L Krawitz) (03/22/90)

VERSION:
    R4

CLIENT MACHINE and OPERATING SYSTEM:
    Sun 4/60 running SunOs 4.0.3 (irrelevant)

DISPLAY TYPE:
    BW (probably irrelevant)

WINDOW MANAGER:
    twm (but not important)

AREA:
    Xsun

SYNOPSIS:
    Setting the root window pixmap causes a memory leak.

[2(rlk)||{!38}<underprize.think.com>/tmp_mnt/am/src.new/X11/R4/X11R4/fixes]
% ps ux
USER       PID %CPU %MEM   SZ  RSS TT STAT START  TIME COMMAND
...
rlk        472  0.0  5.964612  896 co S    09:39  31:51 /usr/bin/X11/Xsun :0 -a
...

I was doing nothing else out of the ordinary.

DESCRIPTION:

I have a program that attempts to display a "rotor" on the root window:
a sequence of bitmaps that when displayed in sequence appear to move in
a rotational pattern on the screen.  I use six bitmaps, each 32x32
pixels.  I left the program running for about 2 hours, at 20
updates/second (thus doing between 70,000 and 100,000 updates).

The inner loop, cribbed (and slightly modified from) xsetroot, looks
like this:

/*
 * SetBackgroundToBitmap: Set the root window background to a caller supplied 
 *                        bitmap.
 */
SetBackgroundToBitmap(bitmap, width, height)
    Pixmap bitmap;
    unsigned int width, height;
{
    Pixmap pix;
    GC gc;
    XGCValues gc_init;

    gc_init.foreground = NameToPixel(fore_color, BlackPixel(dpy, screen));
    gc_init.background = NameToPixel(back_color, WhitePixel(dpy, screen));
    if (reverse) {
	unsigned long temp=gc_init.foreground;
	gc_init.foreground=gc_init.background;
	gc_init.background=temp;
    }
    gc = XCreateGC(dpy, root, GCForeground|GCBackground, &gc_init);
    XSetWindowBackgroundPixmap(dpy, root, bitmap);
    XFreeGC(dpy, gc);
    XClearWindow(dpy, root);
    XFlush(dpy);
    unsave_past = 1;
}

(Never mind that the code looks highly sub-optimal on first glance; I
just hacked at the code until it worked, because I haven't programmed X
in maybe 3 years in the X10 days; I also put no effort into the user
interface).


REPEAT BY:
    Run program below.

SAMPLE FIX:

None.

****************************************************************

/* Copyright 1987, Massachusetts Institute of Technology */

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <stdio.h>
#include "X11/bitmaps/gray"

/*
 * xsetroot.c 	MIT Project Athena, X Window system root window 
 *		parameter setting utility.  This program will set 
 *		various parameters of the X root window.
 *
 *  Author:	Mark Lillibridge, MIT Project Athena
 *		11-Jun-87
 */

char *index();

#define Dynamic 1

char *program_name;
Display *dpy;
int screen;
Window root;
char *fore_color = NULL;
char *back_color = NULL;
int reverse = 0;
int save_colors = 0;
int unsave_past = 0;
Pixmap save_pixmap = (Pixmap)None;

Pixmap ReadBitmapFile();
unsigned long NameToPixel();

main(argc, argv) 
    int argc;
    char **argv;
{
  int excl = 0;
  int nonexcl = 0;
  int restore_defaults = 0;
  char *display_name = NULL;
  char *name = NULL;
  char *cursor_file = NULL;
  char *cursor_mask = NULL;
  char *cursor_name = NULL;
  char *solid_color = NULL;
  Cursor cursor;
  int gray = 0;
  char *bitmap_file = NULL;
  int mod_x = 0;
  int mod_y = 0;
  register int i;
  unsigned int time = 100000;
  unsigned int *ww, *hh;
  Pixmap *bitmap;

  program_name=argv[0];
  argv++;
  argc--; 
  for (i=0; i<argc; i++)
    {
      if (!strcmp ("-display", argv[i]) || !strcmp ("-d", argv[i]))
	{
	  if (++i>=argc) exit(1);
	  display_name = argv[i];
	}
      else if (!strcmp ("-time", argv[i]) || !strcmp("-t", argv[i]))
	{
	  if (++i>=argc) exit(1);
	  time = (unsigned) atoi(argv[i]);
	}
      else
	{
	  argc -= i;
	  argv += i;
	  break;
	}
    }

  bitmap = (Pixmap *) calloc(argc, sizeof(Pixmap));
  hh = (unsigned *) calloc(argc, sizeof(unsigned));
  ww = (unsigned *) calloc(argc, sizeof(unsigned));
    
  dpy = XOpenDisplay(display_name);
  if (!dpy) {
    fprintf(stderr, "%s:  unable to open display '%s'\n",
	    program_name, XDisplayName (display_name));
  }
  screen = DefaultScreen(dpy);
  root = RootWindow(dpy, screen);

  fprintf (stderr, "Time delay = %d\n", time);
  for(i=0; i<argc; i++)
    {
      fprintf (stderr, "Reading %s...", argv[i]);
      bitmap[i] = ReadBitmapFile (argv[i], &ww[i], &hh[i], (int *)NULL, (int *)NULL);
      fprintf (stderr, "Height=%d, Width=%d\n", hh[i], ww[i]);
    }

  while(1)
    for(i=0; i<argc; i++)
      {
	int w, h;
	w=ww[i];
	h=hh[i];
	usleep(time);
	SetBackgroundToBitmap(bitmap[i], w, h);
      }
}
			      
Pixmap ReadBitmapFile(filename, width, height, x_hot, y_hot)
    char *filename;
    unsigned int *width, *height;
    int *x_hot, *y_hot;
{
    Pixmap bitmap;
    int status;

    status = XReadBitmapFile(dpy, root, filename, width,
			     height, &bitmap, x_hot, y_hot);
    if (status == BitmapSuccess)
      return(bitmap);
    else if (status == BitmapOpenFailed)
	fprintf(stderr, "%s: can't open file: %s\n", program_name, filename);
    else if (status == BitmapFileInvalid)
	fprintf(stderr, "%s: bad bitmap format file: %s\n",
			program_name, filename);
    else
	fprintf(stderr, "%s: insufficient memory for bitmap: %s",
			program_name, filename);
    exit(1);
    /*NOTREACHED*/
}

/*
 * SetBackgroundToBitmap: Set the root window background to a caller supplied 
 *                        bitmap.
 */
SetBackgroundToBitmap(bitmap, width, height)
    Pixmap bitmap;
    unsigned int width, height;
{
    Pixmap pix;
    GC gc;
    XGCValues gc_init;

    gc_init.foreground = NameToPixel(fore_color, BlackPixel(dpy, screen));
    gc_init.background = NameToPixel(back_color, WhitePixel(dpy, screen));
    if (reverse) {
	unsigned long temp=gc_init.foreground;
	gc_init.foreground=gc_init.background;
	gc_init.background=temp;
    }
    gc = XCreateGC(dpy, root, GCForeground|GCBackground, &gc_init);
    /*
    pix = XCreatePixmap(dpy, root, width, height,
			(unsigned int)DefaultDepth(dpy, screen));
    XCopyPlane(dpy, bitmap, pix, gc, 0, 0, width, height, 0, 0, (unsigned long)1);
    */
    XSetWindowBackgroundPixmap(dpy, root, bitmap);
    XFreeGC(dpy, gc);
    /*
    XFreePixmap(dpy, bitmap);
    if (save_colors)
	save_pixmap = pix;
    else
	XFreePixmap(dpy, pix);
	*/
    XClearWindow(dpy, root);
    XFlush(dpy);
    unsave_past = 1;
}

unsigned long NameToPixel(name, pixel)
    char *name;
    unsigned long pixel;
{
    XColor ecolor;

    if (!name || !*name)
	return pixel;
    if (!XParseColor(dpy,DefaultColormap(dpy,screen),name,&ecolor)) {
	fprintf(stderr,"%s:  unknown color \"%s\"\n",program_name,name);
	exit(1);
	/*NOTREACHED*/
    }
    if (!XAllocColor(dpy, DefaultColormap(dpy, screen),&ecolor)) {
	fprintf(stderr, "%s:  unable to allocate color for \"%s\"\n",
		program_name, name);
	exit(1);
	/*NOTREACHED*/
    }
    if ((ecolor.pixel != BlackPixel(dpy, screen)) &&
	(ecolor.pixel != WhitePixel(dpy, screen)) &&
	(DefaultVisual(dpy, screen)->class & Dynamic))
	save_colors = 1;
    return(ecolor.pixel);
}