Bug Summary

File:root/firefox-clang/other-licenses/bsdiff/bsdiff.c
Warning:line 400, column 6
The 1st argument to 'lseek' is -1 but should be >= 0

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O3 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name bsdiff.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/other-licenses/bsdiff -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/other-licenses/bsdiff -resource-dir /usr/lib/llvm-23/lib/clang/23 -D XP_UNIX -D DEBUG=1 -I /root/firefox-clang/other-licenses/bsdiff -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/other-licenses/bsdiff -I /root/firefox-clang/toolkit/mozapps/update/updater -I /root/firefox-clang/toolkit/mozapps/update/updater/bspatch -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-10-17-231001-351276-1 -x c /root/firefox-clang/other-licenses/bsdiff/bsdiff.c
1/* vim:set ts=8 sw=8 sts=8 noet: */
2/*
3 bsdiff.c -- Binary patch generator.
4
5 Copyright 2003 Colin Percival
6
7 For the terms under which this work may be distributed, please see
8 the adjoining file "LICENSE".
9
10 ChangeLog:
11 2005-05-05 - Use the modified header struct from bspatch.h; use 32-bit
12 values throughout.
13 --Benjamin Smedberg <benjamin@smedbergs.us>
14 2005-05-18 - Use the same CRC algorithm as bzip2, and leverage the CRC table
15 provided by libbz2.
16 --Darin Fisher <darin@meer.net>
17*/
18
19#include "bspatch.h"
20
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <fcntl.h>
25#include <stdarg.h>
26#ifdef XP_WIN
27#include <io.h>
28#include <winsock2.h>
29#define open _open
30#define close _close
31#define read _read
32#define lseek _lseek
33#define write _write
34#else
35#include <unistd.h>
36#include <arpa/inet.h>
37#define _O_BINARY0 0
38#endif
39
40#include "crctable.h"
41
42#undef MIN
43#define MIN(x,y)(((x)<(y)) ? (x) : (y)) (((x)<(y)) ? (x) : (y))
44
45/* An exact match at least this long ends the byte-by-byte scan in main().
46 * Otherwise, when the old file holds a long run twice and the copy being
47 * followed is only 1-10 bytes worse than the other, the scan calls search()
48 * once per byte of the run, which is quadratic in the run's length.
49 */
50#define LONG_MATCH_LEN65536 65536
51
52/*---------------------------------------------------------------------------*/
53
54static unsigned int
55crc32(const unsigned char *buf, unsigned int len)
56{
57 unsigned int crc = 0xffffffffL;
58
59 const unsigned char *end = buf + len;
60 for (; buf != end; ++buf)
61 crc = (crc << 8) ^ BZ2_crc32Table[(crc >> 24) ^ *buf];
62
63 crc = ~crc;
64 return crc;
65}
66
67/*---------------------------------------------------------------------------*/
68
69static void
70reporterr(int e, const char *fmt, ...)
71{
72 if (fmt) {
73 va_list args;
74 va_start(args, fmt)__builtin_va_start(args, fmt);
75 vfprintf(stderrstderr, fmt, args);
76 va_end(args)__builtin_va_end(args);
77 }
78
79 exit(e);
80}
81
82static void
83split(int32_t *I,int32_t *V,int32_t start,int32_t len,int32_t h)
84{
85 int32_t i,j,k,x,tmp,jj,kk;
86
87 if(len<16) {
88 for(k=start;k<start+len;k+=j) {
89 j=1;x=V[I[k]+h];
90 for(i=1;k+i<start+len;i++) {
91 if(V[I[k+i]+h]<x) {
92 x=V[I[k+i]+h];
93 j=0;
94 };
95 if(V[I[k+i]+h]==x) {
96 tmp=I[k+j];I[k+j]=I[k+i];I[k+i]=tmp;
97 j++;
98 };
99 };
100 for(i=0;i<j;i++) V[I[k+i]]=k+j-1;
101 if(j==1) I[k]=-1;
102 };
103 return;
104 };
105
106 x=V[I[start+len/2]+h];
107 jj=0;kk=0;
108 for(i=start;i<start+len;i++) {
109 if(V[I[i]+h]<x) jj++;
110 if(V[I[i]+h]==x) kk++;
111 };
112 jj+=start;kk+=jj;
113
114 i=start;j=0;k=0;
115 while(i<jj) {
116 if(V[I[i]+h]<x) {
117 i++;
118 } else if(V[I[i]+h]==x) {
119 tmp=I[i];I[i]=I[jj+j];I[jj+j]=tmp;
120 j++;
121 } else {
122 tmp=I[i];I[i]=I[kk+k];I[kk+k]=tmp;
123 k++;
124 };
125 };
126
127 while(jj+j<kk) {
128 if(V[I[jj+j]+h]==x) {
129 j++;
130 } else {
131 tmp=I[jj+j];I[jj+j]=I[kk+k];I[kk+k]=tmp;
132 k++;
133 };
134 };
135
136 if(jj>start) split(I,V,start,jj-start,h);
137
138 for(i=0;i<kk-jj;i++) V[I[jj+i]]=kk-1;
139 if(jj==kk-1) I[jj]=-1;
140
141 if(start+len>kk) split(I,V,kk,start+len-kk,h);
142}
143
144static void
145qsufsort(int32_t *I,int32_t *V,unsigned char *old,int32_t oldsize)
146{
147 int32_t buckets[256];
148 int32_t i,h,len;
149
150 for(i=0;i<256;i++) buckets[i]=0;
151 for(i=0;i<oldsize;i++) buckets[old[i]]++;
152 for(i=1;i<256;i++) buckets[i]+=buckets[i-1];
153 for(i=255;i>0;i--) buckets[i]=buckets[i-1];
154 buckets[0]=0;
155
156 for(i=0;i<oldsize;i++) I[++buckets[old[i]]]=i;
157 I[0]=oldsize;
158 for(i=0;i<oldsize;i++) V[i]=buckets[old[i]];
159 V[oldsize]=0;
160 for(i=1;i<256;i++) if(buckets[i]==buckets[i-1]+1) I[buckets[i]]=-1;
161 I[0]=-1;
162
163 for(h=1;I[0]!=-(oldsize+1);h+=h) {
164 len=0;
165 for(i=0;i<oldsize+1;) {
166 if(I[i]<0) {
167 len-=I[i];
168 i-=I[i];
169 } else {
170 if(len) I[i-len]=-len;
171 len=V[I[i]]+1-i;
172 split(I,V,i,len,h);
173 i+=len;
174 len=0;
175 };
176 };
177 if(len) I[i-len]=-len;
178 };
179
180 for(i=0;i<oldsize+1;i++) I[V[i]]=i;
181}
182
183static int32_t
184matchlen(unsigned char *old,int32_t oldsize,unsigned char *newbuf,int32_t newsize)
185{
186 int32_t i;
187
188 for(i=0;(i<oldsize)&&(i<newsize);i++)
189 if(old[i]!=newbuf[i]) break;
190
191 return i;
192}
193
194static int32_t
195search(int32_t *I,unsigned char *old,int32_t oldsize,
196 unsigned char *newbuf,int32_t newsize,int32_t st,int32_t en,int32_t *pos)
197{
198 int32_t x,y;
199
200 if(en-st<2) {
201 x=matchlen(old+I[st],oldsize-I[st],newbuf,newsize);
202 y=matchlen(old+I[en],oldsize-I[en],newbuf,newsize);
203
204 if(x>y) {
205 *pos=I[st];
206 return x;
207 } else {
208 *pos=I[en];
209 return y;
210 }
211 };
212
213 x=st+(en-st)/2;
214 if(memcmp(old+I[x],newbuf,MIN(oldsize-I[x],newsize)(((oldsize-I[x])<(newsize)) ? (oldsize-I[x]) : (newsize)))<0) {
215 return search(I,old,oldsize,newbuf,newsize,x,en,pos);
216 } else {
217 return search(I,old,oldsize,newbuf,newsize,st,x,pos);
218 };
219}
220
221int main(int argc,char *argv[])
222{
223 int fd;
224 unsigned char *old,*newbuf;
225 int32_t oldsize,newsize;
226 int32_t *I,*V;
227
228 int32_t scan,pos,len;
229 int32_t lastscan,lastpos,lastoffset;
230 int32_t oldscore,scsc;
231
232 int32_t s,Sf,lenf,Sb,lenb;
233 int32_t overlap,Ss,lens;
234 int32_t i;
235
236 int32_t dblen,eblen;
237 unsigned char *db,*eb;
238
239 unsigned int scrc;
240
241 MBSPatchHeader header = {
242 {'M','B','D','I','F','F','1','0'},
243 0, 0, 0, 0, 0, 0
244 };
245
246 uint32_t numtriples;
247
248 if(argc!=4)
1
Assuming 'argc' is not equal to 4
2
Taking true branch
249 reporterr(1,"usage: %s <oldfile> <newfile> <patchfile>\n",argv[0]);
250
251 /* Allocate oldsize+1 bytes instead of oldsize bytes to ensure
252 that we never try to malloc(0) and get a NULL pointer */
253 if(((fd=open(argv[1],O_RDONLY00|_O_BINARY0,0))<0) ||
6
Taking false branch
254 ((oldsize=lseek(fd,0,SEEK_END2))==-1) ||
255 ((old=(unsigned char*) malloc(oldsize+1))==NULL((void*)0)) ||
3
Assuming the condition is false
256 (lseek(fd,0,SEEK_SET0)!=0) ||
4
Assuming the condition is false
257 (read(fd,old,oldsize)!=oldsize) ||
5
Assuming the condition is false
258 (close(fd)==-1))
259 reporterr(1,"%s\n",argv[1]);
260
261 scrc = crc32(old, oldsize);
262
263 if(((I=(int32_t*) malloc((oldsize+1)*sizeof(int32_t)))==NULL((void*)0)) ||
7
Assuming the condition is false
9
Taking false branch
264 ((V=(int32_t*) malloc((oldsize+1)*sizeof(int32_t)))==NULL((void*)0)))
8
Assuming the condition is false
265 reporterr(1,NULL((void*)0));
266
267 qsufsort(I,V,old,oldsize);
268
269 free(V);
270
271 /* Allocate newsize+1 bytes instead of newsize bytes to ensure
272 that we never try to malloc(0) and get a NULL pointer */
273 if(((fd=open(argv[2],O_RDONLY00|_O_BINARY0,0))<0) ||
274 ((newsize=lseek(fd,0,SEEK_END2))==-1) ||
275 ((newbuf=(unsigned char*) malloc(newsize+1))==NULL((void*)0)) ||
276 (lseek(fd,0,SEEK_SET0)!=0) ||
277 (read(fd,newbuf,newsize)!=newsize) ||
278 (close(fd)==-1)) reporterr(1,"%s\n",argv[2]);
279
280 if(((db=(unsigned char*) malloc(newsize+1))==NULL((void*)0)) ||
10
Assuming the condition is false
12
Taking false branch
281 ((eb=(unsigned char*) malloc(newsize+1))==NULL((void*)0)))
11
Assuming the condition is false
282 reporterr(1,NULL((void*)0));
283
284 dblen=0;
285 eblen=0;
286
287 if((fd=open(argv[3],O_CREAT0100|O_TRUNC01000|O_WRONLY01|_O_BINARY0,0666))<0)
13
Assuming that 'open' fails
14
Value assigned to 'fd'
15
Taking true branch
288 reporterr(1,"%s\n",argv[3]);
289
290 /* start writing here */
291
292 /* We don't know the lengths yet, so we will write the header again
293 at the end */
294
295 if(write(fd,&header,sizeof(MBSPatchHeader))!=sizeof(MBSPatchHeader))
16
Assuming the condition is false
17
Taking false branch
296 reporterr(1,"%s\n",argv[3]);
297
298 scan=0;len=0;
299 lastscan=0;lastpos=0;lastoffset=0;
300 numtriples = 0;
301 while(scan<newsize) {
18
Loop condition is false. Execution continues on line 387
302 oldscore=0;
303
304 for(scsc=scan+=len;scan<newsize;scan++) {
305 len=search(I,old,oldsize,newbuf+scan,newsize-scan,
306 0,oldsize,&pos);
307
308 for(;scsc<scan+len;scsc++)
309 if((scsc+lastoffset<oldsize) &&
310 (old[scsc+lastoffset] == newbuf[scsc]))
311 oldscore++;
312
313 if(((len==oldscore) && (len!=0)) ||
314 (len>oldscore+10) || (len>=LONG_MATCH_LEN65536)) break;
315
316 if((scan+lastoffset<oldsize) &&
317 (old[scan+lastoffset] == newbuf[scan]))
318 oldscore--;
319 };
320
321 if((len!=oldscore) || (scan==newsize)) {
322 MBSPatchTriple triple;
323
324 s=0;Sf=0;lenf=0;
325 for(i=0;(lastscan+i<scan)&&(lastpos+i<oldsize);) {
326 if(old[lastpos+i]==newbuf[lastscan+i]) s++;
327 i++;
328 if(s*3-i*2>Sf*3-lenf*2) { Sf=s; lenf=i; };
329 };
330
331 lenb=0;
332 if(scan<newsize) {
333 s=0;Sb=0;
334 for(i=1;(scan>=lastscan+i)&&(pos>=i);i++) {
335 if(old[pos-i]==newbuf[scan-i]) s++;
336 if(s*3-i*2>Sb*3-lenb*2) { Sb=s; lenb=i; };
337 };
338 };
339
340 if(lastscan+lenf>scan-lenb) {
341 overlap=(lastscan+lenf)-(scan-lenb);
342 s=0;Ss=0;lens=0;
343 for(i=0;i<overlap;i++) {
344 if(newbuf[lastscan+lenf-overlap+i]==
345 old[lastpos+lenf-overlap+i]) s++;
346 if(newbuf[scan-lenb+i]==
347 old[pos-lenb+i]) s--;
348 if(s>Ss) { Ss=s; lens=i+1; };
349 };
350
351 lenf+=lens-overlap;
352 lenb-=lens;
353 };
354
355 for(i=0;i<lenf;i++)
356 db[dblen+i]=newbuf[lastscan+i]-old[lastpos+i];
357 for(i=0;i<(scan-lenb)-(lastscan+lenf);i++)
358 eb[eblen+i]=newbuf[lastscan+lenf+i];
359
360 dblen+=lenf;
361 eblen+=(scan-lenb)-(lastscan+lenf);
362
363 triple.x = htonl(lenf)__bswap_32 (lenf);
364 triple.y = htonl((scan-lenb)-(lastscan+lenf))__bswap_32 ((scan-lenb)-(lastscan+lenf));
365 triple.z = htonl((pos-lenb)-(lastpos+lenf))__bswap_32 ((pos-lenb)-(lastpos+lenf));
366 if (write(fd,&triple,sizeof(triple)) != sizeof(triple))
367 reporterr(1,NULL((void*)0));
368
369#ifdef DEBUG_bsmedberg
370 printf("Writing a block:\n"
371 " X: %u\n"
372 " Y: %u\n"
373 " Z: %i\n",
374 (uint32_t) lenf,
375 (uint32_t) ((scan-lenb)-(lastscan+lenf)),
376 (uint32_t) ((pos-lenb)-(lastpos+lenf)));
377#endif
378
379 ++numtriples;
380
381 lastscan=scan-lenb;
382 lastpos=pos-lenb;
383 lastoffset=pos-scan;
384 };
385 };
386
387 if(write(fd,db,dblen)!=dblen)
19
Assuming the condition is false
20
Taking false branch
388 reporterr(1,NULL((void*)0));
389
390 if(write(fd,eb,eblen)!=eblen)
21
Assuming the condition is false
22
Taking false branch
391 reporterr(1,NULL((void*)0));
392
393 header.slen = htonl(oldsize)__bswap_32 (oldsize);
394 header.scrc32 = htonl(scrc)__bswap_32 (scrc);
395 header.dlen = htonl(newsize)__bswap_32 (newsize);
396 header.cblen = htonl(numtriples * sizeof(MBSPatchTriple))__bswap_32 (numtriples * sizeof(MBSPatchTriple));
397 header.difflen = htonl(dblen)__bswap_32 (dblen);
398 header.extralen = htonl(eblen)__bswap_32 (eblen);
399
400 if (lseek(fd,0,SEEK_SET0) == -1 ||
23
The 1st argument to 'lseek' is -1 but should be >= 0
401 write(fd,&header,sizeof(header)) != sizeof(header) ||
402 close(fd) == -1)
403 reporterr(1,NULL((void*)0));
404
405 free(db);
406 free(eb);
407 free(I);
408 free(old);
409 free(newbuf);
410
411 return 0;
412}
413