[FFmpeg-devel] [PATCH] avformat/cache: Separate read and seek return-values within cache_read

Bryan Huh bryan at box.com
Mon Nov 2 07:56:45 CET 2015


Fixes an issue where an int64_t ffurl_seek return-value was being stored
in a generic int "r" variable, leading to integer overflow when seeking
into a large file (>2GB), and ultimately a "Failed to perform internal
seek" error mesage. The "r" variable was used both for storing the
result of any seeks and for the result of any reads. Instead, I separate
the variable into an int64_t seek-variable and int read-variable.

To test, try running `ffprobe 'cache:http://<something>'` on a file that
is ~3GB large, whose moov atom is at the end of the file
---
 libavformat/cache.c |   49 +++++++++++++++++++++++++------------------------
 1 files changed, 25 insertions(+), 24 deletions(-)

diff --git a/libavformat/cache.c b/libavformat/cache.c
index a762aa9..b654f45 100644
--- a/libavformat/cache.c
+++ b/libavformat/cache.c
@@ -156,7 +156,8 @@ static int cache_read(URLContext *h, unsigned char *buf, int size)
 {
     Context *c= h->priv_data;
     CacheEntry *entry, *next[2] = {NULL, NULL};
-    int r;
+    int64_t off;
+    int bytes_read = 0;
 
     entry = av_tree_find(c->root, &c->logical_pos, cmp, (void**)next);
 
@@ -169,21 +170,21 @@ static int cache_read(URLContext *h, unsigned char *buf, int size)
         if (in_block_pos < entry->size) {
             int64_t physical_target = entry->physical_pos + in_block_pos;
 
-            if (c->cache_pos != physical_target) {
-                r = lseek(c->fd, physical_target, SEEK_SET);
-            } else
-                r = c->cache_pos;
+            if (c->cache_pos != physical_target)
+                off = lseek(c->fd, physical_target, SEEK_SET);
+            else
+                off = c->cache_pos;
 
-            if (r >= 0) {
-                c->cache_pos = r;
-                r = read(c->fd, buf, FFMIN(size, entry->size - in_block_pos));
+            if (off >= 0) {
+                c->cache_pos = off;
+                bytes_read = read(c->fd, buf, FFMIN(size, entry->size - in_block_pos));
             }
 
-            if (r > 0) {
-                c->cache_pos += r;
-                c->logical_pos += r;
+            if (bytes_read > 0) {
+                c->cache_pos += bytes_read;
+                c->logical_pos += bytes_read;
                 c->cache_hit ++;
-                return r;
+                return bytes_read;
             }
         }
     }
@@ -191,30 +192,30 @@ static int cache_read(URLContext *h, unsigned char *buf, int size)
     // Cache miss or some kind of fault with the cache
 
     if (c->logical_pos != c->inner_pos) {
-        r = ffurl_seek(c->inner, c->logical_pos, SEEK_SET);
-        if (r<0) {
+        off = ffurl_seek(c->inner, c->logical_pos, SEEK_SET);
+        if (off<0) {
             av_log(h, AV_LOG_ERROR, "Failed to perform internal seek\n");
-            return r;
+            return off;
         }
-        c->inner_pos = r;
+        c->inner_pos = off;
     }
 
-    r = ffurl_read(c->inner, buf, size);
-    if (r == 0 && size>0) {
+    bytes_read = ffurl_read(c->inner, buf, size);
+    if (bytes_read == 0 && size>0) {
         c->is_true_eof = 1;
         av_assert0(c->end >= c->logical_pos);
     }
-    if (r<=0)
-        return r;
-    c->inner_pos += r;
+    if (bytes_read<=0)
+        return bytes_read;
+    c->inner_pos += bytes_read;
 
     c->cache_miss ++;
 
-    add_entry(h, buf, r);
-    c->logical_pos += r;
+    add_entry(h, buf, bytes_read);
+    c->logical_pos += bytes_read;
     c->end = FFMAX(c->end, c->logical_pos);
 
-    return r;
+    return bytes_read;
 }
 
 static int64_t cache_seek(URLContext *h, int64_t pos, int whence)
-- 
1.7.1



More information about the ffmpeg-devel mailing list