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 static GstStaticPadTemplate gst_efence_sink_factory =
60 GST_STATIC_PAD_TEMPLATE (
67 static GstStaticPadTemplate gst_efence_src_factory =
68 GST_STATIC_PAD_TEMPLATE (
75 static void gst_efence_base_init (gpointer g_class);
76 static void gst_efence_class_init (GstEFenceClass *klass);
77 static void gst_efence_init (GstEFence *filter);
79 static void gst_efence_set_property(GObject *object, guint prop_id,
82 static void gst_efence_get_property(GObject *object, guint prop_id,
86 static void gst_efence_chain (GstPad *pad, GstData *_data);
88 static GstElementClass *parent_class = NULL;
90 typedef struct _GstFencedBuffer GstFencedBuffer;
91 struct _GstFencedBuffer {
97 void gst_fenced_buffer_default_free (GstBuffer *buffer);
98 GstBuffer* gst_fenced_buffer_default_copy (GstBuffer *buffer);
99 void *gst_fenced_buffer_alloc(GstBuffer *buffer, unsigned int length,
102 GstBuffer *gst_fenced_buffer_new(void);
105 gst_gst_efence_get_type (void)
107 static GType plugin_type = 0;
111 static const GTypeInfo plugin_info =
113 sizeof (GstEFenceClass),
114 gst_efence_base_init,
116 (GClassInitFunc) gst_efence_class_init,
121 (GInstanceInitFunc) gst_efence_init,
123 plugin_type = g_type_register_static (GST_TYPE_ELEMENT,
131 gst_efence_base_init (gpointer g_class)
133 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
135 gst_element_class_add_pad_template (element_class,
136 gst_static_pad_template_get(&gst_efence_sink_factory));
137 gst_element_class_add_pad_template (element_class,
138 gst_static_pad_template_get(&gst_efence_src_factory));
139 gst_element_class_set_details (element_class, &plugin_details);
142 /* initialize the plugin's class */
144 gst_efence_class_init (GstEFenceClass *klass)
146 GObjectClass *gobject_class;
147 GstElementClass *gstelement_class;
149 gobject_class = (GObjectClass*) klass;
150 gstelement_class = (GstElementClass*) klass;
152 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
154 g_object_class_install_property (gobject_class, ARG_FENCE_TOP,
155 g_param_spec_boolean ("fence_top", "Fence Top", "Align buffers with top of fenced region",
156 TRUE, G_PARAM_READWRITE));
158 gobject_class->set_property = gst_efence_set_property;
159 gobject_class->get_property = gst_efence_get_property;
162 /* initialize the new element
163 * instantiate pads and add them to element
165 * initialize structure
168 gst_efence_init (GstEFence *filter)
170 filter->sinkpad = gst_pad_new_from_template (
171 gst_static_pad_template_get(&gst_efence_sink_factory), "sink");
172 gst_pad_set_link_function (filter->sinkpad, gst_pad_proxy_pad_link);
173 filter->srcpad = gst_pad_new_from_template (
174 gst_static_pad_template_get(&gst_efence_src_factory), "src");
175 gst_pad_set_link_function (filter->srcpad, gst_pad_proxy_pad_link);
177 gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
178 gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
179 gst_pad_set_chain_function (filter->sinkpad, gst_efence_chain);
181 filter->fence_top = TRUE;
185 * this function does the actual processing
189 gst_efence_chain (GstPad *pad, GstData *_data)
191 GstBuffer *buffer = GST_BUFFER (_data);
196 GST_DEBUG ("gst_efence_chain");
198 g_return_if_fail (GST_IS_PAD (pad));
199 g_return_if_fail (buffer != NULL);
201 efence = GST_EFENCE (GST_OBJECT_PARENT (pad));
202 g_return_if_fail (GST_IS_EFENCE (efence));
204 copy = gst_fenced_buffer_new();
206 ptr = gst_fenced_buffer_alloc(copy, GST_BUFFER_SIZE(buffer),
208 memcpy(ptr, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer));
210 GST_BUFFER_DATA (copy) = ptr;
211 GST_BUFFER_SIZE (copy) = GST_BUFFER_SIZE (buffer);
212 GST_BUFFER_MAXSIZE (copy) = GST_BUFFER_SIZE (buffer);
213 GST_BUFFER_TIMESTAMP (copy) = GST_BUFFER_TIMESTAMP (buffer);
214 GST_BUFFER_DURATION (copy) = GST_BUFFER_DURATION (buffer);
215 GST_BUFFER_OFFSET (copy) = GST_BUFFER_OFFSET (buffer);
216 GST_BUFFER_FREE_DATA_FUNC (copy) = NULL;
217 GST_BUFFER_PRIVATE (copy) = NULL;
219 gst_buffer_unref(buffer);
220 gst_pad_push (efence->srcpad, GST_DATA (copy));
224 gst_efence_set_property (GObject *object, guint prop_id,
225 const GValue *value, GParamSpec *pspec)
229 g_return_if_fail (GST_IS_EFENCE (object));
230 filter = GST_EFENCE (object);
235 filter->fence_top = g_value_get_boolean (value);
238 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
244 gst_efence_get_property (GObject *object, guint prop_id,
245 GValue *value, GParamSpec *pspec)
249 g_return_if_fail (GST_IS_EFENCE (object));
250 filter = GST_EFENCE (object);
254 g_value_set_boolean (value, filter->fence_top);
257 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
262 /* entry point to initialize the plug-in
263 * initialize the plug-in itself
264 * register the element factories and pad templates
265 * register the features
268 plugin_init (GstPlugin *plugin)
270 if (!gst_element_register (plugin, "efence", GST_RANK_NONE, GST_TYPE_EFENCE))
273 /* plugin initialisation succeeded */
281 "This element converts a stream of normal GStreamer buffers into a "
282 "stream of buffers that are allocated in such a way that out-of-bounds "
283 "access to data in the buffer is more likely to cause segmentation "
284 "faults. This allocation method is very similar to the debugging tool "
285 "\"Electric Fence\".",
292 GstBuffer *gst_fenced_buffer_new(void)
296 newbuf = (GstBuffer *) g_new0(GstFencedBuffer,1);
298 gst_data_init (GST_DATA (newbuf), _gst_buffer_type, 0,
299 (GstDataFreeFunction) gst_fenced_buffer_default_free,
300 (GstDataCopyFunction) gst_fenced_buffer_default_copy);
302 GST_BUFFER_DATA (newbuf) = NULL;
303 GST_BUFFER_SIZE (newbuf) = 0;
304 GST_BUFFER_MAXSIZE (newbuf) = GST_BUFFER_MAXSIZE_NONE;
305 GST_BUFFER_TIMESTAMP (newbuf) = GST_CLOCK_TIME_NONE;
306 GST_BUFFER_DURATION (newbuf) = GST_CLOCK_TIME_NONE;
307 GST_BUFFER_OFFSET (newbuf) = GST_BUFFER_OFFSET_NONE;
308 GST_BUFFER_FREE_DATA_FUNC (newbuf) = NULL;
309 GST_BUFFER_PRIVATE (newbuf) = NULL;
311 GST_DEBUG ("new buffer=%p", newbuf);
316 void gst_fenced_buffer_default_free (GstBuffer *buffer)
318 GstFencedBuffer *fenced_buffer;
320 GST_DEBUG ("free buffer=%p", buffer);
322 g_return_if_fail (buffer != NULL);
324 fenced_buffer = (GstFencedBuffer *) buffer;
327 if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_DONTFREE) &&
328 GST_BUFFER_DATA (buffer)) {
329 GST_DEBUG ("free region %p %d", fenced_buffer->region,
330 fenced_buffer->length);
331 munmap(fenced_buffer->region, fenced_buffer->length);
333 GST_DEBUG ("not freeing region %p %d %p", fenced_buffer->region,
334 GST_BUFFER_FLAGS(buffer), GST_BUFFER_DATA(buffer));
337 /* set to safe values */
338 GST_BUFFER_DATA (buffer) = NULL;
339 GST_BUFFER_SIZE (buffer) = 0;
344 GstBuffer* gst_fenced_buffer_default_copy (GstBuffer *buffer)
349 g_return_val_if_fail (buffer != NULL, NULL);
351 /* create a fresh new buffer */
352 copy = (GstBuffer *) g_new0(GstFencedBuffer,1);
354 gst_data_init (GST_DATA (copy), _gst_buffer_type, 0,
355 (GstDataFreeFunction) gst_fenced_buffer_default_free,
356 (GstDataCopyFunction) gst_fenced_buffer_default_copy);
358 /* we simply copy everything from our parent */
359 ptr = gst_fenced_buffer_alloc(copy, GST_BUFFER_SIZE(buffer), TRUE);
360 memcpy(ptr, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer));
362 GST_BUFFER_SIZE (copy) = GST_BUFFER_SIZE (buffer);
363 GST_BUFFER_MAXSIZE (copy) = GST_BUFFER_SIZE (buffer);
364 GST_BUFFER_TIMESTAMP (copy) = GST_BUFFER_TIMESTAMP (buffer);
365 GST_BUFFER_DURATION (copy) = GST_BUFFER_DURATION (buffer);
366 GST_BUFFER_OFFSET (copy) = GST_BUFFER_OFFSET (buffer);
367 GST_BUFFER_FREE_DATA_FUNC (copy) = NULL;
368 GST_BUFFER_PRIVATE (copy) = NULL;
373 void *gst_fenced_buffer_alloc(GstBuffer *buffer, unsigned int length,
378 GstFencedBuffer *fenced_buffer = (GstFencedBuffer *) buffer;
381 GST_DEBUG ("buffer=%p length=%d fence_top=%d", buffer, length, fence_top);
383 if(length==0)return NULL;
386 page_size = sysconf(_SC_PAGESIZE);
388 page_size = getpagesize();
391 alloc_size = ((length - 1) & ~(page_size - 1)) + page_size;
392 alloc_size += 2*page_size;
394 region = mmap(NULL, alloc_size, PROT_READ|PROT_WRITE,
395 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
396 if(region == MAP_FAILED){
397 g_warning("mmap failed");
401 munmap(region, page_size);
402 munmap(region + alloc_size - page_size, page_size);
404 fenced_buffer->region = region;
405 fenced_buffer->length = alloc_size;
407 GST_DEBUG ("new region %p %d", fenced_buffer->region,
408 fenced_buffer->length);
412 /* Align to top of region, but force alignment to 4 bytes */
413 offset = alloc_size - page_size - length;
415 return region + offset;
417 return region + page_size;