[FFmpeg-devel] [PATCH] Fix MSVC warnings about possible value truncation.

Reimar Döffinger Reimar.Doeffinger at gmx.de
Tue Sep 2 23:43:33 CEST 2014

On Tue, Sep 02, 2014 at 01:13:27PM -0700, Peter Kasting wrote:
> On Sat, Aug 30, 2014 at 2:21 AM, wm4 <nfxjfg at googlemail.com> wrote:
> > I'd
> > expect it rather to hide bugs than to expose them. For example, it
> > could make a static analyzer with value range analysis stop working,
> > because the casts will basically throw a wrench into its algorithm.
> I can't understand how the sorts of casts that would be introduced here.
> I'm suggesting would harm static analysis.  If we're assigning a value to a
> variable of type T, then "T var = x;" and "T var = (T)x;" have the same
> effect, and a static analyzer ought to treat them identically.

The problem is that we have nothing that ensures the form
T var = (T)x;
T2 var = (T)x;
(where T2 is a wider type than T for example).
Depending on the static analyzer you can make it ignore
T var = x;
but it will start warning again once the type of var or x changes.

+                // !!! Is this cast safe?
+                sub->end_display_time = (uint32_t)av_rescale_q(avpkt->duration,
+                                                               avctx->pkt_timebase, ms);

Don't really see anything much better to do.
You could clamp it to e.g. INT_MAX, but not convinced it
would get any better by that.

+            // !!! Are these casts safe?
+            s->base_matrix[0][i]        = (uint8_t)vp31_intra_y_dequant[i];
+            s->base_matrix[1][i]        = (uint8_t)vp31_intra_c_dequant[i];
+            s->base_matrix[2][i]        = (uint8_t)vp31_inter_dequant[i];

That one is answered by a simple look in the table: None are negative, so yes.
No idea if there is a specific reason they use signed types.
Considering this seems to be the only place they are used, it probably is
a "bug" in sofar as the declared types of the tables are stupid.

     secs %= 86400;
-    tm->tm_hour = secs / 3600;
+    tm->tm_hour =(int)(secs / 3600);
     tm->tm_min = (secs % 3600) / 60;
-    tm->tm_sec =  secs % 60;
+    tm->tm_sec = secs % 60;

The second part breaks the alignment. And the first one the compiler in theory could figure out on its own...

+// !!! Should |pts_num| and |pts_den| be uint64_t?
 void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits,
                          unsigned int pts_num, unsigned int pts_den);

I can only hope that nobody has/will come up with some insanity where
that would be useful.

+        if (ffio_limit(pb, (int)length) != length)

This one actually looks kind of like a bug, the cast might invoke
undefined behaviour.

@@ -1500,7 +1500,7 @@ static void matroska_add_index_entries(MatroskaDemuxContext *matroska)
     EbmlList *index_list;
     MatroskaIndex *index;
-    int index_scale = 1;
+    uint64_t index_scale = 1;

That looks like it will be a really expensive change,
division by a 64 bit value isn't fast.
In general, the nicer way to avoid the matroska issues and saving
a bit of memory would be to add a EBML_UINT32 (dummy) type.

-static int matroska_aac_sri(int samplerate)
+static int matroska_aac_sri(double samplerate)

I don't think this is equivalent at all.
Not sure if it is better or worse though, we seem to switch between doing
int and doing float comparisons.

-        avpriv_set_pts_info(st, 64, matroska->time_scale * track->time_scale,
+        avpriv_set_pts_info(st, 64, (unsigned int)(matroska->time_scale * track->time_scale),
                             1000 * 1000 * 1000);    /* 64 bit pts in ns */

I see where the other question came from.
That looks a bit annoying, won't work for time_scale values > 4s??
Not that I think anyone cares.

--- a/libavformat/riffdec.c
+++ b/libavformat/riffdec.c
@@ -185,7 +185,7 @@ int ff_read_riff_info(AVFormatContext *s, int64_t size)
     while ((cur = avio_tell(pb)) >= 0 &&
            cur <= end - 8 /* = tag + size */) {
         uint32_t chunk_code;
-        int64_t chunk_size;
+        unsigned int chunk_size;

That seems risky to me.
We seem to have the right checks right now, but just one mistake
and we have an integer overflow in a malloc argument and
a huge security hole if we using a 32 bit type here.

         if (bitrate >= 0 && bitrate <= INT_MAX)
-            ic->bit_rate = bitrate;
+            ic->bit_rate = (int)bitrate;

I'd kind of think the compilers should manage at least these trivial cases...

--- a/libavformat/wavdec.c
+++ b/libavformat/wavdec.c
@@ -61,7 +61,7 @@ typedef struct WAVDemuxContext {
-static int64_t next_tag(AVIOContext *pb, uint32_t *tag)
+static unsigned int next_tag(AVIOContext *pb, uint32_t *tag)
     *tag = avio_rl32(pb);
     return avio_rl32(pb);
@@ -76,10 +76,10 @@ static int64_t wav_seek_tag(WAVDemuxContext * wav, AVIOContext *s, int64_t offse
 /* return the size of the found tag */
-static int64_t find_tag(WAVDemuxContext * wav, AVIOContext *pb, uint32_t tag1)
+static unsigned int find_tag(WAVDemuxContext * wav, AVIOContext *pb, uint32_t tag1)
     unsigned int tag;
-    int64_t size;
+    unsigned int size;
     for (;;) {
         if (avio_feof(pb))

These seem reasonable

-            int level = e->param[1] ? av_clip(eval_expr(p, e->param[1]), INT_MIN, INT_MAX) : AV_LOG_INFO;
+            int level = e->param[1] ? (int)av_clip64((int64_t)eval_expr(p, e->param[1]), INT_MIN, INT_MAX) : AV_LOG_INFO;

?? I think I've seen another one like it. Were they meant to be av_clipf/av_clipd?

-            int idx= av_clip(eval_expr(p, e->param[0]), 0, VARS-1);
-            uint64_t r= isnan(p->var[idx]) ? 0 : p->var[idx];
+            int idx= av_clip((int)eval_expr(p, e->param[0]), 0, VARS-1);
+            uint64_t r= isnan(p->var[idx]) ? 0 : (uint64_t)p->var[idx];
             r= r*1664525+1013904223;
-            p->var[idx]= r;
+            p->var[idx]= (double)r;

Can this even work correctly?? I think we'd want to mask that to what double can store without losing precision.

More information about the ffmpeg-devel mailing list