3 * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
4 * Copyright (C) 2002 David A. Schleef <ds@schleef.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
35 #define MAP_ANONYMOUS MAP_ANON
37 /* assume we don't need it */
38 #define MAP_ANONYMOUS 0
42 static GstElementDetails plugin_details = {
45 "This element converts a stream of normal GStreamer buffers into a "
46 "stream of buffers that are allocated in such a way that out-of-bounds "
47 "access to data in the buffer is more likely to cause segmentation "
48 "faults. This allocation method is very similar to the debugging tool "
49 "\"Electric Fence\".",
50 "David A. Schleef <ds@schleef.org>",
53 /* Filter signals and args */
64 static GstStaticPadTemplate gst_efence_sink_factory =
65 GST_STATIC_PAD_TEMPLATE (
72 static GstStaticPadTemplate gst_efence_src_factory =
73 GST_STATIC_PAD_TEMPLATE (
80 static void gst_efence_base_init (gpointer g_class);
81 static void gst_efence_class_init (GstEFenceClass *klass);
82 static void gst_efence_init (GstEFence *filter);
84 static void gst_efence_set_property(GObject *object, guint prop_id,
87 static void gst_efence_get_property(GObject *object, guint prop_id,
91 static void gst_efence_chain (GstPad *pad, GstData *_data);
93 static GstElementClass *parent_class = NULL;
95 typedef struct _GstFencedBuffer GstFencedBuffer;
96 struct _GstFencedBuffer {
102 void gst_fenced_buffer_default_free (GstData *data);
103 GstData * gst_fenced_buffer_default_copy (const GstData *data);
104 void *gst_fenced_buffer_alloc(GstBuffer *buffer, unsigned int length,
106 static GstBuffer * gst_efence_buffer_alloc (GstPad *pad, guint64 offset, guint size);
108 GstBuffer *gst_fenced_buffer_new(void);
111 gst_gst_efence_get_type (void)
113 static GType plugin_type = 0;
117 static const GTypeInfo plugin_info =
119 sizeof (GstEFenceClass),
120 gst_efence_base_init,
122 (GClassInitFunc) gst_efence_class_init,
127 (GInstanceInitFunc) gst_efence_init,
129 plugin_type = g_type_register_static (GST_TYPE_ELEMENT,
137 gst_efence_base_init (gpointer g_class)
139 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
141 gst_element_class_add_pad_template (element_class,
142 gst_static_pad_template_get(&gst_efence_sink_factory));
143 gst_element_class_add_pad_template (element_class,
144 gst_static_pad_template_get(&gst_efence_src_factory));
145 gst_element_class_set_details (element_class, &plugin_details);
148 /* initialize the plugin's class */
150 gst_efence_class_init (GstEFenceClass *klass)
152 GObjectClass *gobject_class;
153 GstElementClass *gstelement_class;
155 gobject_class = (GObjectClass*) klass;
156 gstelement_class = (GstElementClass*) klass;
158 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
160 g_object_class_install_property (gobject_class, ARG_FENCE_TOP,
161 g_param_spec_boolean ("fence_top", "Fence Top", "Align buffers with top of fenced region",
162 TRUE, G_PARAM_READWRITE));
164 gobject_class->set_property = gst_efence_set_property;
165 gobject_class->get_property = gst_efence_get_property;
168 /* initialize the new element
169 * instantiate pads and add them to element
171 * initialize structure
174 gst_efence_init (GstEFence *filter)
176 filter->sinkpad = gst_pad_new_from_template (
177 gst_static_pad_template_get(&gst_efence_sink_factory), "sink");
178 gst_pad_set_getcaps_function (filter->sinkpad, gst_pad_proxy_getcaps);
179 gst_pad_set_link_function (filter->sinkpad, gst_pad_proxy_pad_link);
180 filter->srcpad = gst_pad_new_from_template (
181 gst_static_pad_template_get(&gst_efence_src_factory), "src");
182 gst_pad_set_getcaps_function (filter->srcpad, gst_pad_proxy_getcaps);
183 gst_pad_set_link_function (filter->srcpad, gst_pad_proxy_pad_link);
185 gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
186 gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
187 gst_pad_set_chain_function (filter->sinkpad, gst_efence_chain);
188 gst_pad_set_bufferalloc_function (filter->sinkpad, gst_efence_buffer_alloc);
190 filter->fence_top = TRUE;
194 * this function does the actual processing
198 gst_efence_chain (GstPad *pad, GstData *_data)
200 GstBuffer *buffer = GST_BUFFER (_data);
205 GST_DEBUG ("gst_efence_chain");
207 g_return_if_fail (GST_IS_PAD (pad));
208 g_return_if_fail (buffer != NULL);
210 efence = GST_EFENCE (GST_OBJECT_PARENT (pad));
211 g_return_if_fail (GST_IS_EFENCE (efence));
213 if (GST_DATA_FREE_FUNC (_data) == gst_fenced_buffer_default_free) {
214 gst_pad_push (efence->srcpad, _data);
218 copy = gst_fenced_buffer_new();
220 ptr = gst_fenced_buffer_alloc(copy, GST_BUFFER_SIZE(buffer),
222 memcpy(ptr, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer));
224 GST_BUFFER_DATA (copy) = ptr;
225 GST_BUFFER_SIZE (copy) = GST_BUFFER_SIZE (buffer);
226 GST_BUFFER_MAXSIZE (copy) = GST_BUFFER_SIZE (buffer);
227 GST_BUFFER_TIMESTAMP (copy) = GST_BUFFER_TIMESTAMP (buffer);
228 GST_BUFFER_DURATION (copy) = GST_BUFFER_DURATION (buffer);
229 GST_BUFFER_OFFSET (copy) = GST_BUFFER_OFFSET (buffer);
230 GST_BUFFER_FREE_DATA_FUNC (copy) = NULL;
231 GST_BUFFER_PRIVATE (copy) = NULL;
233 gst_buffer_unref(buffer);
234 gst_pad_push (efence->srcpad, GST_DATA (copy));
238 gst_efence_buffer_alloc (GstPad *pad, guint64 offset, guint size)
243 efence = GST_EFENCE (GST_OBJECT_PARENT (pad));
245 buffer = gst_fenced_buffer_new ();
247 GST_BUFFER_DATA (buffer) = gst_fenced_buffer_alloc(buffer, size,
249 GST_BUFFER_SIZE (buffer) = size;
255 gst_efence_set_property (GObject *object, guint prop_id,
256 const GValue *value, GParamSpec *pspec)
260 g_return_if_fail (GST_IS_EFENCE (object));
261 filter = GST_EFENCE (object);
266 filter->fence_top = g_value_get_boolean (value);
269 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
275 gst_efence_get_property (GObject *object, guint prop_id,
276 GValue *value, GParamSpec *pspec)
280 g_return_if_fail (GST_IS_EFENCE (object));
281 filter = GST_EFENCE (object);
285 g_value_set_boolean (value, filter->fence_top);
288 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
293 /* entry point to initialize the plug-in
294 * initialize the plug-in itself
295 * register the element factories and pad templates
296 * register the features
299 plugin_init (GstPlugin *plugin)
301 if (!gst_element_register (plugin, "efence", GST_RANK_NONE, GST_TYPE_EFENCE))
304 /* plugin initialisation succeeded */
312 "This element converts a stream of normal GStreamer buffers into a "
313 "stream of buffers that are allocated in such a way that out-of-bounds "
314 "access to data in the buffer is more likely to cause segmentation "
315 "faults. This allocation method is very similar to the debugging tool "
316 "\"Electric Fence\".",
323 GstBuffer *gst_fenced_buffer_new(void)
327 newbuf = (GstBuffer *) g_new0(GstFencedBuffer,1);
329 gst_data_init (GST_DATA (newbuf), _gst_buffer_type, 0,
330 gst_fenced_buffer_default_free,
331 gst_fenced_buffer_default_copy);
333 GST_BUFFER_DATA (newbuf) = NULL;
334 GST_BUFFER_SIZE (newbuf) = 0;
335 GST_BUFFER_MAXSIZE (newbuf) = GST_BUFFER_MAXSIZE_NONE;
336 GST_BUFFER_TIMESTAMP (newbuf) = GST_CLOCK_TIME_NONE;
337 GST_BUFFER_DURATION (newbuf) = GST_CLOCK_TIME_NONE;
338 GST_BUFFER_OFFSET (newbuf) = GST_BUFFER_OFFSET_NONE;
339 GST_BUFFER_FREE_DATA_FUNC (newbuf) = NULL;
340 GST_BUFFER_PRIVATE (newbuf) = NULL;
342 GST_DEBUG ("new buffer=%p", newbuf);
347 void gst_fenced_buffer_default_free (GstData *data)
349 GstFencedBuffer *fenced_buffer;
350 GstBuffer *buffer = GST_BUFFER (data);
352 GST_DEBUG ("free buffer=%p", data);
354 g_return_if_fail (data != NULL);
356 fenced_buffer = (GstFencedBuffer *) data;
359 if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_DONTFREE) &&
360 GST_BUFFER_DATA (buffer)) {
361 GST_DEBUG ("free region %p %d", fenced_buffer->region,
362 fenced_buffer->length);
363 munmap(fenced_buffer->region, fenced_buffer->length);
365 GST_DEBUG ("not freeing region %p %d %p", fenced_buffer->region,
366 GST_BUFFER_FLAGS(buffer), GST_BUFFER_DATA(buffer));
369 /* set to safe values */
370 GST_BUFFER_DATA (buffer) = NULL;
371 GST_BUFFER_SIZE (buffer) = 0;
376 GstData* gst_fenced_buffer_default_copy (const GstData *data)
378 GstBuffer *buffer = GST_BUFFER (data);
382 g_return_val_if_fail (buffer != NULL, NULL);
384 /* create a fresh new buffer */
385 copy = (GstData *) g_new0(GstFencedBuffer,1);
387 gst_data_init (copy, _gst_buffer_type, 0,
388 gst_fenced_buffer_default_free,
389 gst_fenced_buffer_default_copy);
391 /* we simply copy everything from our parent */
392 ptr = gst_fenced_buffer_alloc(GST_BUFFER(copy),
393 GST_BUFFER_SIZE(buffer), TRUE);
394 memcpy(ptr, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer));
396 GST_BUFFER_SIZE (copy) = GST_BUFFER_SIZE (buffer);
397 GST_BUFFER_MAXSIZE (copy) = GST_BUFFER_SIZE (buffer);
398 GST_BUFFER_TIMESTAMP (copy) = GST_BUFFER_TIMESTAMP (buffer);
399 GST_BUFFER_DURATION (copy) = GST_BUFFER_DURATION (buffer);
400 GST_BUFFER_OFFSET (copy) = GST_BUFFER_OFFSET (buffer);
401 GST_BUFFER_FREE_DATA_FUNC (copy) = NULL;
402 GST_BUFFER_PRIVATE (copy) = NULL;
407 void *gst_fenced_buffer_alloc(GstBuffer *buffer, unsigned int length,
412 GstFencedBuffer *fenced_buffer = (GstFencedBuffer *) buffer;
415 GST_DEBUG ("buffer=%p length=%d fence_top=%d", buffer, length, fence_top);
417 if(length==0)return NULL;
420 page_size = sysconf(_SC_PAGESIZE);
422 page_size = getpagesize();
425 alloc_size = ((length - 1) & ~(page_size - 1)) + page_size;
426 alloc_size += 2*page_size;
428 region = mmap(NULL, alloc_size, PROT_READ|PROT_WRITE,
429 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
430 if(region == MAP_FAILED){
431 g_warning("mmap failed");
435 munmap(region, page_size);
436 munmap(region + alloc_size - page_size, page_size);
438 fenced_buffer->region = region;
439 fenced_buffer->length = alloc_size;
441 GST_DEBUG ("new region %p %d", fenced_buffer->region,
442 fenced_buffer->length);
446 /* Align to top of region, but force alignment to 4 bytes */
447 offset = alloc_size - page_size - length;
449 return region + offset;
451 return region + page_size;