/** * gdk_pixbuf_new: * @colorspace: Color space for image * @has_alpha: Whether the image should have transparency information * @bits_per_sample: Number of bits per color sample * @width: Width of image in pixels, must be > 0 * @height: Height of image in pixels, must be > 0 * * Creates a new #GdkPixbuf structure and allocates a buffer for it. The * buffer has an optimal rowstride. Note that the buffer is not cleared; * you will have to fill it completely yourself. * * Return value: (nullable): A newly-created #GdkPixbuf with a reference count of 1, or * %NULL if not enough memory could be allocated for the image buffer. **/ GdkPixbuf * gdk_pixbuf_new (GdkColorspace colorspace, gboolean has_alpha, int bits_per_sample, int width, int height) { guchar *buf; int rowstride; rowstride = gdk_pixbuf_calculate_rowstride (colorspace, has_alpha, bits_per_sample, width, height); if (rowstride <= 0) return NULL; buf = g_try_malloc_n (height, rowstride); if (!buf) return NULL; return gdk_pixbuf_new_from_data (buf, colorspace, has_alpha, bits_per_sample, width, height, rowstride, free_buffer, NULL); }
/** * gdk_pixbuf_new: * @colorspace: Color space for image * @has_alpha: Whether the image should have transparency information * @bits_per_sample: Number of bits per color sample * @width: Width of image in pixels, must be > 0 * @height: Height of image in pixels, must be > 0 * * Creates a new #GdkPixbuf structure and allocates a buffer for it. The * buffer has an optimal rowstride. Note that the buffer is not cleared; * you will have to fill it completely yourself. * * Return value: A newly-created #GdkPixbuf with a reference count of 1, or * %NULL if not enough memory could be allocated for the image buffer. **/ GdkPixbuf * gdk_pixbuf_new (GdkColorspace colorspace, gboolean has_alpha, int bits_per_sample, int width, int height) { guchar *buf; int channels; int rowstride; g_return_val_if_fail (colorspace == GDK_COLORSPACE_RGB, NULL); g_return_val_if_fail (bits_per_sample == 8, NULL); g_return_val_if_fail (width > 0, NULL); g_return_val_if_fail (height > 0, NULL); channels = has_alpha ? 4 : 3; rowstride = width * channels; if (rowstride / channels != width || rowstride + 3 < 0) /* overflow */ return NULL; /* Always align rows to 32-bit boundaries */ rowstride = (rowstride + 3) & ~3; buf = g_try_malloc_n (height, rowstride); if (!buf) return NULL; return gdk_pixbuf_new_from_data (buf, colorspace, has_alpha, bits_per_sample, width, height, rowstride, free_buffer, NULL); }
static gpointer try_malloc_n (gsize n_blocks, gsize n_block_bytes, GError **error) { gpointer ptr = g_try_malloc_n (n_blocks, n_block_bytes); if (ptr == NULL) g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_NO_MEMORY, _("Failed to allocate memory")); return ptr; }
void *g_try_malloc(size_t size) { return g_try_malloc_n(1, size); }
/** * gdk_pixbuf_from_pixdata: * @pixdata: a #GdkPixdata to convert into a #GdkPixbuf. * @copy_pixels: whether to copy raw pixel data; run-length encoded * pixel data is always copied. * @error: location to store possible errors. * * Converts a #GdkPixdata to a #GdkPixbuf. If @copy_pixels is %TRUE or * if the pixel data is run-length-encoded, the pixel data is copied into * newly-allocated memory; otherwise it is reused. * * Returns: (transfer full): a new #GdkPixbuf. * Deprecated: 2.32: Use #GResource instead. **/ GdkPixbuf* gdk_pixbuf_from_pixdata (const GdkPixdata *pixdata, gboolean copy_pixels, GError **error) { guint encoding, bpp; guint8 *data = NULL; g_return_val_if_fail (pixdata != NULL, NULL); g_return_val_if_fail (pixdata->width > 0, NULL); g_return_val_if_fail (pixdata->height > 0, NULL); g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL); g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB || (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL); g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL); g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW || (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL); g_return_val_if_fail (pixdata->pixel_data != NULL, NULL); bpp = (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ? 3 : 4; encoding = pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK; g_debug ("gdk_pixbuf_from_pixdata() called on:"); g_debug ("\tEncoding %s", encoding == GDK_PIXDATA_ENCODING_RAW ? "raw" : "rle"); g_debug ("\tDimensions: %d x %d", pixdata->width, pixdata->height); g_debug ("\tRowstride: %d, Length: %d", pixdata->rowstride, pixdata->length); g_debug ("\tCopy pixels == %s", copy_pixels ? "true" : "false"); if (encoding == GDK_PIXDATA_ENCODING_RLE) copy_pixels = TRUE; /* Sanity check the length and dimensions */ if (SIZE_OVERFLOWS (pixdata->height, pixdata->rowstride)) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Image pixel data corrupt")); return NULL; } if (encoding == GDK_PIXDATA_ENCODING_RAW && pixdata->length >= 1 && pixdata->length < pixdata->height * pixdata->rowstride - GDK_PIXDATA_HEADER_LENGTH) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Image pixel data corrupt")); return NULL; } if (copy_pixels) { data = g_try_malloc_n (pixdata->height, pixdata->rowstride); if (!data) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, g_dngettext(GETTEXT_PACKAGE, "failed to allocate image buffer of %u byte", "failed to allocate image buffer of %u bytes", pixdata->rowstride * pixdata->height), pixdata->rowstride * pixdata->height); return NULL; } } if (encoding == GDK_PIXDATA_ENCODING_RLE) { const guint8 *rle_buffer = pixdata->pixel_data; guint8 *rle_buffer_limit = NULL; guint8 *image_buffer = data; guint8 *image_limit = data + pixdata->rowstride * pixdata->height; gboolean check_overrun = FALSE; if (pixdata->length >= 1) rle_buffer_limit = pixdata->pixel_data + pixdata->length - GDK_PIXDATA_HEADER_LENGTH; while (image_buffer < image_limit && (rle_buffer_limit != NULL || rle_buffer > rle_buffer_limit)) { guint length; if (RLE_OVERRUN(1)) { check_overrun = TRUE; break; } length = *(rle_buffer++); if (length & 128) { length = length - 128; check_overrun = image_buffer + length * bpp > image_limit; if (check_overrun) length = (image_limit - image_buffer) / bpp; if (RLE_OVERRUN(bpp < 4 ? 3 : 4)) { check_overrun = TRUE; break; } if (bpp < 4) /* RGB */ do { memcpy (image_buffer, rle_buffer, 3); image_buffer += 3; } while (--length); else /* RGBA */ do { memcpy (image_buffer, rle_buffer, 4); image_buffer += 4; } while (--length); if (RLE_OVERRUN(bpp)) { check_overrun = TRUE; break; } rle_buffer += bpp; } else { length *= bpp; check_overrun = image_buffer + length > image_limit; if (check_overrun) length = image_limit - image_buffer; if (RLE_OVERRUN(length)) { check_overrun = TRUE; break; } memcpy (image_buffer, rle_buffer, length); image_buffer += length; rle_buffer += length; } } if (check_overrun) { g_free (data); g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Image pixel data corrupt")); return NULL; } } else if (copy_pixels) memcpy (data, pixdata->pixel_data, pixdata->rowstride * pixdata->height); else data = pixdata->pixel_data; return gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB, (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, 8, pixdata->width, pixdata->height, pixdata->rowstride, copy_pixels ? (GdkPixbufDestroyNotify) g_free : NULL, data); }
static void mem_overflow (void) { gsize a = G_MAXSIZE / 10 + 10; gsize b = 10; gpointer p, q; typedef char X[10]; #define CHECK_PASS(P) p = (P); g_assert (p == NULL); #define CHECK_FAIL(P) p = (P); g_assert (p != NULL); CHECK_PASS (g_try_malloc_n (a, a)); CHECK_PASS (g_try_malloc_n (a, b)); CHECK_PASS (g_try_malloc_n (b, a)); CHECK_FAIL (g_try_malloc_n (b, b)); CHECK_PASS (g_try_malloc0_n (a, a)); CHECK_PASS (g_try_malloc0_n (a, b)); CHECK_PASS (g_try_malloc0_n (b, a)); CHECK_FAIL (g_try_malloc0_n (b, b)); q = g_malloc (1); CHECK_PASS (g_try_realloc_n (q, a, a)); CHECK_PASS (g_try_realloc_n (q, a, b)); CHECK_PASS (g_try_realloc_n (q, b, a)); CHECK_FAIL (g_try_realloc_n (q, b, b)); free (p); CHECK_PASS (g_try_new (X, a)); CHECK_FAIL (g_try_new (X, b)); CHECK_PASS (g_try_new0 (X, a)); CHECK_FAIL (g_try_new0 (X, b)); q = g_try_malloc (1); CHECK_PASS (g_try_renew (X, q, a)); CHECK_FAIL (g_try_renew (X, q, b)); free (p); #undef CHECK_FAIL #undef CHECK_PASS #define CHECK_FAIL(P) if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) { p = (P); exit (0); } g_test_trap_assert_failed(); #define CHECK_PASS(P) if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR)) { p = (P); exit (0); } g_test_trap_assert_passed(); CHECK_FAIL (g_malloc_n (a, a)); CHECK_FAIL (g_malloc_n (a, b)); CHECK_FAIL (g_malloc_n (b, a)); CHECK_PASS (g_malloc_n (b, b)); CHECK_FAIL (g_malloc0_n (a, a)); CHECK_FAIL (g_malloc0_n (a, b)); CHECK_FAIL (g_malloc0_n (b, a)); CHECK_PASS (g_malloc0_n (b, b)); q = g_malloc (1); CHECK_FAIL (g_realloc_n (q, a, a)); CHECK_FAIL (g_realloc_n (q, a, b)); CHECK_FAIL (g_realloc_n (q, b, a)); CHECK_PASS (g_realloc_n (q, b, b)); free (q); CHECK_FAIL (g_new (X, a)); CHECK_PASS (g_new (X, b)); CHECK_FAIL (g_new0 (X, a)); CHECK_PASS (g_new0 (X, b)); q = g_malloc (1); CHECK_FAIL (g_renew (X, q, a)); CHECK_PASS (g_renew (X, q, b)); free (q); }