[xiph-commits] r16409 - in branches/theora-thusnelda/lib: dec enc

tterribe at svn.xiph.org tterribe at svn.xiph.org
Mon Aug 3 23:19:13 PDT 2009


Author: tterribe
Date: 2009-08-03 23:19:12 -0700 (Mon, 03 Aug 2009)
New Revision: 16409

Modified:
   branches/theora-thusnelda/lib/dec/decapiwrapper.c
   branches/theora-thusnelda/lib/dec/decinfo.c
   branches/theora-thusnelda/lib/dec/decint.h
   branches/theora-thusnelda/lib/dec/decode.c
   branches/theora-thusnelda/lib/dec/dequant.c
   branches/theora-thusnelda/lib/dec/huffdec.c
   branches/theora-thusnelda/lib/dec/huffdec.h
   branches/theora-thusnelda/lib/dec/info.c
   branches/theora-thusnelda/lib/dec/internal.c
   branches/theora-thusnelda/lib/dec/state.c
   branches/theora-thusnelda/lib/enc/encapiwrapper.c
   branches/theora-thusnelda/lib/enc/encinfo.c
   branches/theora-thusnelda/lib/enc/encode.c
   branches/theora-thusnelda/lib/enc/rate.c
Log:
Add malloc failure checks.
Note, on platforms that overcommit (including almost every fork-based Unix,
 excluding Solaris), this does not provide any additional safety as the kernel
 could create page table entries and segfault later when it fails to map pages
 to back them, and even platforms that don't overcommit could allocate more
 memory than the machine has physical RAM and cause a DoS via excessive paging.
Nevertheless, on some systems, with proper precautions, these may be useful.
In addition, we now allocate Huffman trees in a single block of RAM, which may
 provide slightly improved cache coherency (the measured benefit, if any, was
 very small).


Modified: branches/theora-thusnelda/lib/dec/decapiwrapper.c
===================================================================
--- branches/theora-thusnelda/lib/dec/decapiwrapper.c	2009-08-04 04:47:16 UTC (rev 16408)
+++ branches/theora-thusnelda/lib/dec/decapiwrapper.c	2009-08-04 06:19:12 UTC (rev 16409)
@@ -96,6 +96,7 @@
     This avoids having to figure out whether or not we need to free the info
      struct in either theora_info_clear() or theora_clear().*/
   apiinfo=(th_api_info *)_ogg_calloc(1,sizeof(*apiinfo));
+  if(apiinfo==NULL)return OC_FAULT;
   /*Make our own copy of the info struct, since its lifetime should be
      independent of the one we were passed in.*/
   *&apiinfo->info=*_ci;
@@ -131,6 +132,7 @@
      theora_info struct like the ones that are used in a theora_state struct.*/
   if(api==NULL){
     _ci->codec_setup=_ogg_calloc(1,sizeof(*api));
+    if(_ci->codec_setup==NULL)return OC_FAULT;
     api=(th_api_wrapper *)_ci->codec_setup;
     api->clear=(oc_setup_clear_func)th_dec_api_clear;
   }

Modified: branches/theora-thusnelda/lib/dec/decinfo.c
===================================================================
--- branches/theora-thusnelda/lib/dec/decinfo.c	2009-08-04 04:47:16 UTC (rev 16408)
+++ branches/theora-thusnelda/lib/dec/decinfo.c	2009-08-04 06:19:12 UTC (rev 16409)
@@ -114,6 +114,7 @@
   len=oc_unpack_length(_opb);
   if(len<0||len>oc_pack_bytes_left(_opb))return TH_EBADHEADER;
   _tc->vendor=_ogg_malloc((size_t)len+1);
+  if(_tc->vendor==NULL)return TH_EFAULT;
   oc_unpack_octets(_opb,_tc->vendor,len);
   _tc->vendor[len]='\0';
   /*Read the user comments.*/
@@ -135,6 +136,10 @@
     }
     _tc->comment_lengths[i]=len;
     _tc->user_comments[i]=_ogg_malloc((size_t)len+1);
+    if(_tc->user_comments[i]==NULL){
+      _tc->comments=i;
+      return TH_EFAULT;
+    }
     oc_unpack_octets(_opb,_tc->user_comments[i],len);
     _tc->user_comments[i][len]='\0';
   }
@@ -201,6 +206,7 @@
         return TH_EBADHEADER;
       }
       setup=(oc_setup_info *)_ogg_calloc(1,sizeof(*setup));
