Blame tests/pixbuf-lowmem.c

Packit a4058c
/* -*- Mode: C; c-basic-offset: 2; -*- */
Packit a4058c
/* GdkPixbuf library - test loaders
Packit a4058c
 *
Packit a4058c
 * Copyright (C) 2001 Søren Sandmann (sandmann@daimi.au.dk)
Packit a4058c
 *
Packit a4058c
 * This program is free software; you can redistribute it and/or modify
Packit a4058c
 * it under the terms of the GNU General Public License as published by
Packit a4058c
 * the Free Software Foundation; either version 2 of the License, or
Packit a4058c
 * (at your option) any later version.
Packit a4058c
 *
Packit a4058c
 * This program is distributed in the hope that it will be useful,
Packit a4058c
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit a4058c
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit a4058c
 * GNU General Public License for more details.
Packit a4058c
 *
Packit a4058c
 * You should have received a copy of the GNU General Public License
Packit a4058c
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
Packit a4058c
 */
Packit a4058c
Packit a4058c
#include "config.h"
Packit a4058c
#include "gdk-pixbuf/gdk-pixbuf.h"
Packit a4058c
#include <stdio.h>
Packit a4058c
#include <stdlib.h>
Packit a4058c
#include <time.h>
Packit a4058c
#include <string.h>
Packit a4058c
Packit a4058c
#ifdef __GLIBC__
Packit a4058c
#define PRETEND_MEM_SIZE (16 * 1024 * 1024)
Packit a4058c
#define REMAINING_MEM_SIZE 100000
Packit a4058c
Packit a4058c
Packit a4058c
static int current_allocation = 0;
Packit a4058c
static int max_allocation = PRETEND_MEM_SIZE;
Packit a4058c
Packit a4058c
#define HEADER_SPACE sizeof(gsize)
Packit a4058c
Packit a4058c
extern void *__libc_malloc (size_t size);
Packit a4058c
extern void *__libc_realloc (void *mem, size_t size);
Packit a4058c
extern void *__libc_free (void *mem);
Packit a4058c
Packit a4058c
static gpointer
Packit a4058c
record_bytes (gpointer mem, gsize bytes)
Packit a4058c
{
Packit a4058c
  if (mem == NULL ||
Packit a4058c
      (current_allocation + bytes) > max_allocation)
Packit a4058c
    {
Packit a4058c
      if (mem)
Packit a4058c
        __libc_free (mem);
Packit a4058c
Packit a4058c
      return NULL;
Packit a4058c
    }
Packit a4058c
  
Packit a4058c
  *(void **)mem = GINT_TO_POINTER (bytes);
Packit a4058c
Packit a4058c
  g_assert (GPOINTER_TO_INT (*(void**)mem) == bytes);
Packit a4058c
  
Packit a4058c
  g_assert (current_allocation >= 0);
Packit a4058c
  current_allocation += bytes;
Packit a4058c
  g_assert (current_allocation >= 0);
Packit a4058c
  
Packit a4058c
  g_assert ( mem == (void*) ((((char*)mem) + HEADER_SPACE) - HEADER_SPACE) );
Packit a4058c
  return ((char*)mem) + HEADER_SPACE;
Packit a4058c
}
Packit a4058c
Packit a4058c
void *malloc (size_t n_bytes)
Packit a4058c
{
Packit a4058c
  gpointer mem;
Packit a4058c
Packit a4058c
  mem = __libc_malloc (n_bytes + HEADER_SPACE);
Packit a4058c
  return record_bytes (mem, n_bytes);
Packit a4058c
}
Packit a4058c
Packit a4058c
void *calloc (size_t n_blocks, size_t n_block_bytes)
Packit a4058c
{
Packit a4058c
  size_t bytes;
Packit a4058c
  gpointer mem;
Packit a4058c
Packit a4058c
  bytes = n_blocks * n_block_bytes + HEADER_SPACE;
Packit a4058c
  mem = __libc_malloc (bytes);
Packit a4058c
  memset (mem, 0, bytes);
Packit a4058c
  return record_bytes (mem, n_blocks * n_block_bytes);
Packit a4058c
}
Packit a4058c
Packit a4058c
void free (void *mem)
Packit a4058c
{
Packit a4058c
  gpointer real;
Packit a4058c
Packit a4058c
  if (mem == NULL)
Packit a4058c
    return;
Packit a4058c
Packit a4058c
  real = ((char*)mem) - HEADER_SPACE;
Packit a4058c
Packit a4058c
  g_assert (current_allocation >= 0);
Packit a4058c
  current_allocation -= GPOINTER_TO_INT (*(void**)real);
Packit a4058c
  g_assert (current_allocation >= 0);
Packit a4058c
Packit a4058c
  __libc_free (real);
Packit a4058c
}
Packit a4058c
Packit a4058c
void *realloc (void *mem, size_t n_bytes)
Packit a4058c
{
Packit a4058c
  if (mem == NULL)
Packit a4058c
    return malloc (n_bytes);
Packit a4058c
  else
Packit a4058c
    {
Packit a4058c
      gpointer real;
Packit a4058c
Packit a4058c
      real = ((char*)mem) - HEADER_SPACE;
Packit a4058c
Packit a4058c
      g_assert (current_allocation >= 0);
Packit a4058c
      current_allocation -= GPOINTER_TO_INT (*(void**)real);
Packit a4058c
      g_assert (current_allocation >= 0);
Packit a4058c
Packit a4058c
      return record_bytes (__libc_realloc (real, n_bytes + HEADER_SPACE), n_bytes);
Packit a4058c
    }
Packit a4058c
}
Packit a4058c
Packit a4058c
static void
Packit a4058c
mem_test (const gchar *bytes, gsize len)
Packit a4058c
{
Packit a4058c
  gboolean did_fail = FALSE;
Packit a4058c
  GError *err = NULL;
Packit a4058c
  GdkPixbufLoader *loader;
Packit a4058c
  GList *loaders = NULL;
Packit a4058c
  GList *i;
Packit a4058c
Packit a4058c
  do {
Packit a4058c
    loader = gdk_pixbuf_loader_new ();
Packit a4058c
    gdk_pixbuf_loader_write (loader, (guchar *) bytes, len, &err;;
Packit a4058c
    if (err)
Packit a4058c
      {
Packit a4058c
	g_error_free (err);
Packit a4058c
	err = NULL;
Packit a4058c
	did_fail = TRUE;
Packit a4058c
      }
Packit a4058c
    gdk_pixbuf_loader_close (loader, &err;;
Packit a4058c
    if (err)
Packit a4058c
      {
Packit a4058c
	g_error_free (err);
Packit a4058c
	err = NULL;
Packit a4058c
	did_fail = TRUE;
Packit a4058c
      }
Packit a4058c
    loaders = g_list_prepend (loaders, loader);
Packit a4058c
  } while (!did_fail);
Packit a4058c
Packit a4058c
  for (i = loaders; i != NULL; i = i->next)
Packit a4058c
    g_object_unref (i->data);
Packit a4058c
  g_list_free (loaders);
Packit a4058c
}
Packit a4058c
Packit a4058c
static void
Packit a4058c
almost_exhaust_memory (void)
Packit a4058c
{
Packit a4058c
  gpointer x = g_malloc (REMAINING_MEM_SIZE);
Packit a4058c
  while (g_try_malloc (REMAINING_MEM_SIZE / 10))
Packit a4058c
    ;
Packit a4058c
  g_free (x);
Packit a4058c
}
Packit a4058c
Packit a4058c
static void
Packit a4058c
usage (void)
Packit a4058c
{
Packit a4058c
  g_print ("usage: pixbuf-lowmem <pretend_memory_size> <files>\n");
Packit a4058c
  exit (EXIT_FAILURE);
Packit a4058c
}
Packit a4058c
Packit a4058c
int
Packit a4058c
main (int argc, char **argv)
Packit a4058c
{
Packit a4058c
  int i;
Packit a4058c
  char *endptr;
Packit a4058c
Packit a4058c
  if (argc <= 2)
Packit a4058c
    usage();
Packit a4058c
Packit a4058c
  max_allocation = strtol (argv[1], &endptr, 10);
Packit a4058c
  if (endptr == argv[1])
Packit a4058c
    usage();
Packit a4058c
Packit a4058c
  g_log_set_always_fatal (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
Packit a4058c
Packit a4058c
  /* memory tests */
Packit a4058c
Packit a4058c
  /* How do the loaders behave when memory is low?
Packit a4058c
     It depends on the state the above tests left the
Packit a4058c
     memory in.
Packit a4058c
Packit a4058c
     - Sometimes the png loader tries to report an
Packit a4058c
       "out of memory", but then g_strdup_printf() calls
Packit a4058c
       g_malloc(), which fails.
Packit a4058c
Packit a4058c
     - There are unchecked realloc()s inside libtiff, which means it
Packit a4058c
       will never work with low memory, unless something drastic is
Packit a4058c
       done, like allocating a lot of memory upfront and release it
Packit a4058c
       before entering libtiff.  Also, some TIFFReadRGBAImage calls
Packit a4058c
       returns successfully, even though they have called the error
Packit a4058c
       handler with an 'out of memory' message.
Packit a4058c
  */
Packit a4058c
Packit a4058c
  almost_exhaust_memory ();
Packit a4058c
Packit a4058c
  g_print ("Allocated %dK of %dK, %dK free during tests\n",
Packit a4058c
           current_allocation / 1024, max_allocation / 1024,
Packit a4058c
           (max_allocation - current_allocation) / 1024);
Packit a4058c
Packit a4058c
  for (i = 2; i < argc; ++i)
Packit a4058c
    {
Packit a4058c
      gchar *contents;
Packit a4058c
      gsize size;
Packit a4058c
      GError *err = NULL;
Packit a4058c
Packit a4058c
      if (!g_file_get_contents (argv[i], &contents, &size, &err))
Packit a4058c
	{
Packit a4058c
	  g_print ("couldn't read %s: %s\n", argv[i], err->message);
Packit a4058c
	  exit (EXIT_FAILURE);
Packit a4058c
	}
Packit a4058c
      else
Packit a4058c
	{
Packit a4058c
	  g_print ("%-40s memory            ", argv[i]);
Packit a4058c
	  fflush (stdout);
Packit a4058c
	  mem_test (contents, size);
Packit a4058c
	  g_print ("\tpassed\n");
Packit a4058c
	  g_free (contents);
Packit a4058c
	}
Packit a4058c
    }
Packit a4058c
  
Packit a4058c
  return 0;
Packit a4058c
}
Packit a4058c
#else
Packit a4058c
int
Packit a4058c
main (int argc, char **argv)
Packit a4058c
{
Packit a4058c
	return 0;
Packit a4058c
}
Packit a4058c
#endif