This project has moved. For the latest updates, please go here.

StackOverflow when running a service

Aug 3, 2012 at 9:08 AM

When scanning QR Codes in a service, I was receiving a stack overflow error, coming from an unknown module.  Downloading the source code and going through it, I was able to determine that the crash was coming from ZXing.QRCode.Internal.FinderPatternFinder, method name handlePossibleCenter or roughly line 486 within that.

The exact root of the problem was an if statement:

if (centerI != Single.NaN)
// which we changed to
if (centerI != null)

I found that the service would randomly crash when scanning QR Codes at this point, but ran with no problem if exactly the same code was used within a Windows Form.

Within the definition methods for floats centerJ and centerI of this method, was multiple "return Single.Nan" (s).  

The problem was resolved by making the centerJ and centerI floats nullable (float?), and by returning null instead of any references to Single.NaN.  

Some examples of changes made are below:

// Within this method, the two floats, centerJ and centerI were floats, and are now nullable, and checked if (centerI != Single.NaN), now check if (centerI != null).
      protected bool handlePossibleCenter(int[] stateCount, int i, int j)
      {
         int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] +
             stateCount[4];
         float? centerJ = centerFromEnd(stateCount, j);
         float? centerI = crossCheckVertical(i, (int)centerJ, stateCount[2], stateCountTotal);

          if (centerI != null)
         {
            // Re-cross check
            centerJ = crossCheckHorizontal((int)centerJ, (int)centerI, stateCount[2], stateCountTotal);
            if (centerJ != null)
              {
                  float newI, newJ;

                  if (centerI == null)
                  { newI = 0; }
                  else { newI = centerI.Value; }

                  if (centerJ == null)
                  { newJ = 0; }
                  else { newJ = centerJ.Value; }


// Within this method, the return null was previous return Single.NaN.
private float? crossCheckVertical(int startI, int centerJ, int maxCount, int originalStateCountTotal)
      {
         BitMatrix image = this.image;

         int maxI = image.Height;
         int[] stateCount = CrossCheckStateCount;

         // Start counting up from center
         int i = startI;
         while (i >= 0 && image[centerJ, i])
         {
            stateCount[2]++;
            i--;
         }
         if (i < 0)
         {
            return null;
         }

Coordinator
Aug 3, 2012 at 7:20 PM

Can you please try the current source from the repository.

A while ago I changed it to the following statements:

         if (!Single.IsNaN(centerI))
         {
            // Re-cross check
            centerJ = crossCheckHorizontal((int)centerJ, (int)centerI, stateCount[2], stateCountTotal);
            if (!Single.IsNaN(centerJ))
            {

 

Aug 4, 2012 at 11:33 AM

Sorry for the confusion.  I posted it as well as I could remember it from the top of my head.  I definitely downloaded the current source code, and it did previously look as you have quoted above: 

         if (!Single.IsNaN(centerI))
         {
            // Re-cross check
            centerJ = crossCheckHorizontal((int)centerJ, (int)centerI, stateCount[2], stateCountTotal);
            if (!Single.IsNaN(centerJ))
            {

This was changed to:
         if (centerI != null)
         {
            // Re-cross check
            centerJ = crossCheckHorizontal((int)centerJ, (int)centerI, stateCount[2], stateCountTotal);
            if (centerJ != null)
            {
Which seemed to fix the stackoverflow when running as a Windows Service.
Again, sorry for the confusion, and I hope that I have cleared that up for you.
Coordinator
Aug 4, 2012 at 12:23 PM

I think you are right. I should change the comparison. I'm not sure why it works for Windows Forms.

But I found some articles in the internet which describe the special behaviour of Single.NaN:
http://stackoverflow.com/questions/11518563/single-nan-doesnt-equal-itself

Aug 21, 2012 at 7:38 AM
Edited Aug 21, 2012 at 7:39 AM

After having looked further into it, it would appear that the source of the Stack Overflow errors may be within a few of the calculations, where divisions by 0 seemed to be happening.  I have found it necessary to track down the exact calculations which are causing the errors, and add checks for 0 at certain points throughout the source code in order to fix the errors for my own project.  

The example shown below is found in ZXing.Datamatrix.Internal.Detector - correctTopRightRectangular - roughly line 255, but there are a few more similar instances.

 

//Changed to check for norm != 0 because it was dividing by norm when norm = 0.

if (norm != 0)
{
    cos = (topRight.X - bottomRight.X) / norm;
    sin = (topRight.Y - bottomRight.Y) / norm;
}
else
{
return null;
}

There are a few more instances where I have found it necessary to make checks such as these, and felt that it may be beneficial to yourself or others, in case they also run into the same problem.  Just to reiterate, this does seem to be a problem which only occurs when running this library through a service.

Coordinator
Aug 21, 2012 at 8:15 PM

It would be great if you can provide some patches.

For the datamatrix detector I added the checks.