+      if(setup==NULL)return TH_EFAULT;
       ret=oc_setup_unpack(_opb,setup);
       if(ret<0){
         oc_setup_clear(setup);

Modified: branches/theora-thusnelda/lib/dec/decint.h
===================================================================
--- branches/theora-thusnelda/lib/dec/decint.h	2009-08-04 04:47:16 UTC (rev 16408)
+++ branches/theora-thusnelda/lib/dec/decint.h	2009-08-04 06:19:12 UTC (rev 16409)
@@ -80,7 +80,7 @@
   /*The storage for the post-processed frame buffer.*/
   unsigned char       *pp_frame_data;
   /*Whether or not the post-processsed frame buffer has space for chroma.*/
-  int                  pp_frame_has_chroma;
+  int                  pp_frame_state;
   /*The buffer used for the post-processed frame.
     Note that this is _not_ guaranteed to have the same strides and offsets as
      the reference frame buffers.*/

Modified: branches/theora-thusnelda/lib/dec/decode.c
===================================================================
--- branches/theora-thusnelda/lib/dec/decode.c	2009-08-04 04:47:16 UTC (rev 16408)
+++ branches/theora-thusnelda/lib/dec/decode.c	2009-08-04 06:19:12 UTC (rev 16409)
@@ -370,8 +370,23 @@
   int ret;
   ret=oc_state_init(&_dec->state,_info,3);
   if(ret<0)return ret;
-  oc_huff_trees_copy(_dec->huff_tables,
+  ret=oc_huff_trees_copy(_dec->huff_tables,
    (const oc_huff_node *const *)_setup->huff_tables);
+  if(ret<0){
+    oc_state_clear(&_dec->state);
+    return ret;
+  }
+  /*For each fragment, allocate one byte for every DCT coefficient token, plus
+     one byte for extra-bits for each token, plus one more byte for the long
+     EOB run, just in case it's the very last token and has a run length of
+     one.*/
+  _dec->dct_tokens=(unsigned char *)_ogg_malloc((64+64+1)*
+   _dec->state.nfrags*sizeof(_dec->dct_tokens[0]));
+  if(_dec->dct_tokens==NULL){
+    oc_huff_trees_clear(_dec->huff_tables);
+    oc_state_clear(&_dec->state);
+    return TH_EFAULT;
+  }
   for(qi=0;qi<64;qi++)for(pli=0;pli<3;pli++)for(qti=0;qti<2;qti++){
     _dec->state.dequant_tables[qi][pli][qti]=
      _dec->state.dequant_table_data[qi][pli][qti];
@@ -389,12 +404,6 @@
     }
     _dec->pp_sharp_mod[qi]=-(qsum>>11);
   }
-  /*For each fragment, allocate one byte for every DCT coefficient token, plus
-     one byte for extra-bits for each token, plus one more byte for the long
-     EOB run, just in case it's the very last token and has a run length of
-     one.*/
-  _dec->dct_tokens=(unsigned char *)_ogg_malloc((64+64+1)*
-   _dec->state.nfrags*sizeof(_dec->dct_tokens[0]));
   memcpy(_dec->state.loop_filter_limits,_setup->qinfo.loop_filter_limits,
    sizeof(_dec->state.loop_filter_limits));
   _dec->pp_level=OC_PP_LEVEL_DISABLED;
@@ -1190,6 +1199,7 @@
     if(_dec->state.frame_type!=OC_INTRA_FRAME)return 1;
     _dec->dc_qis=(unsigned char *)_ogg_malloc(
      _dec->state.nfrags*sizeof(_dec->dc_qis[0]));
+    if(_dec->dc_qis==NULL)return 1;
     memset(_dec->dc_qis,_dec->state.qis[0],_dec->state.nfrags);
   }
   else{
@@ -1218,15 +1228,37 @@
     }
     return 1;
   }
