tag 886496 patch
thanks.

On 07.01.2019 18:50, Bernhard Übelacker wrote:
> Dear Maintainer,
> I tried to have a look at this segfault.
> 
> It seems this is a case of pointer truncation.

Thanks for finding the problem!

Now that I knew where to look, I made a patch to store the pointer in a
separate array and only pass an index into that array to the backend.
With an error message if the array exceeds the maximum size
representable by an int...

I tested it in the stable package and so far it worked.

I used these for testing (particularly against memory leaks):

perl -e 'use OpenGL ":all"; glutInit(); glutCreateWindow("title"); sub
queue { my ($time,$id) = @_; glutTimerFunc($time,sub{ print $id,"\n";
queue($time,$id); }); } for (1..1000) { queue(sqrt($_),$_); }
glutMainLoop();'

---> using "top", check that resident set size stops growing.


perl -e '$|=1; use List::Util "shuffle"; use OpenGL ":all"; glutInit();
glutCreateWindow("title"); my @arr = shuffle(1..1000); for my $x (@arr)
{ glutTimerFunc($x*10,sub{ print $x,"\n"; }); } glutMainLoop();' | tee
foo.txt

perl -ne 'BEGIN{$i=0} print if $_ != ($i+1); $i = $_' < foo.txt

---> check, that the callbacks are not mixed up. (There may be
irregularities if the event times are close to each other)


perl -e 'use OpenGL ":all"; glutInit(); glutCreateWindow("title"); for
my $x (0..66553) { glutTimerFunc(1000,sub{ print $x,"\n"; }); }
glutMainLoop();'

---> Many concurrent timers need a lot of time and memory, but I think
that is more due to the backend than due to my array... Also, it's still
linear time and memory.


One of these days, someone's got to show me how to work *with* quilt
rather than against it...


Yours
Thomas


-- 
OpenPGP Key ID: 0x6BFFE5CF3C7720398928CE741F2DAE97486A60BF
Description: Fix https://bugs.debian.org/886496
   * Patched pogl_glut.xs to fix pointer truncation in glutTimerFunc
     (Closes: #886496)
Author: Thomas Kremer <bugs.deb...@xorg.c-informatik.de>
Bug-Debian: https://bugs.debian.org/886496
Last-Update: 2019-01-23

--- libopengl-perl-0.6704+dfsg.orig/pogl_glut.xs
+++ libopengl-perl-0.6704+dfsg/pogl_glut.xs
@@ -440,10 +440,27 @@ static void generic_glut_Close_handler(v
 	DO_perl_call_sv(handler, G_DISCARD);
 }
 
+/* glut_timer_handlers is an allocation buffer.
+   All unused elements are SVivs forming a linked-list,
+   starting at glut_timer_handlers_next_free.
+   The end of the list is marked by a -1.
+   If no element is free when one is needed, the buffer will grow.
+*/
+static AV * glut_timer_handlers = 0;
+static int glut_timer_handlers_next_free = -1;
+
 /* Callback for glutTimerFunc */
 static void generic_glut_timer_handler(int value)
 {
-	AV * handler_data = (AV*)value;
+	if (!glut_timer_handlers)
+		croak("Timer handler called, but no timers have ever been set up");
+	SV** h = av_fetch(glut_timer_handlers,value,FALSE);
+	if (!h || !SvOK(*h) || !SvROK(*h))
+		croak("Timer handler called for unregistered timer");
+	AV * handler_data = (AV*)SvRV(*h);
+	sv_setiv(*h,glut_timer_handlers_next_free);
+	glut_timer_handlers_next_free = value;
+
 	SV * handler;
 	int i;
 	dSP;
@@ -1016,8 +1033,24 @@ glutTimerFunc(msecs, handler=0, ...)
 			AV * handler_data = newAV();
 		
 			PackCallbackST(handler_data, 1);
+			SV * handler_data_sv = newRV_inc((SV*)handler_data);
 			
-			glutTimerFunc(msecs, generic_glut_timer_handler, (int)handler_data);
+			if (!glut_timer_handlers)
+				glut_timer_handlers = newAV();
+
+			int handler_id = glut_timer_handlers_next_free;
+			if (handler_id == -1) {
+			  handler_id = ((int) av_top_index(glut_timer_handlers))+1;
+			  if (handler_id < 0)
+			    croak("Limit of concurrent timers reached (MAX_INT)");
+			  av_push(glut_timer_handlers, handler_data_sv);
+			} else {
+			  SV** entry = av_fetch(glut_timer_handlers,handler_id,FALSE);
+			  glut_timer_handlers_next_free = SvIV(*entry);
+			  sv_setsv(*entry,sv_2mortal(handler_data_sv));
+			}
+
+			glutTimerFunc(msecs, generic_glut_timer_handler, handler_id);
 		}
 	ENSURE_callback_thread;}
 

Reply via email to