Hello,

I was just going through the code and noticed a possible issue with the fifo 
code. I think there will be instances where it is not two process safe. I have 
similar code which I got burned on recently. It applies to both read and write.

int fifo_write(struct FIFO *fifo, short data[], int n) {
    int            i;
    short         *pdata;
    short         *pin = fifo->pin;

    assert(fifo != NULL);
    assert(data != NULL);

    if (n > fifo_free(fifo)) {
                return -1;
    }
    else {

                /* This could be made more efficient with block copies
                   using memcpy */

                pdata = data;
                for(i=0; i<n; i++) {

  1.  ->        *pin++ = *pdata++;
  2.  ->        if (pin == (fifo->buf + fifo->nshort))
                                pin = fifo->buf;
                }
                fifo->pin = pin;
    }

    return 0;
}


  1.  Depending on compiler/optimizations it is possible that the following 
happens:
     *   pin pointer value will be loaded to a register from memory
     *   The actual value in memory will be incremented. The pointer increment 
is essentially done before storing data
     *   The value stored in the register is used to store pdata.


The intent of the C code is not violated by this sequence, but the compiler has 
no idea this is being used as a 2 process safe code. If this happens and the 
reading process runs at just the right time it could read out invalid data. To 
get around this make pin volatile and do the increment after the data transfer 
(the volatile will ensure the compiler maintains the order you want).


  1.  At this point it's possible for pin to point to invalid memory. If the 
reading process gets context at this instant there could be a lot of invalid 
data read out. This one is harder to fix. Typically I use free running offsets 
instead of pointers for this type of code. Also my code requires modulus, but 
to make it more efficient I make the Fifo size be a power of 2 so that I can 
use the and operator (ulMyBufferMask is fifo size -1)

ULONG
Length()
{
    return (((ULONG)(ulMyHead - ulMyTail)) & ulMyBufferMask);
}

ULONG
FreeSpace()
{
    return (ulMyBufferMask - Length());
}

BOOL
Put(
    UCHAR* pucBuf_, //The buffer to store
    USHORT usLen_) //Number of elements in the passed in buffer that will be 
stored
{
    //Check there is enough room for the entire buffer
    if (usLen_ > FreeSpace())
        return FALSE;

    //Store buffer
    for (USHORT i = 0; i < usLen_; i++)
    {
        pucMyBuffer[ulMyHead & ulMyBufferMask] = pucBuf_[i];
        ulMyHead++;
    }

    return TRUE;
}

If I misunderstood the code and there are no issues please ignore my long 
blurb. Just bringing this up as the comments indicate the Fifo is meant to be 2 
process safe. Data corruption created by these types of bugs will be very 
timing dependent and infuriating to debug so hopefully this helps.

Cheers,
Marko
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Freetel-codec2 mailing list
Freetel-codec2@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/freetel-codec2

Reply via email to