-  if(_dec->variances==NULL||
-   _dec->pp_frame_has_chroma!=(_dec->pp_level>=OC_PP_LEVEL_DEBLOCKC)){
+  if(_dec->variances==NULL){
     size_t frame_sz;
+    size_t c_sz;
+    int    c_w;
+    int    c_h;
     frame_sz=_dec->state.info.frame_width*(size_t)_dec->state.info.frame_height;
+    c_w=_dec->state.info.frame_width>>!(_dec->state.info.pixel_fmt&1);
+    c_h=_dec->state.info.frame_height>>!(_dec->state.info.pixel_fmt&2);
+    c_sz=c_w*(size_t)c_h;
+    /*Allocate space for the chroma planes, even if we're not going to use
+       them; this simplifies allocation state management, though it may waste
+       memory on the few systems that don't overcommit pages.*/
+    frame_sz+=c_sz<<1;
+    _dec->pp_frame_data=(unsigned char *)_ogg_malloc(
+     frame_sz*sizeof(_dec->pp_frame_data[0]));
+    _dec->variances=(int *)_ogg_malloc(
+     _dec->state.nfrags*sizeof(_dec->variances[0]));
+    if(_dec->variances==NULL||_dec->pp_frame_data==NULL){
+      _ogg_free(_dec->pp_frame_data);
+      _dec->pp_frame_data=NULL;
+      _ogg_free(_dec->variances);
+      _dec->variances=NULL;
+      return 1;
+    }
+    /*Force an update of the PP buffer pointers.*/
+    _dec->pp_frame_state=0;
+  }
+  /*Update the PP buffer pointers if necessary.*/
+  if(_dec->pp_frame_state!=1+(_dec->pp_level>=OC_PP_LEVEL_DEBLOCKC)){
     if(_dec->pp_level<OC_PP_LEVEL_DEBLOCKC){
-      _dec->variances=(int *)_ogg_realloc(_dec->variances,
-       _dec->state.fplanes[0].nfrags*sizeof(_dec->variances[0]));
-      _dec->pp_frame_data=(unsigned char *)_ogg_realloc(
-       _dec->pp_frame_data,frame_sz*sizeof(_dec->pp_frame_data[0]));
+      /*If chroma processing is disabled, just use the PP luma plane.*/
       _dec->pp_frame_buf[0].width=_dec->state.info.frame_width;
       _dec->pp_frame_buf[0].height=_dec->state.info.frame_height;
       _dec->pp_frame_buf[0].stride=-_dec->pp_frame_buf[0].width;
@@ -1238,15 +1270,11 @@
       size_t c_sz;
       int    c_w;
       int    c_h;
-      _dec->variances=(int *)_ogg_realloc(_dec->variances,
-       _dec->state.nfrags*sizeof(_dec->variances[0]));
-      y_sz=frame_sz;
+      /*Otherwise, set up pointers to all three PP planes.*/
+      y_sz=_dec->state.info.frame_width*(size_t)_dec->state.info.frame_height;
       c_w=_dec->state.info.frame_width>>!(_dec->state.info.pixel_fmt&1);
       c_h=_dec->state.info.frame_height>>!(_dec->state.info.pixel_fmt&2);
-      c_sz=c_w*c_h;
-      frame_sz+=c_sz<<1;
-      _dec->pp_frame_data=(unsigned char *)_ogg_realloc(
-       _dec->pp_frame_data,frame_sz*sizeof(_dec->pp_frame_data[0]));
+      c_sz=c_w*(size_t)c_h;
       _dec->pp_frame_buf[0].width=_dec->state.info.frame_width;
       _dec->pp_frame_buf[0].height=_dec->state.info.frame_height;
       _dec->pp_frame_buf[0].stride=_dec->pp_frame_buf[0].width;
@@ -1261,7 +1289,7 @@
       _dec->pp_frame_buf[2].data=_dec->pp_frame_buf[1].data+c_sz;
       oc_ycbcr_buffer_flip(_dec->pp_frame_buf,_dec->pp_frame_buf);
     }
-    _dec->pp_frame_has_chroma=(_dec->pp_level>=OC_PP_LEVEL_DEBLOCKC);
+    _dec->pp_frame_state=1+(_dec->pp_level>=OC_PP_LEVEL_DEBLOCKC);
   }
   /*If we're not processing chroma, copy the reference frame's chroma planes.*/
   if(_dec->pp_level<OC_PP_LEVEL_DEBLOCKC){
@@ -1927,7 +1955,7 @@
   oc_dec_ctx *dec;
   if(_info==NULL||_setup==NULL)return NULL;
   dec=_ogg_malloc(sizeof(*dec));
-  if(oc_dec_init(dec,_info,_setup)<0){
+  if(dec==NULL||oc_dec_init(dec,_info,_setup)<0){
     _ogg_free(dec);
     return NULL;
   }
@@ -2274,13 +2302,18 @@
        memory, but complicate the allocation logic there.
       I don't think anyone cares about memory usage when using telemetry; it is
        not meant for embedded devices.*/
-    if(!_dec->telemetry_frame_data){
+    if(_dec->telemetry_frame_data==NULL){
       _dec->telemetry_frame_data=_ogg_malloc(
        (w*h+2*(w>>hdec)*(h>>vdec))*sizeof(*_dec->telemetry_frame_data));
+      if(_dec->telemetry_frame_data==NULL)return 0;
     }
     cs=cairo_image_surface_create(CAIRO_FORMAT_RGB24,w,h);
     /*Sadly, no YUV support in Cairo (yet); convert into the RGB buffer.*/
     data=cairo_image_surface_get_data(cs);
+    if(data==NULL){
+      cairo_surface_destroy(cs);
+      return 0;
+    }
     cstride=cairo_image_surface_get_stride(cs);
     y_row=_ycbcr[0].data;
     u_row=_ycbcr[1].data;

Modified: branches/theora-thusnelda/lib/dec/dequant.c
===================================================================
--- branches/theora-thusnelda/lib/dec/dequant.c	2009-08-04 04:47:16 UTC (rev 16408)
+++ branches/theora-thusnelda/lib/dec/dequant.c	2009-08-04 06:19:12 UTC (rev 16409)
@@ -56,6 +56,7 @@
   val=oc_pack_read(_opb,9);
   nbase_mats=(int)val+1;
   base_mats=_ogg_malloc(nbase_mats*sizeof(base_mats[0]));
+  if(base_mats==NULL)return TH_EFAULT;
   for(bmi=0;bmi<nbase_mats;bmi++){
     for(ci=0;ci<64;ci++){
       val=oc_pack_read(_opb,8);
@@ -111,8 +112,20 @@
     }
     qranges->nranges=qri;
     qranges->sizes=qrsizes=(int *)_ogg_malloc(qri*sizeof(qrsizes[0]));
+    if(qranges->sizes==NULL){
+      /*Note: The caller is responsible for cleaning up any partially
+         constructed qinfo.*/
+      _ogg_free(base_mats);
+      return TH_EFAULT;
+    }
     memcpy(qrsizes,sizes,qri*sizeof(qrsizes[0]));
     qrbms=(th_quant_base *)_ogg_malloc((qri+1)*sizeof(qrbms[0]));
+    if(qrbms==NULL){
+      /*Note: The caller is responsible for cleaning up any partially
+         constructed qinfo.*/
+      _ogg_free(base_mats);
+      return TH_EFAULT;
+    }
     qranges->base_matrices=(const th_quant_base *)qrbms;
     do{
       bmi=indices[qri];

Modified: branches/theora-thusnelda/lib/dec/huffdec.c
===================================================================
--- branches/theora-thusnelda/lib/dec/huffdec.c	2009-08-04 04:47:16 UTC (rev 16408)
+++ branches/theora-thusnelda/lib/dec/huffdec.c	2009-08-04 06:19:12 UTC (rev 16409)
@@ -16,6 +16,7 @@
  ********************************************************************/
 
 #include <stdlib.h>
+#include <string.h>
 #include <ogg/ogg.h>
 #include "huffdec.h"
 #include "decint.h"
@@ -172,46 +173,48 @@
 #define OC_HUFF_SLUSH (1)
 
 
-/*Allocates a Huffman tree node that represents a subtree of depth _nbits.
+/*Determines the size in bytes of a Huffman tree node that represents a
+   subtree of depth _nbits.
   _nbits: The depth of the subtree.
           If this is 0, the node is a leaf node.
           Otherwise 1<<_nbits pointers are allocated for children.
-  Return: The newly allocated and fully initialized Huffman tree node.*/
-static oc_huff_node *oc_huff_node_alloc(int _nbits){
-  oc_huff_node *ret;
-  size_t        size;
+  Return: The number of bytes required to store the node.*/
+static size_t oc_huff_node_size(int _nbits){
+  size_t size;
   size=_ogg_offsetof(oc_huff_node,nodes);
   if(_nbits>0)size+=sizeof(oc_huff_node *)*(1<<_nbits);
-  ret=_ogg_calloc(1,size);
+  return size;
+}
+
+static oc_huff_node *oc_huff_node_init(char **_storage,size_t _size,int _nbits){
+  oc_huff_node *ret;
+  ret=(oc_huff_node *)*_storage;
   ret->nbits=(unsigned char)_nbits;
+  (*_storage)+=_size;
   return ret;
 }
 
-/*Frees a Huffman tree node allocated with oc_huf_node_alloc.
-  _node: The node to free.
-         This may be NULL.*/
-static void oc_huff_node_free(oc_huff_node *_node){
-  _ogg_free(_node);
-}
 
-/*Frees the memory used by a Huffman tree.
-  _node: The Huffman tree to free.
-         This may be NULL.*/
-static void oc_huff_tree_free(oc_huff_node *_node){
-  if(_node==NULL)return;
+/*Determines the size in bytes of a Huffman tree.
+  _nbits: The depth of the subtree.
+          If this is 0, the node is a leaf node.
+          Otherwise storage for 1<<_nbits pointers are added for children.
+  Return: The number of bytes required to store the tree.*/
+static size_t oc_huff_tree_size(const oc_huff_node *_node){
+  size_t size;
+  size=oc_huff_node_size(_node->nbits);
   if(_node->nbits){
     int nchildren;
     int i;
-    int inext;
     nchildren=1<<_node->nbits;
-    for(i=0;i<nchildren;i=inext){
-      inext=i+(_node->nodes[i]!=NULL?1<<_node->nbits-_node->nodes[i]->depth:1);
-      oc_huff_tree_free(_node->nodes[i]);
+    for(i=0;i<nchildren;i+=1<<_node->nbits-_node->nodes[i]->depth){
+      size+=oc_huff_tree_size(_node->nodes[i]);
     }
   }
-  oc_huff_node_free(_node);
+  return size;
 }
 
+
 /*Unpacks a sub-tree from the given buffer.
   _opb:      The buffer to unpack from.
   _binodes:  The nodes to store the sub-tree in.
@@ -310,9 +313,10 @@
 /*Makes a copy of the given Huffman tree.
   _node: The Huffman tree to copy.
   Return: The copy of the Huffman tree.*/
-static oc_huff_node *oc_huff_tree_copy(const oc_huff_node *_node){
+static oc_huff_node *oc_huff_tree_copy(const oc_huff_node *_node,
+ char **_storage){
   oc_huff_node *ret;
-  ret=oc_huff_node_alloc(_node->nbits);
+  ret=oc_huff_node_init(_storage,oc_huff_node_size(_node->nbits),_node->nbits);
   ret->depth=_node->depth;
   if(_node->nbits){
     int nchildren;
@@ -320,7 +324,7 @@
     int inext;
     nchildren=1<<_node->nbits;
     for(i=0;i<nchildren;){
-      ret->nodes[i]=oc_huff_tree_copy(_node->nodes[i]);
+      ret->nodes[i]=oc_huff_tree_copy(_node->nodes[i],_storage);
       inext=i+(1<<_node->nbits-ret->nodes[i]->depth);
       while(++i<inext)ret->nodes[i]=ret->nodes[i-1];
     }
@@ -329,8 +333,35 @@
   return ret;
 }
 
-static oc_huff_node *oc_huff_tree_collapse(oc_huff_node *_binode);
+static size_t oc_huff_tree_collapse_size(oc_huff_node *_binode,int _depth){
+  size_t size;
+  int    mindepth;
+  int    depth;
+  int    loccupancy;
+  int    occupancy;
+  if(_binode->nbits!=0&&_depth>0){
+    return oc_huff_tree_collapse_size(_binode->nodes[0],_depth-1)+
+     oc_huff_tree_collapse_size(_binode->nodes[1],_depth-1);
+  }
+  depth=mindepth=oc_huff_tree_mindepth(_binode);
+  occupancy=1<<mindepth;
+  do{
+    loccupancy=occupancy;
+    occupancy=oc_huff_tree_occupancy(_binode,++depth);
+  }
+  while(occupancy>loccupancy&&occupancy>=1<<OC_MAXI(depth-OC_HUFF_SLUSH,0));
+  depth--;
+  size=oc_huff_node_size(depth);
+  if(depth>0){
+    size+=oc_huff_tree_collapse_size(_binode->nodes[0],depth-1);
+    size+=oc_huff_tree_collapse_size(_binode->nodes[1],depth-1);
+  }
+  return size;
+}
 
+static oc_huff_node *oc_huff_tree_collapse(oc_huff_node *_binode,
+ char **_storage);
+
 /*Fills the given nodes table with all the children in the sub-tree at the
    given depth.
   The nodes in the sub-tree with a depth less than that stored in the table
@@ -345,17 +376,18 @@
   _depth:  The depth of the nodes to fill the table with, relative to their
             parent.*/
 static void oc_huff_node_fill(oc_huff_node **_nodes,
- oc_huff_node *_binode,int _level,int _depth){
+ oc_huff_node *_binode,int _level,int _depth,char **_storage){
   if(_level<=0||_binode->nbits==0){
     int i;
     _binode->depth=(unsigned char)(_depth-_level);
-    _nodes[0]=oc_huff_tree_collapse(_binode);
+    _nodes[0]=oc_huff_tree_collapse(_binode,_storage);
     for(i=1;i<1<<_level;i++)_nodes[i]=_nodes[0];
   }
   else{
     _level--;
-    oc_huff_node_fill(_nodes,_binode->nodes[0],_level,_depth);
-    oc_huff_node_fill(_nodes+(1<<_level),_binode->nodes[1],_level,_depth);
+    oc_huff_node_fill(_nodes,_binode->nodes[0],_level,_depth,_storage);
+    _nodes+=1<<_level;
+    oc_huff_node_fill(_nodes,_binode->nodes[1],_level,_depth,_storage);
   }
 }
 
@@ -365,8 +397,10 @@
   _binode: The root of the sub-tree to collapse.
            _binode->nbits must be 0 or 1.
   Return: The new root of the collapsed sub-tree.*/
-static oc_huff_node *oc_huff_tree_collapse(oc_huff_node *_binode){
+static oc_huff_node *oc_huff_tree_collapse(oc_huff_node *_binode,
+ char **_storage){
   oc_huff_node *root;
+  size_t        size;
   int           mindepth;
   int           depth;
   int           loccupancy;
@@ -379,10 +413,11 @@
   }
   while(occupancy>loccupancy&&occupancy>=1<<OC_MAXI(depth-OC_HUFF_SLUSH,0));
   depth--;
-  if(depth<=1)return oc_huff_tree_copy(_binode);
-  root=oc_huff_node_alloc(depth);
+  if(depth<=1)return oc_huff_tree_copy(_binode,_storage);
+  size=oc_huff_node_size(depth);
+  root=oc_huff_node_init(_storage,size,depth);
   root->depth=_binode->depth;
-  oc_huff_node_fill(root->nodes,_binode,depth,depth);
+  oc_huff_node_fill(root->nodes,_binode,depth,depth,_storage);
   return root;
 }
 
@@ -395,12 +430,19 @@
  oc_huff_node *_nodes[TH_NHUFFMAN_TABLES]){
   int i;
   for(i=0;i<TH_NHUFFMAN_TABLES;i++){
-    oc_huff_node nodes[511];
-    int          ret;
+    oc_huff_node  nodes[511];
+    char         *storage;
+    size_t        size;
+    int           ret;
     /*Unpack the full tree into a temporary buffer.*/
     ret=oc_huff_tree_unpack(_opb,nodes,sizeof(nodes)/sizeof(*nodes));
     if(ret<0)return ret;
-    _nodes[i]=oc_huff_tree_collapse(nodes);
+    /*Figure out how big the collapsed tree will be.*/
+    size=oc_huff_tree_collapse_size(nodes,0);
+    storage=(char *)_ogg_calloc(1,size);
+    if(storage==NULL)return TH_EFAULT;
+    /*And collapse it.*/
+    _nodes[i]=oc_huff_tree_collapse(nodes,&storage);
   }
   return 0;
 }
@@ -408,17 +450,28 @@
 /*Makes a copy of the given set of Huffman trees.
   _dst: The array to store the copy in.
   _src: The array of trees to copy.*/
-void oc_huff_trees_copy(oc_huff_node *_dst[TH_NHUFFMAN_TABLES],
+int oc_huff_trees_copy(oc_huff_node *_dst[TH_NHUFFMAN_TABLES],
  const oc_huff_node *const _src[TH_NHUFFMAN_TABLES]){
   int i;
-  for(i=0;i<TH_NHUFFMAN_TABLES;i++)_dst[i]=oc_huff_tree_copy(_src[i]);
+  for(i=0;i<TH_NHUFFMAN_TABLES;i++){
+    size_t  size;
+    char   *storage;
+    size=oc_huff_tree_size(_src[i]);
+    storage=(char *)_ogg_calloc(1,size);
+    if(storage==NULL){
+      while(i-->0)_ogg_free(_dst[i]);
+      return TH_EFAULT;
+    }
+    _dst[i]=oc_huff_tree_copy(_src[i],&storage);
+  }
+  return 0;
 }
 
 /*Frees the memory used by a set of Huffman trees.
   _nodes: The array of trees to free.*/
 void oc_huff_trees_clear(oc_huff_node *_nodes[TH_NHUFFMAN_TABLES]){
   int i;
-  for(i=0;i<TH_NHUFFMAN_TABLES;i++)oc_huff_tree_free(_nodes[i]);
+  for(i=0;i<TH_NHUFFMAN_TABLES;i++)_ogg_free(_nodes[i]);
 }
 
 /*Unpacks a single token using the given Huffman tree.

Modified: branches/theora-thusnelda/lib/dec/huffdec.h
===================================================================
--- branches/theora-thusnelda/lib/dec/huffdec.h	2009-08-04 04:47:16 UTC (rev 16408)
+++ branches/theora-thusnelda/lib/dec/huffdec.h	2009-08-04 06:19:12 UTC (rev 16409)
@@ -83,7 +83,7 @@
 
 int oc_huff_trees_unpack(oc_pack_buf *_opb,
  oc_huff_node *_nodes[TH_NHUFFMAN_TABLES]);
-void oc_huff_trees_copy(oc_huff_node *_dst[TH_NHUFFMAN_TABLES],
+int oc_huff_trees_copy(oc_huff_node *_dst[TH_NHUFFMAN_TABLES],
  const oc_huff_node *const _src[TH_NHUFFMAN_TABLES]);
 void oc_huff_trees_clear(oc_huff_node *_nodes[TH_NHUFFMAN_TABLES]);
 int oc_huff_token_decode(oc_pack_buf *_opb,const oc_huff_node *_node);

Modified: branches/theora-thusnelda/lib/dec/info.c
===================================================================
--- branches/theora-thusnelda/lib/dec/info.c	2009-08-04 04:47:16 UTC (rev 16408)
+++ branches/theora-thusnelda/lib/dec/info.c	2009-08-04 06:19:12 UTC (rev 16409)
@@ -55,14 +55,21 @@
 }
 
 void th_comment_add(th_comment *_tc,char *_comment){
-  int comment_len;
-  _tc->user_comments=_ogg_realloc(_tc->user_comments,
+  char **user_comments;
+  int   *comment_lengths;
+  int    comment_len;
+  user_comments=_ogg_realloc(_tc->user_comments,
    (_tc->comments+2)*sizeof(*_tc->user_comments));
-  _tc->comment_lengths=_ogg_realloc(_tc->comment_lengths,
+  if(user_comments==NULL)return;
+  _tc->user_comments=user_comments;
+  comment_lengths=_ogg_realloc(_tc->comment_lengths,
    (_tc->comments+2)*sizeof(*_tc->comment_lengths));
+  if(comment_lengths==NULL)return;
+  _tc->comment_lengths=comment_lengths;
   comment_len=strlen(_comment);
-  _tc->comment_lengths[_tc->comments]=comment_len;
-  _tc->user_comments[_tc->comments]=_ogg_malloc(comment_len+1);
+  comment_lengths[_tc->comments]=comment_len;
+  user_comments[_tc->comments]=_ogg_malloc(comment_len+1);
+  if(user_comments[_tc->comments]==NULL)return;
   memcpy(_tc->user_comments[_tc->comments],_comment,comment_len+1);
   _tc->comments++;
   _tc->user_comments[_tc->comments]=NULL;
@@ -76,6 +83,7 @@
   val_len=strlen(_val);
   /*+2 for '=' and '\0'.*/
   comment=_ogg_malloc(tag_len+val_len+2);
+  if(comment==NULL)return;
   memcpy(comment,_tag,tag_len);
   comment[tag_len]='=';
   memcpy(comment+tag_len+1,_val,val_len+1);

Modified: branches/theora-thusnelda/lib/dec/internal.c
===================================================================
--- branches/theora-thusnelda/lib/dec/internal.c	2009-08-04 04:47:16 UTC (rev 16408)
+++ branches/theora-thusnelda/lib/dec/internal.c	2009-08-04 06:19:12 UTC (rev 16409)
@@ -181,6 +181,7 @@
   datsz=rowsz*_height;
   /*Alloc array and row pointers.*/
   ret=(char *)_ogg_malloc(datsz+colsz);
+  if(ret==NULL)return NULL;
   /*Initialize the array.*/
   if(ret!=NULL){
     size_t   i;
@@ -203,6 +204,7 @@
   datsz=rowsz*_height;
   /*Alloc array and row pointers.*/
   ret=(char *)_ogg_calloc(datsz+colsz,1);
+  if(ret==NULL)return NULL;
   /*Initialize the array.*/
   if(ret!=NULL){
     size_t   i;

Modified: branches/theora-thusnelda/lib/dec/state.c
===================================================================
--- branches/theora-thusnelda/lib/dec/state.c	2009-08-04 04:47:16 UTC (rev 16408)
+++ branches/theora-thusnelda/lib/dec/state.c	2009-08-04 06:19:12 UTC (rev 16409)
@@ -432,6 +432,11 @@
   _state->mb_maps=_ogg_calloc(nmbs,sizeof(*_state->mb_maps));
   _state->mb_modes=_ogg_calloc(nmbs,sizeof(*_state->mb_modes));
   _state->coded_fragis=_ogg_malloc(nfrags*sizeof(*_state->coded_fragis));
+  if(_state->frags==NULL||_state->frag_mvs==NULL||_state->sb_maps==NULL||
+   _state->sb_flags==NULL||_state->mb_maps==NULL||_state->mb_modes==NULL||
+   _state->coded_fragis==NULL){
+    return TH_EFAULT;
+  }
   /*Create the mapping from super blocks to fragments.*/
   for(pli=0;pli<3;pli++){
     oc_fragment_plane *fplane;
@@ -506,6 +511,13 @@
     return TH_EIMPL;
   }
   ref_frame_data=_ogg_malloc(ref_frame_data_sz);
+  frag_buf_offs=_state->frag_buf_offs=
+   _ogg_malloc(_state->nfrags*sizeof(*frag_buf_offs));
+  if(ref_frame_data==NULL||frag_buf_offs==NULL){
+    _ogg_free(frag_buf_offs);
+    _ogg_free(ref_frame_data);
+    return TH_EFAULT;
+  }
   /*Set up the width, height and stride for the image buffers.*/
   _state->ref_frame_bufs[0][0].width=info->frame_width;
   _state->ref_frame_bufs[0][0].height=info->frame_height;
@@ -539,8 +551,6 @@
   _state->ref_ystride[1]=_state->ref_ystride[2]=-chstride;
   /*Initialize the fragment buffer offsets.*/
   ref_frame_data=_state->ref_frame_data[0];
-  frag_buf_offs=_state->frag_buf_offs=
-   _ogg_malloc(_state->nfrags*sizeof(*frag_buf_offs));
   fragi=0;
   for(pli=0;pli<3;pli++){
     th_img_plane      *iplane;
@@ -640,9 +650,11 @@
   _state->frame_type=OC_UNKWN_FRAME;
   oc_state_vtable_init(_state);
   ret=oc_state_frarray_init(_state);
-  if(ret<0)return ret;
-  ret=oc_state_ref_bufs_init(_state,_nrefs);
-  if(ret<0)return ret;
+  if(ret>=0)ret=oc_state_ref_bufs_init(_state,_nrefs);
+  if(ret<0){
+    oc_state_frarray_clear(_state);
+    return ret;
+  }
   /*If the keyframe_granule_shift is out of range, use the maximum allowable
      value.*/
   if(_info->keyframe_granule_shift<0||_info->keyframe_granule_shift>31){
@@ -1085,6 +1097,10 @@
   fp=fopen(fname,"wb");
   if(fp==NULL)return TH_EFAULT;
   image=(png_bytep *)oc_malloc_2d(height,6*width,sizeof(**image));
+  if(image==NULL){
+    fclose(fp);
+    return TH_EFAULT;
+  }
   png=png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
   if(png==NULL){
     oc_free_2d(image);

Modified: branches/theora-thusnelda/lib/enc/encapiwrapper.c
===================================================================
--- branches/theora-thusnelda/lib/enc/encapiwrapper.c	2009-08-04 04:47:16 UTC (rev 16408)
+++ branches/theora-thusnelda/lib/enc/encapiwrapper.c	2009-08-04 06:19:12 UTC (rev 16409)
@@ -49,6 +49,7 @@
     This avoids having to figure out whether or not we need to free the info
      struct in either theora_info_clear() or theora_clear().*/
   apiinfo=(th_api_info *)_ogg_malloc(sizeof(*apiinfo));
+  if(apiinfo==NULL)return TH_EFAULT;
   /*Make our own copy of the info struct, since its lifetime should be
      independent of the one we were passed in.*/
   *&apiinfo->info=*_ci;
@@ -136,9 +137,15 @@
       This part works nothing like the Vorbis API, and the documentation on it
        has been wrong for some time, claiming libtheora owned the memory.*/
     buf=_ogg_malloc(_op->bytes);
-    memcpy(buf,_op->packet,_op->bytes);
-    _op->packet=buf;
-    ret=0;
+    if(buf==NULL){
+      _op->packet=NULL;
+      ret=TH_EFAULT;
+    }
+    else{
+      memcpy(buf,_op->packet,_op->bytes);
+      _op->packet=buf;
+      ret=0;
+    }
   }
   oggpack_writeclear(&opb);
   return ret;

Modified: branches/theora-thusnelda/lib/enc/encinfo.c
===================================================================
--- branches/theora-thusnelda/lib/enc/encinfo.c	2009-08-04 04:47:16 UTC (rev 16408)
+++ branches/theora-thusnelda/lib/enc/encinfo.c	2009-08-04 06:19:12 UTC (rev 16409)
@@ -21,6 +21,8 @@
  oggpack_buffer *_opb,const th_quant_info *_qinfo,
  const th_huff_code _codes[TH_NHUFFMAN_TABLES][TH_NDCT_TOKENS],
  const char *_vendor,th_comment *_tc,ogg_packet *_op){
+  unsigned char *packet;
+  int            b_o_s;
   if(_op==NULL)return TH_EFAULT;
   switch(*_packet_state){
     /*Codec info header.*/
@@ -53,7 +55,7 @@
       oggpackB_write(_opb,_state->info.pixel_fmt,2);
       /*Spare configuration bits.*/
       oggpackB_write(_opb,0,3);
-      _op->b_o_s=1;
+      b_o_s=1;
     }break;
     /*Comment header.*/
     case OC_PACKET_COMMENT_HDR:{
@@ -77,7 +79,7 @@
         }
         else oggpack_write(_opb,0,32);
       }
-      _op->b_o_s=0;
+      b_o_s=0;
     }break;
     /*Codec setup header.*/
     case OC_PACKET_SETUP_HDR:{
@@ -95,7 +97,7 @@
          are set.
         If you see, it's a good chance memory is being corrupted.*/
       if(ret<0)return ret;
-      _op->b_o_s=0;
+      b_o_s=0;
     }break;
     /*No more headers to emit.*/
     default:return 0;
@@ -106,8 +108,12 @@
     Vorbis is little better: it hands back buffers that it will free the next
      time the headers are requested, or when the encoder is cleared.
     Hopefully libogg2 will make this much cleaner.*/
-  _op->packet=oggpackB_get_buffer(_opb);
+  packet=oggpackB_get_buffer(_opb);
+  /*If there's no packet, malloc failed while writing.*/
+  if(packet==NULL)return TH_EFAULT;
+  _op->packet=packet;
   _op->bytes=oggpackB_bytes(_opb);
+  _op->b_o_s=b_o_s;
   _op->e_o_s=0;
   _op->granulepos=0;
   _op->packetno=*_packet_state+3;

Modified: branches/theora-thusnelda/lib/enc/encode.c
===================================================================
--- branches/theora-thusnelda/lib/enc/encode.c	2009-08-04 04:47:16 UTC (rev 16408)
+++ branches/theora-thusnelda/lib/enc/encode.c	2009-08-04 06:19:12 UTC (rev 16409)
@@ -1034,6 +1034,8 @@
   return 0;
 }
 
+static void oc_enc_clear(oc_enc_ctx *_enc);
+
 static int oc_enc_init(oc_enc_ctx *_enc,const th_info *_info){
   th_info   info;
   size_t    mcu_nmbs;
@@ -1081,13 +1083,28 @@
 #else
   oc_enc_vtable_init_c(_enc);
 #endif
+  _enc->keyframe_frequency_force=1<<_enc->state.info.keyframe_granule_shift;
+  _enc->state.qis[0]=_enc->state.info.quality;
+  _enc->state.nqis=1;
+  oc_rc_state_init(&_enc->rc,_enc);
+  oggpackB_writeinit(&_enc->opb);
+  if(_enc->mb_info==NULL||_enc->frag_dc==NULL||_enc->coded_mbis==NULL||
+   _enc->mcu_skip_ssd==NULL||_enc->dct_tokens[0]==NULL||
+   _enc->dct_tokens[1]==NULL||_enc->dct_tokens[2]==NULL||
+   _enc->extra_bits[0]==NULL||_enc->extra_bits[1]==NULL||
+   _enc->extra_bits[2]==NULL
+#if defined(OC_COLLECT_METRICS)
+   ||_enc->frag_satd==NULL||_enc->frag_ssd==NULL
+#endif
+   ){
+    oc_enc_clear(_enc);
+    return TH_EFAULT;
+  }
   oc_mode_scheme_chooser_init(&_enc->chooser);
   oc_enc_mb_info_init(_enc);
   memset(_enc->huff_idxs,0,sizeof(_enc->huff_idxs));
   /*Reset the packet-out state machine.*/
-  oggpackB_writeinit(&_enc->opb);
   _enc->packet_state=OC_PACKET_INFO_HDR;
-  _enc->keyframe_frequency_force=1<<_enc->state.info.keyframe_granule_shift;
   _enc->dup_count=0;
   _enc->nqueued_dups=0;
   _enc->prev_dup_count=0;
@@ -1097,13 +1114,10 @@
   _enc->coded_inter_frame=0;
   memcpy(_enc->huff_codes,TH_VP31_HUFF_CODES,sizeof(_enc->huff_codes));
   oc_enc_set_quant_params(_enc,NULL);
-  _enc->state.qis[0]=_enc->state.info.quality;
-  _enc->state.nqis=1;
-  oc_rc_state_init(&_enc->rc,_enc);
   return 0;
 }
 
-static void oc_enc_clear(th_enc_ctx *_enc){
+static void oc_enc_clear(oc_enc_ctx *_enc){
   int pli;
   oc_rc_state_clear(&_enc->rc);
 #if defined(OC_COLLECT_METRICS)
@@ -1207,7 +1221,7 @@
   oc_enc_ctx *enc;
   if(_info==NULL)return NULL;
   enc=_ogg_malloc(sizeof(*enc));
-  if(oc_enc_init(enc,_info)<0){
+  if(enc==NULL||oc_enc_init(enc,_info)<0){
     _ogg_free(enc);
     return NULL;
   }
@@ -1547,15 +1561,19 @@
   if(_enc==NULL||_op==NULL)return TH_EFAULT;
   if(_enc->packet_state==OC_PACKET_READY){
     _enc->packet_state=OC_PACKET_EMPTY;
+    if(_enc->rc.twopass!=1){
+      unsigned char *packet;
+      packet=oggpackB_get_buffer(&_enc->opb);
+      /*If there's no packet, malloc failed while writing; it's lost forever.*/
+      if(packet==NULL)return TH_EFAULT;
+      _op->packet=packet;
+      _op->bytes=oggpackB_bytes(&_enc->opb);
+    }
     /*For the first pass in 2-pass mode, don't emit any packet data.*/
-    if(_enc->rc.twopass==1){
+    else{
       _op->packet=NULL;
       _op->bytes=0;
     }
-    else{
-      _op->packet=oggpackB_get_buffer(&_enc->opb);
-      _op->bytes=oggpackB_bytes(&_enc->opb);
-    }
   }
   else if(_enc->packet_state==OC_PACKET_EMPTY){
     if(_enc->nqueued_dups>0){

Modified: branches/theora-thusnelda/lib/enc/rate.c
===================================================================
--- branches/theora-thusnelda/lib/enc/rate.c	2009-08-04 04:47:16 UTC (rev 16408)
+++ branches/theora-thusnelda/lib/enc/rate.c	2009-08-04 06:19:12 UTC (rev 16409)
@@ -327,15 +327,29 @@
     int cfm;
     int buf_delay;
     int reset_window;
-    reset_window=_enc->rc.frame_metrics==NULL;
+    reset_window=_enc->rc.frame_metrics==NULL&&buf_delay<
+     _enc->rc.frames_total[0]+_enc->rc.frames_total[1]+_enc->rc.frames_total[2];
     cfm=_enc->rc.cframe_metrics;
     buf_delay=_enc->rc.buf_delay;
-    if(cfm<buf_delay){
+    /*Only try to resize the frame metrics buffer if a) it's too small and
+       b) we were using a finite buffer, or are about to start.*/
+    if(cfm<buf_delay&&(_enc->rc.frame_metrics!=NULL||reset_window)){
       oc_frame_metrics *fm;
       int               nfm;
       int               fmh;
-      fm=_enc->rc.frame_metrics=(oc_frame_metrics *)_ogg_realloc(
-       _enc->rc.frame_metrics,buf_delay*sizeof(*_enc->rc.frame_metrics));
+      fm=(oc_frame_metrics *)_ogg_realloc(_enc->rc.frame_metrics,
+       buf_delay*sizeof(*_enc->rc.frame_metrics));
+      if(fm==NULL){
+        /*We failed to allocate a finite buffer; revert to the largest finite
+           size previously set, or to whole-file buffering if we were using
+           that.*/
+        _enc->rc.buf_delay=_enc->rc.frame_metrics!=NULL?
+         cfm:_enc->rc.frames_total[0]+_enc->rc.frames_total[1]
+         +_enc->rc.frames_total[2];
+        oc_enc_rc_resize(_enc);
+        return;
+      }
+      _enc->rc.frame_metrics=fm;
       _enc->rc.cframe_metrics=buf_delay;
       /*Re-organize the circular buffer.*/
       fmh=_enc->rc.frame_metrics_head;



More information about the commits mailing list