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.
34 #define MAP_ANONYMOUS MAP_ANON
37 static GstElementDetails plugin_details = {
40 "This element converts a stream of normal GStreamer buffers into a "
41 "stream of buffers that are allocated in such a way that out-of-bounds "
42 "access to data in the buffer is more likely to cause segmentation "
43 "faults. This allocation method is very similar to the debugging tool "
44 "\"Electric Fence\".",
45 "David A. Schleef <ds@schleef.org>",
48 /* Filter signals and args */
59 GST_PAD_TEMPLATE_FACTORY (gst_efence_sink_factory,
66 GST_PAD_TEMPLATE_FACTORY (gst_efence_src_factory,
73 static void gst_efence_base_init (gpointer g_class);
74 static void gst_efence_class_init (GstEFenceClass *klass);
75 static void gst_efence_init (GstEFence *filter);
77 static void gst_efence_set_property(GObject *object, guint prop_id,
80 static void gst_efence_get_property(GObject *object, guint prop_id,
84 static void gst_efence_chain (GstPad *pad, GstData *_data);
86 static GstElementClass *parent_class = NULL;
88 typedef struct _GstFencedBuffer GstFencedBuffer;
89 struct _GstFencedBuffer {
95 void gst_fenced_buffer_default_free (GstBuffer *buffer);
96 GstBuffer* gst_fenced_buffer_default_copy (GstBuffer *buffer);
97 void *gst_fenced_buffer_alloc(GstBuffer *buffer, unsigned int length,
100 GstBuffer *gst_fenced_buffer_new(void);
102 static GstPadLinkReturn
103 gst_efence_link (GstPad *pad, GstCaps *caps)
108 filter = GST_EFENCE (gst_pad_get_parent (pad));
109 g_return_val_if_fail (filter != NULL, GST_PAD_LINK_REFUSED);
110 g_return_val_if_fail (GST_IS_EFENCE (filter),
111 GST_PAD_LINK_REFUSED);
112 otherpad = (pad == filter->srcpad ? filter->sinkpad : filter->srcpad);
114 if (GST_CAPS_IS_FIXED (caps))
116 /* caps are not fixed, so try to link on the other side and see if
119 if (!gst_pad_try_set_caps (otherpad, caps))
120 return GST_PAD_LINK_REFUSED;
122 /* caps on other side were accepted, so we're ok */
123 return GST_PAD_LINK_OK;
125 /* not enough information yet, delay negotation */
126 return GST_PAD_LINK_DELAYED;
130 gst_gst_efence_get_type (void)
132 static GType plugin_type = 0;
136 static const GTypeInfo plugin_info =
138 sizeof (GstEFenceClass),
139 gst_efence_base_init,
141 (GClassInitFunc) gst_efence_class_init,
146 (GInstanceInitFunc) gst_efence_init,
148 plugin_type = g_type_register_static (GST_TYPE_ELEMENT,
156 gst_efence_base_init (gpointer g_class)
158 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
160 gst_element_class_add_pad_template (element_class, gst_efence_sink_factory ());
161 gst_element_class_add_pad_template (element_class, gst_efence_src_factory ());
162 gst_element_class_set_details (element_class, &plugin_details);
165 /* initialize the plugin's class */
167 gst_efence_class_init (GstEFenceClass *klass)
169 GObjectClass *gobject_class;
170 GstElementClass *gstelement_class;
172 gobject_class = (GObjectClass*) klass;
173 gstelement_class = (GstElementClass*) klass;
175 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
177 g_object_class_install_property (gobject_class, ARG_FENCE_TOP,
178 g_param_spec_boolean ("fence_top", "Fence Top", "Align buffers with top of fenced region",
179 TRUE, G_PARAM_READWRITE));
181 gobject_class->set_property = gst_efence_set_property;
182 gobject_class->get_property = gst_efence_get_property;
185 /* initialize the new element
186 * instantiate pads and add them to element
188 * initialize structure
191 gst_efence_init (GstEFence *filter)
193 filter->sinkpad = gst_pad_new_from_template (gst_efence_sink_factory (),
195 gst_pad_set_link_function (filter->sinkpad, gst_efence_link);
196 filter->srcpad = gst_pad_new_from_template (gst_efence_src_factory (),
198 gst_pad_set_link_function (filter->srcpad, gst_efence_link);
200 gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
201 gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
202 gst_pad_set_chain_function (filter->sinkpad, gst_efence_chain);
204 filter->fence_top = TRUE;
208 * this function does the actual processing
212 gst_efence_chain (GstPad *pad, GstData *_data)
214 GstBuffer *buffer = GST_BUFFER (_data);
219 GST_DEBUG ("gst_efence_chain");
221 g_return_if_fail (GST_IS_PAD (pad));
222 g_return_if_fail (buffer != NULL);
224 efence = GST_EFENCE (GST_OBJECT_PARENT (pad));
225 g_return_if_fail (GST_IS_EFENCE (efence));
227 copy = gst_fenced_buffer_new();
229 ptr = gst_fenced_buffer_alloc(copy, GST_BUFFER_SIZE(buffer),
231 memcpy(ptr, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer));
233 GST_BUFFER_DATA (copy) = ptr;
234 GST_BUFFER_SIZE (copy) = GST_BUFFER_SIZE (buffer);
235 GST_BUFFER_MAXSIZE (copy) = GST_BUFFER_SIZE (buffer);
236 GST_BUFFER_TIMESTAMP (copy) = GST_BUFFER_TIMESTAMP (buffer);
237 GST_BUFFER_DURATION (copy) = GST_BUFFER_DURATION (buffer);
238 GST_BUFFER_OFFSET (copy) = GST_BUFFER_OFFSET (buffer);
239 GST_BUFFER_BUFFERPOOL (copy) = NULL;
240 GST_BUFFER_POOL_PRIVATE (copy) = NULL;
242 gst_buffer_unref(buffer);
243 gst_pad_push (efence->srcpad, GST_DATA (copy));
247 gst_efence_set_property (GObject *object, guint prop_id,
248 const GValue *value, GParamSpec *pspec)
252 g_return_if_fail (GST_IS_EFENCE (object));
253 filter = GST_EFENCE (object);
258 filter->fence_top = g_value_get_boolean (value);
261 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
267 gst_efence_get_property (GObject *object, guint prop_id,
268 GValue *value, GParamSpec *pspec)
272 g_return_if_fail (GST_IS_EFENCE (object));
273 filter = GST_EFENCE (object);
277 g_value_set_boolean (value, filter->fence_top);
280 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
285 /* entry point to initialize the plug-in
286 * initialize the plug-in itself
287 * register the element factories and pad templates
288 * register the features
291 plugin_init (GstPlugin *plugin)
293 if (!gst_element_register (plugin, "efence", GST_RANK_NONE, GST_TYPE_EFENCE))
296 /* plugin initialisation succeeded */
304 "This element converts a stream of normal GStreamer buffers into a "
305 "stream of buffers that are allocated in such a way that out-of-bounds "
306 "access to data in the buffer is more likely to cause segmentation "
307 "faults. This allocation method is very similar to the debugging tool "
308 "\"Electric Fence\".",
316 GstBuffer *gst_fenced_buffer_new(void)
320 newbuf = (GstBuffer *) g_new0(GstFencedBuffer,1);
322 gst_data_init (GST_DATA (newbuf), _gst_buffer_type, 0,
323 (GstDataFreeFunction) gst_fenced_buffer_default_free,
324 (GstDataCopyFunction) gst_fenced_buffer_default_copy);
326 GST_BUFFER_DATA (newbuf) = NULL;
327 GST_BUFFER_SIZE (newbuf) = 0;
328 GST_BUFFER_MAXSIZE (newbuf) = GST_BUFFER_MAXSIZE_NONE;
329 GST_BUFFER_TIMESTAMP (newbuf) = GST_CLOCK_TIME_NONE;
330 GST_BUFFER_DURATION (newbuf) = GST_CLOCK_TIME_NONE;
331 GST_BUFFER_OFFSET (newbuf) = GST_BUFFER_OFFSET_NONE;
332 GST_BUFFER_BUFFERPOOL (newbuf) = NULL;
333 GST_BUFFER_POOL_PRIVATE (newbuf) = NULL;
335 GST_DEBUG ("new buffer=%p", newbuf);
340 void gst_fenced_buffer_default_free (GstBuffer *buffer)
342 GstFencedBuffer *fenced_buffer;
344 GST_DEBUG ("free buffer=%p", buffer);
346 g_return_if_fail (buffer != NULL);
348 fenced_buffer = (GstFencedBuffer *) buffer;
351 if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_DONTFREE) &&
352 GST_BUFFER_DATA (buffer)) {
353 GST_DEBUG ("free region %p %d", fenced_buffer->region,
354 fenced_buffer->length);
355 munmap(fenced_buffer->region, fenced_buffer->length);
357 GST_DEBUG ("not freeing region %p %d %p", fenced_buffer->region,
358 GST_BUFFER_FLAGS(buffer), GST_BUFFER_DATA(buffer));
361 /* set to safe values */
362 GST_BUFFER_DATA (buffer) = NULL;
363 GST_BUFFER_SIZE (buffer) = 0;
368 GstBuffer* gst_fenced_buffer_default_copy (GstBuffer *buffer)
373 g_return_val_if_fail (buffer != NULL, NULL);
375 /* create a fresh new buffer */
376 copy = (GstBuffer *) g_new0(GstFencedBuffer,1);
378 gst_data_init (GST_DATA (copy), _gst_buffer_type, 0,
379 (GstDataFreeFunction) gst_fenced_buffer_default_free,
380 (GstDataCopyFunction) gst_fenced_buffer_default_copy);
382 /* we simply copy everything from our parent */
383 ptr = gst_fenced_buffer_alloc(copy, GST_BUFFER_SIZE(buffer), TRUE);
384 memcpy(ptr, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer));
386 GST_BUFFER_SIZE (copy) = GST_BUFFER_SIZE (buffer);
387 GST_BUFFER_MAXSIZE (copy) = GST_BUFFER_SIZE (buffer);
388 GST_BUFFER_TIMESTAMP (copy) = GST_BUFFER_TIMESTAMP (buffer);
389 GST_BUFFER_DURATION (copy) = GST_BUFFER_DURATION (buffer);
390 GST_BUFFER_OFFSET (copy) = GST_BUFFER_OFFSET (buffer);
391 GST_BUFFER_BUFFERPOOL (copy) = NULL;
392 GST_BUFFER_POOL_PRIVATE (copy) = NULL;
397 void *gst_fenced_buffer_alloc(GstBuffer *buffer, unsigned int length,
402 GstFencedBuffer *fenced_buffer = (GstFencedBuffer *) buffer;
405 GST_DEBUG ("buffer=%p length=%d fence_top=%d", buffer, length, fence_top);
407 if(length==0)return NULL;
410 page_size = sysconf(_SC_PAGESIZE);
412 page_size = getpagesize();
415 alloc_size = ((length - 1) & ~(page_size - 1)) + page_size;
416 alloc_size += 2*page_size;
418 region = mmap(NULL, alloc_size, PROT_READ|PROT_WRITE,
419 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
420 if(region == MAP_FAILED){
421 g_warning("mmap failed");
425 munmap(region, page_size);
426 munmap(region + alloc_size - page_size, page_size);
428 fenced_buffer->region = region;
429 fenced_buffer->length = alloc_size;
431 GST_DEBUG ("new region %p %d", fenced_buffer->region,
432 fenced_buffer->length);
436 /* Align to top of region, but force alignment to 4 bytes */
437 offset = alloc_size - page_size - length;
439 return region + offset;
441 return region + page_size;