Code: Select all
/* .NAME wlb --- expose a locale-related bug in MagickWand
* .SH SYNOPSIS
* LANG=pl_PL.utf8 gdb wlb
* .SH BUGS
* The program crashes with segmentation violation when $LANG == pl_PL.utf8
* */
#define TRIGGER_CRASH /* undef to inhibit the crash */
#include <stdlib.h>
#include <stdio.h>
#include <locale.h>
#include <assert.h>
#include <string.h>
#include <ImageMagick/wand/MagickWand.h>
struct stdnames
{ char t_locale [07], t_write [06], t_spawn [05], t_empty [01]; }
const sc_stdnames = { "locale", "write", "spawn" };
static void handle_Magick_error (MagickWand *p_wand)
/* Writes an error message to the standard error */
{
ExceptionType a_sev;
register char *const a_descr = MagickGetException (p_wand, &a_sev);
if (0 > fprintf (stderr, "%s %s %lu %s", GetMagickModule (), a_descr))
{ perror (sc_stdnames. t_write); } MagickRelinquishMemory (a_descr); }
/* !handle_Magick_error X */
int main (int p_arg_count, char const *const p_args [])
/*
* Fills the form with predefined strings.
* The form has four pages and the strings are placed on subsequent pages in order.
*/
{ register int a_code = +EXIT_FAILURE;
if (setlocale (LC_ALL, "") == NULL) perror (sc_stdnames. t_locale);
MagickWandGenesis ();
{ register MagickWand *const a_wand = NewMagickWand ();
if (MagickReadImage (a_wand, "canvas:white") == MagickTrue) /* ?READ_IMAGE_SUCCEEDED Y */
{
register DrawingWand *const a_draw = NewDrawingWand ();
register PixelWand *const a_px = NewPixelWand (); /* .H2 FORM DATA */
static unsigned char const sc_message [] = "BUG!";
PixelSetHSL (a_px, 0, 0, 0);
#ifdef TRIGGER_CRASH
DrawSetStrokeColor (a_draw, a_px);
#endif
DrawAnnotation (a_draw, 0, 0, sc_message);
if (MagickDrawImage (a_wand, a_draw) != MagickTrue) handle_Magick_error (a_wand);
DestroyPixelWand (a_px); DestroyDrawingWand (a_draw); }
else /* ?READ_IMAGE_SUCCEEDED N */ handle_Magick_error (a_wand); /* ?READ_IMAGE_SUCCEEDED */
DestroyMagickWand (a_wand);
}
MagickWandTerminus ();
if (fflush (stdout) < 0)
{ perror (sc_stdnames. t_write); return +EXIT_FAILURE; } else return +a_code;
}
Program received signal SIGSEGV, Segmentation fault.
TraceBezier (primitive_info=0x7ffff4d14840, number_coordinates=<value optimized out>) at magick/draw.c:5076
5076 TracePoint(p,points);
(gdb) bt
#0 TraceBezier (primitive_info=0x7ffff4d14840, number_coordinates=<value optimized out>) at magick/draw.c:5076
#1 0x00007ffff76e162e in TracePath (image=0x41e950, draw_info=0x47ea30) at magick/draw.c:5419
#2 DrawImage (image=0x41e950, draw_info=0x47ea30) at magick/draw.c:3019
#3 0x00007ffff765c2bf in RenderFreetype (image=0x41e950, draw_info=<value optimized out>, encoding=<value optimized out>, offset=0x7fffffff0470, metrics=<value optimized out>) at magick/annotate.c:1471
#4 0x00007ffff765cd9e in RenderType (image=0x41e950, draw_info=<value optimized out>, offset=0x7fffffff0470, metrics=0x7fffffff03a0) at magick/annotate.c:916
#5 0x00007ffff765e68f in AnnotateImage (image=0x41e950, draw_info=0x46e310) at magick/annotate.c:481
#6 0x00007ffff76dc600 in DrawPrimitive (image=0x41e950, draw_info=<value optimized out>, primitive_info=0x457f80) at magick/draw.c:4402
#7 0x00007ffff76e0471 in DrawImage (image=0x41e950, draw_info=0x415c80) at magick/draw.c:3107
#8 0x00007ffff7b55e64 in MagickDrawImage (wand=0x408a00, drawing_wand=<value optimized out>) at wand/magick-image.c:2759
#9 0x0000000000400dc8 in main (p_arg_count=1, p_args=0x7fffffffdc58) at wlb.c:49
Version: ImageMagick 6.6.9-5 2011-04-11 Q16 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2011 ImageMagick Studio LLC
Features: OpenMP
control_points == 600 (otherwise 3)
quantum == 200 (initially and otherwise 3)
The program crashes on "O" and "c" but it does not crash on "----" or "." or "(" or "\302\267" (middle dot).
quantum gets modified via primitive_info.
Here is your primitive_info for the 1st curve in "c" when localized, note the bogus values for the ordinate:
{
{point = {x = 5, y = -2}, coordinates = 0, primitive = UndefinedPrimitive, method = UndefinedMethod, text = 0x0},
{point = {x = 4, y = 6875}, coordinates = 0, primitive = UndefinedPrimitive, method = UndefinedMethod, text = 0x0},
{point = {x = -0, y = 984375}, coordinates = 0, primitive = UndefinedPrimitive, method = UndefinedMethod, text = 0x0}}
And here it is when not:
{
{point = {x = 5, y = -2}, coordinates = 0, primitive = UndefinedPrimitive, method = UndefinedMethod, text = 0x0},
{point = {x = 4.6875, y = -0.984375}, coordinates = 0, primitive = UndefinedPrimitive, method = UndefinedMethod, text = 0x0},
{point = {x = 4.1093799999999998, y = -0.609375}, coordinates = 0, primitive = UndefinedPrimitive, method = UndefinedMethod, text = 0x0}}
The structure primitive_info is initialized in stack frame #2 based on a binary argument named keyword; the value of the keyword is the same in both runs. The process crashes after hitting magick/draw.c:1815 3rd time. The following keywords are being considered:
- stroke
- text
- path (crash!)
Code: Select all
case PathPrimitive:
{
char
*s,
*t;
GetMagickToken(q,&q,token);
length=1;
t=token;
for (s=token; *s != '\0'; s=t)
{
double
value;
value=strtod(s,&t);
(void) value;
if (s == t)
{
t++;
continue;
}
length+=BezierQuantum;
}
break;
}
whereas when $LANG == C you get
token == "M4,-2L5,-2Q4.6875,-0.984375 4.10938,-0.609375Q3.53125,-0.25 2.79688,0Q1.98438,0 1.48438,-0.703125Q1,-1.40625 1,-2.6875Q1,-3.78125 1.35938,-4.82812Q1.73438,-5.89062 2.54688,-6.4375Q3.375,-7 4,-7Q4.9218"…
What happened? Dots turned into commas because that is how you write decimal fractions in Polish; commas remained commas because they are hardwired (probably); strtod is unable to tell decimal separator from number separator (which, BTW, is thousands separator in English); havoc; crash; Profit!!!
Well, since nobody has anything to say, I shall try replacing the comma separating numbers by something else. I am considering space, forward slash and line break for the purpose. I also think it is quite inconvenient and inefficient to store textual representation of numbers in internal data structures; the path should be stored and passed in binary form.