[PATCH] 2.2.0 NTFS driver memory leaks & checking

Steve Dodd (dirk@loth.demon.co.uk)
Wed, 27 Jan 1999 00:35:37 +0000


--k1lZvvs/B4yU6o8G
Content-Type: text/plain; charset=us-ascii

Hi all,

This is a patch against 2.2.0 for the NTFS driver which

- fixes a small memory leak, and
- checks for kmalloc() failure every where it is used and
copes appropriately

This should stop the out of memory Oops, though it doesn't address the
obscene memory usage issue - I'm going to play with vmalloc() rather
than kmalloc() and see what happens.

S.

-- 
%DCL-MEM-BAD, bad memory
VMS-F-PDGERS, pudding between the ears

--k1lZvvs/B4yU6o8G Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="ntfs-mem-fix.patch"

Only in linux/fs/ntfs/: .attr.o.flags Only in linux/fs/ntfs/: .dir.o.flags Only in linux/fs/ntfs/: .fs.o.flags Only in linux/fs/ntfs/: .inode.o.flags Only in linux/fs/ntfs/: .ntfs.o.flags Only in linux/fs/ntfs/: .super.o.flags Only in linux/fs/ntfs/: .support.o.flags Only in linux/fs/ntfs/: .sysctl.o.flags Only in linux/fs/ntfs/: .util.o.flags diff -ur vanilla/fs/ntfs/attr.c linux/fs/ntfs/attr.c --- vanilla/fs/ntfs/attr.c Sun Jan 3 17:23:02 1999 +++ linux/fs/ntfs/attr.c Wed Jan 27 00:28:49 1999 @@ -19,7 +19,8 @@ /* Look if an attribute already exists in the inode, and if not, create it */ static int -new_attr(ntfs_inode *ino,int type,void *name,int namelen,int *pos, int *found) +new_attr(ntfs_inode *ino,int type,void *name,int namelen,int *pos, int *found, + int do_search ) { int do_insert=0; int i; @@ -28,15 +29,17 @@ { int n=min(namelen,ino->attrs[i].namelen); int s=ntfs_uni_strncmp(ino->attrs[i].name,name,n); - /* - * We assume that each attribute can be uniquely - * identified by inode - * number, attribute type and attribute name. - */ - if(ino->attrs[i].type==type && ino->attrs[i].namelen==namelen && !s){ - *found=1; - *pos=i; - return 0; + if( do_search ) { + /* + * We assume that each attribute can be uniquely + * identified by inode + * number, attribute type and attribute name. + */ + if(ino->attrs[i].type==type && ino->attrs[i].namelen==namelen && !s){ + *found=1; + *pos=i; + return 0; + } } /* attributes are ordered by type, then by name */ if(ino->attrs[i].type>type || (ino->attrs[i].type==type && s==1)){ @@ -48,17 +51,21 @@ /* re-allocate space */ if(ino->attr_count % 8 ==0) { - ntfs_attribute* old=ino->attrs; - ino->attrs = (ntfs_attribute*)ntfs_malloc((ino->attr_count+8)* + ntfs_attribute* new; + new = (ntfs_attribute*)ntfs_malloc((ino->attr_count+8)* sizeof(ntfs_attribute)); - if(old){ - ntfs_memcpy(ino->attrs,old,ino->attr_count*sizeof(ntfs_attribute)); - ntfs_free(old); + if( !new ) + return ENOMEM; + if( ino->attrs ) { + ntfs_memcpy( new, ino->attrs, ino->attr_count*sizeof(ntfs_attribute) ); + ntfs_free( ino->attrs ); } + ino->attrs = new; } if(do_insert) ntfs_memmove(ino->attrs+i+1,ino->attrs+i,(ino->attr_count-i)* sizeof(ntfs_attribute)); + ino->attr_count++; ino->attrs[i].type=type; ino->attrs[i].namelen=namelen; @@ -86,14 +93,16 @@ { /* (re-)allocate space if necessary */ if(attr->d.r.len % 8 == 0) { - ntfs_runlist* old; - old=attr->d.r.runlist; - attr->d.r.runlist=ntfs_malloc((attr->d.r.len+8)*sizeof(ntfs_runlist)); - if(old) { - ntfs_memcpy(attr->d.r.runlist,old,attr->d.r.len + ntfs_runlist* new; + new = ntfs_malloc((attr->d.r.len+8)*sizeof(ntfs_runlist)); + if( !new ) + return; + if( attr->d.r.runlist ) { + ntfs_memcpy(new, attr->d.r.runlist, attr->d.r.len *sizeof(ntfs_runlist)); - ntfs_free(old); + ntfs_free( attr->d.r.runlist ); } + attr->d.r.runlist = new; } if(attr->d.r.len>cnum) ntfs_memmove(attr->d.r.runlist+cnum+1,attr->d.r.runlist+cnum, @@ -208,8 +217,10 @@ v=attr->d.data; if(newsize){ attr->d.data=ntfs_malloc(newsize); - if(!attr->d.data) + if(!attr->d.data) { + ntfs_free(v); return ENOMEM; + } if(newsize>oldsize) ntfs_bzero((char*)attr->d.data+oldsize, newsize-oldsize); @@ -279,12 +290,20 @@ if(aname){ namelen=strlen(aname); name=ntfs_malloc(2*namelen); + if( !name ) + return ENOMEM; ntfs_ascii2uni(name,aname,namelen); }else{ name=0; namelen=0; } - new_attr(ino,anum,name,namelen,&i,&found); + + error = new_attr(ino,anum,name,namelen,&i,&found,1); + if( error ) { + ntfs_free( name ); + return error; + } + if(found){ ntfs_free(name); return EEXIST; @@ -309,6 +328,10 @@ }else attr->indexed=0; attr->d.data=ntfs_malloc(dsize); + + if( !attr->d.data ) + return ENOMEM; + ntfs_memcpy(attr->d.data,data,dsize); return 0; } @@ -366,6 +389,7 @@ int namelen; void *data; ntfs_attribute *attr; + int error; type = NTFS_GETU32(attrdata); namelen = NTFS_GETU8(attrdata+9); @@ -376,15 +400,30 @@ { /* 1 Unicode character fits in 2 bytes */ name=ntfs_malloc(2*namelen); + if( !name ) + return ENOMEM; + ntfs_memcpy(name,attrdata+NTFS_GETU16(attrdata+10),2*namelen); } - new_attr(ino,type,name,namelen,&i,&found); + + error = new_attr(ino,type,name,namelen,&i,&found,1); + if( error ) { + if( name ) ntfs_free( name ); + return error; + } + /* We can have in one inode two attributes with type 0x00000030 (File Name) and without name */ if(found && /*FIXME*/type!=ino->vol->at_file_name) { ntfs_process_runs(ino,ino->attrs+i,attrdata); return 0; + } else if( found ) { + /* Don't understand the above, but I know it leaks memory below + as it overwrites a found entry without freeing it. So here we + call new_attr again but this time ask it to always allocate a + new entry */ + new_attr(ino,type,name,namelen,&i,&found,0); } attr=ino->attrs+i; attr->resident=NTFS_GETU8(attrdata+8)==0; @@ -395,6 +434,8 @@ attr->size=NTFS_GETU16(attrdata+0x10); data=attrdata+NTFS_GETU16(attrdata+0x14); attr->d.data = (void*)ntfs_malloc(attr->size); + if( !attr->d.data ) + return ENOMEM; ntfs_memcpy(attr->d.data,data,attr->size); attr->indexed=NTFS_GETU16(attrdata+0x16); }else{ Only in linux/fs/ntfs/: attr.c.orig Only in linux/fs/ntfs/: attr.c.rej Only in linux/fs/ntfs/: attr.o diff -ur vanilla/fs/ntfs/dir.c linux/fs/ntfs/dir.c --- vanilla/fs/ntfs/dir.c Sun Jan 3 17:23:02 1999 +++ linux/fs/ntfs/dir.c Tue Jan 26 23:44:58 1999 @@ -166,6 +166,8 @@ int nr_fix = s1/vol->blocksize+1; int hsize; char *record=ntfs_malloc(s1); + if( !record ) + return ENOMEM; ntfs_bzero(record,s1); /* magic */ ntfs_memcpy(record,"INDX",4); @@ -395,8 +397,9 @@ goto out; } index = ntfs_malloc(ino->vol->index_recordsize); - if(!index) - goto out; + if(!index) { + error = ENOMEM; goto out; + } walk.dir = ino; walk.block = -1; walk.result = walk.new_entry = 0; @@ -485,6 +488,9 @@ int oldblock; ntfs_io io; + if( !record ) + return ENOMEM; + io.fn_put=ntfs_put; io.param=record; io.size=length; @@ -683,6 +689,9 @@ char *root=ntfs_malloc(length); ntfs_io io; + if( !root ) + return ENOMEM; + io.fn_put=ntfs_put; io.param=root; io.size=length; @@ -747,6 +756,8 @@ /* are we still in the index root */ if(*p_high==0){ buf=ntfs_malloc(length=vol->mft_recordsize); + if( !buf ) + return ENOMEM; io.fn_put=ntfs_put; io.param=buf; io.size=length; @@ -762,6 +773,8 @@ }else{ /* we are in an index record */ length=ino->u.index.recordsize; buf=ntfs_malloc(length); + if( !buf ) + return ENOMEM; io.fn_put=ntfs_put; io.param=buf; io.size=length; @@ -821,6 +834,9 @@ return 0; } buf=ntfs_malloc(length=attr->size); + if( !buf ) + return ENOMEM; + io.param=buf; io.size=length; error=ntfs_read_attr(ino,vol->at_bitmap,I30,0,&io); Only in linux/fs/ntfs/: dir.o diff -ur vanilla/fs/ntfs/fs.c linux/fs/ntfs/fs.c --- vanilla/fs/ntfs/fs.c Sun Jan 3 17:23:02 1999 +++ linux/fs/ntfs/fs.c Wed Jan 27 00:14:12 1999 @@ -387,6 +387,8 @@ if(error) return error; item=ntfs_malloc(ITEM_SIZE); + if( !item ) + return ENOMEM; /* ntfs_getdir will place the directory entry into item, and the first long long is the MFT record number */ walk.type=BY_NAME; @@ -707,6 +709,7 @@ #ifdef NTFS_IN_LINUX_KERNEL ino=&inode->u.ntfs_i; #else + /* FIXME: check for ntfs_malloc failure */ ino=(ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode)); inode->u.generic_ip=ino; #endif @@ -816,6 +819,7 @@ struct statfs fs; struct inode *mft; ntfs_volume *vol; + int error; ntfs_debug(DEBUG_OTHER, "ntfs_statfs\n"); vol=NTFS_SB2VOL(sb); @@ -823,7 +827,9 @@ fs.f_type=NTFS_SUPER_MAGIC; fs.f_bsize=vol->clustersize; - fs.f_blocks=ntfs_get_volumesize(NTFS_SB2VOL(sb)); + error = ntfs_get_volumesize( NTFS_SB2VOL( sb ), &fs.f_blocks ); + if( error ) + return error; fs.f_bfree=ntfs_get_free_cluster_count(vol->bitmap); fs.f_bavail=fs.f_bfree; Only in linux/fs/ntfs/: fs.o diff -ur vanilla/fs/ntfs/inode.c linux/fs/ntfs/inode.c --- vanilla/fs/ntfs/inode.c Sun Jan 3 17:23:02 1999 +++ linux/fs/ntfs/inode.c Tue Jan 26 23:50:46 1999 @@ -165,13 +165,16 @@ /* (re-)allocate space if necessary */ if(ino->record_count % 8==0) { - int *old=ino->records; - ino->records=ntfs_malloc((ino->record_count+8)*sizeof(int)); - if(old) { + int *new; + new = ntfs_malloc((ino->record_count+8)*sizeof(int)); + if( !new ) + return; + if( ino->records ) { for(i=0;i<ino->record_count;i++) - ino->records[i]=old[i]; - ntfs_free(old); + new[i] = ino->records[i]; + ntfs_free( ino->records ); } + ino->records = new; } ino->records[ino->record_count]=mftno; ino->record_count++; @@ -179,8 +182,10 @@ do{ type=NTFS_GETU32(it); len=NTFS_GETU32(it+4); - if(type!=-1) + if(type!=-1) { + /* FIXME: check ntfs_insert_attribute for failure (e.g. no mem)? */ ntfs_insert_attribute(ino,it); + } it+=len; }while(type!=-1); /* attribute list ends with type -1 */ } @@ -195,6 +200,8 @@ int last_mft=-1; int len=*plen; mft=ntfs_malloc(ino->vol->mft_recordsize); + if( !mft ) + return ENOMEM; while(len>8) { l=NTFS_GETU16(alist+4); @@ -239,6 +246,8 @@ return; } buf=ntfs_malloc(1024); + if( !buf ) + return; delta=0; for(offset=0;datasize;datasize-=len) { @@ -271,6 +280,8 @@ ino->i_number=inum; ino->vol=vol; ino->attr=buf=ntfs_malloc(vol->mft_recordsize); + if( !buf ) + return ENOMEM; error=ntfs_read_mft_record(vol,inum,ino->attr); if(error){ ntfs_debug(DEBUG_OTHER, "init inode: %x failed\n",inum); @@ -1108,6 +1119,8 @@ /* work out the size */ size = 0x42 + 2 * length; data = ntfs_malloc(size); + if( !data ) + return ENOMEM; ntfs_bzero(data,size); /* search for a position */ @@ -1238,10 +1251,17 @@ result->sequence_number=NTFS_GETU16(buffer)+1; result->vol=vol; result->attr=ntfs_malloc(vol->mft_recordsize); + if( !result->attr ) + return ENOMEM; result->attr_count=0; result->attrs=0; result->record_count=1; result->records=ntfs_malloc(8*sizeof(int)); + if( !result->records ) { + ntfs_free( result->attr ); + result->attr = NULL; + return ENOMEM; + } result->records[0]=result->i_number; error=add_mft_header(result); if(error) Only in linux/fs/ntfs/: inode.o Only in linux/fs/ntfs/: ntfs.o diff -ur vanilla/fs/ntfs/super.c linux/fs/ntfs/super.c --- vanilla/fs/ntfs/super.c Sun Jan 3 17:23:02 1999 +++ linux/fs/ntfs/super.c Wed Jan 27 00:05:32 1999 @@ -113,6 +113,8 @@ ntfs_io io; #define UPCASE_LENGTH 256 upcase->vol->upcase = ntfs_malloc(2*UPCASE_LENGTH); + if( !upcase->vol->upcase ) + return; upcase->vol->upcase_length = UPCASE_LENGTH; io.fn_put=ntfs_put; io.fn_get=0; @@ -246,11 +248,22 @@ return 0; } -int ntfs_get_volumesize(ntfs_volume *vol) +/* + * Writes the volume size into vol_size. Returns 0 if successful + * or error. + */ +int ntfs_get_volumesize(ntfs_volume *vol, long *vol_size ) { ntfs_io io; - char *cluster0=ntfs_malloc(vol->clustersize); ntfs_u64 size; + char *cluster0; + + if( !vol_size ) + return EFAULT; + + cluster0=ntfs_malloc(vol->clustersize); + if( !cluster0 ) + return ENOMEM; io.fn_put=ntfs_put; io.fn_get=ntfs_get; @@ -262,7 +275,8 @@ ntfs_free(cluster0); /* FIXME: more than 2**32 cluster */ /* FIXME: gcc will emit udivdi3 if we don't truncate it */ - return ((unsigned int)size)/vol->clusterfactor; + *vol_size = ((unsigned long)size)/vol->clusterfactor; + return 0; } static int nc[16]={4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0}; @@ -460,6 +474,8 @@ int start; bits=ntfs_malloc(2048); + if( !bits ) + return ENOMEM; io.fn_put=ntfs_put; io.fn_get=ntfs_get; io.param=bits; diff -ur vanilla/fs/ntfs/super.h linux/fs/ntfs/super.h --- vanilla/fs/ntfs/super.h Sun Jan 3 17:23:02 1999 +++ linux/fs/ntfs/super.h Wed Jan 27 00:12:18 1999 @@ -10,7 +10,7 @@ #define ALLOC_REQUIRE_SIZE 2 int ntfs_get_free_cluster_count(ntfs_inode *bitmap); -int ntfs_get_volumesize(ntfs_volume *vol); +int ntfs_get_volumesize(ntfs_volume *vol, long *vol_size ); int ntfs_init_volume(ntfs_volume *vol,char *boot); int ntfs_load_special_files(ntfs_volume *vol); int ntfs_release_volume(ntfs_volume *vol); Only in linux/fs/ntfs/: super.o diff -ur vanilla/fs/ntfs/support.c linux/fs/ntfs/support.c --- vanilla/fs/ntfs/support.c Sun Jan 3 17:23:02 1999 +++ linux/fs/ntfs/support.c Wed Jan 27 00:07:00 1999 @@ -246,6 +246,10 @@ if(!(vol->nct & nct_uni_xlate))goto inval; /* realloc */ buf=ntfs_malloc(*out_len+3); + if( !buf ) { + ntfs_free( result ); + return ENOMEM; + } memcpy(buf,result,o); ntfs_free(result); result=buf; Only in linux/fs/ntfs/: support.o Only in linux/fs/ntfs/: sysctl.o Only in linux/fs/ntfs/: util.o

--k1lZvvs/B4yU6o8G--

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/