API: add gst_buffer_try_new_and_alloc() plus unit test (#431940).
authorTim-Philipp Müller <tim@centricular.net>
Thu, 26 Apr 2007 10:00:49 +0000 (10:00 +0000)
committerTim-Philipp Müller <tim@centricular.net>
Thu, 26 Apr 2007 10:00:49 +0000 (10:00 +0000)
Original commit message from CVS:
* docs/gst/gstreamer-sections.txt:
* gst/gstbuffer.c: (gst_buffer_try_new_and_alloc):
* gst/gstbuffer.h:
* tests/check/gst/gstbuffer.c: (GST_START_TEST),
(gst_buffer_suite):
API: add gst_buffer_try_new_and_alloc() plus unit test (#431940).

ChangeLog
docs/gst/gstreamer-sections.txt
gst/gstbuffer.c
gst/gstbuffer.h
tests/check/gst/gstbuffer.c

index e6f8b3c..0412667 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2007-04-26  Tim-Philipp Müller  <tim at centricular dot net>
+
+       * docs/gst/gstreamer-sections.txt:
+       * gst/gstbuffer.c: (gst_buffer_try_new_and_alloc):
+       * gst/gstbuffer.h:
+       * tests/check/gst/gstbuffer.c: (GST_START_TEST),
+       (gst_buffer_suite):
+         API: add gst_buffer_try_new_and_alloc() plus unit test (#431940).
+
 2007-04-26  Stefan Kost  <ensonic@users.sf.net>
 
        * gst/gstregistrybinary.c: (gst_registry_binary_write_cache),
index f091ea5..096bb9a 100644 (file)
@@ -157,6 +157,7 @@ GST_BUFFER_TRACE_NAME
 
 gst_buffer_new
 gst_buffer_new_and_alloc
+gst_buffer_try_new_and_alloc
 
 gst_buffer_ref
 gst_buffer_unref
index 236263a..a9b65cc 100644 (file)
@@ -305,7 +305,12 @@ gst_buffer_new (void)
  * @size: the size of the new buffer's data.
  *
  * Creates a newly allocated buffer with data of the given size.
- * The buffer memory is not cleared.
+ * The buffer memory is not cleared. If the requested amount of
+ * memory can't be allocated, the program will abort. Use
+ * gst_buffer_try_new_and_alloc() if you want to handle this case
+ * gracefully or have gotten the size to allocate from an untrusted
+ * source such as a media stream.
+ * 
  *
  * Note that when @size == 0, the buffer data pointer will be NULL.
  *
@@ -329,6 +334,48 @@ gst_buffer_new_and_alloc (guint size)
 }
 
 /**
+ * gst_buffer_try_new_and_alloc:
+ * @size: the size of the new buffer's data.
+ *
+ * Tries to create a newly allocated buffer with data of the given size. If
+ * the requested amount of memory can't be allocated, NULL will be returned.
+ * The buffer memory is not cleared.
+ *
+ * Note that when @size == 0, the buffer data pointer will be NULL.
+ *
+ * MT safe.
+ *
+ * Returns: a new #GstBuffer, or NULL if the memory couldn't be allocated.
+ *
+ * Since: 0.10.13
+ */
+GstBuffer *
+gst_buffer_try_new_and_alloc (guint size)
+{
+  GstBuffer *newbuf;
+  guint8 *malloc_data;
+
+  malloc_data = g_try_malloc (size);
+
+  if (G_UNLIKELY (malloc_data == NULL && size != 0)) {
+    GST_CAT_WARNING (GST_CAT_BUFFER, "failed to allocate %d bytes", size);
+    return NULL;
+  }
+
+  /* FIXME: there's no g_type_try_create_instance() in GObject yet, so this
+   * will still abort if a new GstBuffer structure can't be allocated */
+  newbuf = gst_buffer_new ();
+
+  GST_BUFFER_MALLOCDATA (newbuf) = malloc_data;
+  GST_BUFFER_DATA (newbuf) = malloc_data;
+  GST_BUFFER_SIZE (newbuf) = size;
+
+  GST_CAT_LOG (GST_CAT_BUFFER, "new %p of size %d", newbuf, size);
+
+  return newbuf;
+}
+
+/**
  * gst_buffer_get_caps:
  * @buffer: a #GstBuffer.
  *
index 2c08fd7..7b05c46 100644 (file)
@@ -267,10 +267,12 @@ struct _GstBufferClass {
   GstMiniObjectClass    mini_object_class;
 };
 
+GType       gst_buffer_get_type (void);
+
 /* allocation */
-GType          gst_buffer_get_type             (void);
-GstBuffer*     gst_buffer_new                  (void);
-GstBuffer*     gst_buffer_new_and_alloc        (guint size);
+GstBuffer * gst_buffer_new               (void);
+GstBuffer * gst_buffer_new_and_alloc     (guint size);
+GstBuffer * gst_buffer_try_new_and_alloc (guint size);
 
 /**
  * gst_buffer_set_data:
index 7be0c52..792520e 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_VALGRIND
+# include <valgrind/valgrind.h>
+#else
+# define RUNNING_ON_VALGRIND FALSE
+#endif
+
 #include <gst/check/gstcheck.h>
 
 GST_START_TEST (test_caps)
@@ -401,7 +411,40 @@ GST_START_TEST (test_copy)
 
 GST_END_TEST;
 
-Suite *
+GST_START_TEST (test_try_new_and_alloc)
+{
+  GstBuffer *buf;
+
+  /* special case: alloc of 0 bytes results in new buffer with NULL data */
+  buf = gst_buffer_try_new_and_alloc (0);
+  fail_unless (buf != NULL);
+  fail_unless (GST_IS_BUFFER (buf));
+  fail_unless (GST_BUFFER_SIZE (buf) == 0);
+  fail_unless (GST_BUFFER_DATA (buf) == NULL);
+  fail_unless (GST_BUFFER_MALLOCDATA (buf) == NULL);
+  gst_buffer_unref (buf);
+
+  /* normal alloc should still work */
+  buf = gst_buffer_try_new_and_alloc (640 * 480 * 4);
+  fail_unless (buf != NULL);
+  fail_unless (GST_IS_BUFFER (buf));
+  fail_unless (GST_BUFFER_SIZE (buf) == (640 * 480 * 4));
+  fail_unless (GST_BUFFER_DATA (buf) != NULL);
+  fail_unless (GST_BUFFER_MALLOCDATA (buf) != NULL);
+  GST_BUFFER_DATA (buf)[640 * 479 * 4 + 479] = 0xff;
+  gst_buffer_unref (buf);
+
+  /* now this better fail (don't run in valgrind, it will abort
+   * or warn when passing silly arguments to malloc) */
+  if (!RUNNING_ON_VALGRIND) {
+    buf = gst_buffer_try_new_and_alloc ((guint) - 1);
+    fail_unless (buf == NULL);
+  }
+}
+
+GST_END_TEST;
+
+static Suite *
 gst_buffer_suite (void)
 {
   Suite *s = suite_create ("GstBuffer");
@@ -416,6 +459,7 @@ gst_buffer_suite (void)
   tcase_add_test (tc_chain, test_span);
   tcase_add_test (tc_chain, test_metadata_writable);
   tcase_add_test (tc_chain, test_copy);
+  tcase_add_test (tc_chain, test_try_new_and_alloc);
 
   return s;
 }