Hi Marko,

Thank you for that analysis.  I used this fifo design a lot, e.g in
FreeDV GUI and the SM1000.  No current issues that I am aware of but
they could be subtle.

What specific changes to fifo.c would you suggest?

Is there a unit test that can demonstrate the problem?

Thanks,

David

On 29/06/18 13:56, Marko Milutinovic wrote:
> 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:
>      1. *pin* pointer value will be loaded to a register from memory
>      2. The actual value in memory will be incremented. The pointer
>         increment is essentially done before storing data
>      3. 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).
> 
>  
> 
>  2. 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
> 

------------------------------------------------------------------------------
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