Bug Summary

File:src/usr.bin/cvs/history.c
Warning:line 187, column 3
Argument to free() is the address of a global variable, which is not memory allocated by malloc()

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name history.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -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 -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/cvs/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.bin/cvs -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/cvs/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/cvs/history.c
1/* $OpenBSD: history.c,v 1.45 2017/07/20 13:39:11 okan Exp $ */
2/*
3 * Copyright (c) 2007 Joris Vink <joris@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <sys/stat.h>
19
20#include <ctype.h>
21#include <errno(*__errno()).h>
22#include <fcntl.h>
23#include <pwd.h>
24#include <stdlib.h>
25#include <string.h>
26#include <time.h>
27#include <unistd.h>
28
29#include "cvs.h"
30#include "remote.h"
31
32void cvs_history_local(struct cvs_file *);
33
34static void history_compress(char *, const char *);
35
36struct cvs_cmd cvs_cmd_history = {
37 CVS_OP_HISTORY10, CVS_USE_WDIR0x01, "history",
38 { "hi", "his" }, /* omghi2you */
39 "Display history of actions done in the base repository",
40 "[-ac]",
41 "ac",
42 NULL((void *)0),
43 cvs_history
44};
45
46/* keep in sync with the defines for history stuff in cvs.h */
47const char historytab[] = {
48 'T',
49 'O',
50 'E',
51 'F',
52 'W',
53 'U',
54 'G',
55 'C',
56 'M',
57 'A',
58 'R',
59 '\0'
60};
61
62#define HISTORY_ALL_USERS0x01 0x01
63#define HISTORY_DISPLAY_ARCHIVED0x02 0x02
64
65void
66cvs_history_add(int type, struct cvs_file *cf, const char *argument)
67{
68 BUF *buf;
69 FILE *fp;
70 RCSNUM *hrev;
71 size_t len;
72 int fd;
73 char *cwd, *p, *rev;
74 char revbuf[CVS_REV_BUFSZ32], repo[PATH_MAX1024], fpath[PATH_MAX1024];
75 char timebuf[CVS_TIME_BUFSZ64];
76 struct tm datetm;
77
78 if (cvs_nolog == 1)
1
Assuming 'cvs_nolog' is not equal to 1
2
Taking false branch
79 return;
80
81 if (cvs_cmdop == CVS_OP_CHECKOUT4 || cvs_cmdop == CVS_OP_EXPORT9) {
3
Assuming 'cvs_cmdop' is not equal to CVS_OP_CHECKOUT
4
Assuming 'cvs_cmdop' is not equal to CVS_OP_EXPORT
5
Taking false branch
82 if (type != CVS_HISTORY_CHECKOUT1 &&
83 type != CVS_HISTORY_EXPORT2)
84 return;
85 }
86
87 cvs_log(LP_TRACE4, "cvs_history_add(`%c', `%s', `%s')",
88 historytab[type], (cf != NULL((void *)0)) ? cf->file_name : "", argument);
6
Assuming 'cf' is equal to NULL
7
'?' condition is false
89
90 /* construct repository field */
91 if (cvs_cmdop != CVS_OP_CHECKOUT4 && cvs_cmdop != CVS_OP_EXPORT9) {
8
Assuming 'cvs_cmdop' is equal to CVS_OP_CHECKOUT
92 cvs_get_repository_name((cf != NULL((void *)0)) ? cf->file_wd : ".",
93 repo, sizeof(repo));
94 } else {
95 cvs_get_repository_name(argument, repo, sizeof(repo));
96 }
97
98 if (cvs_server_active == 1) {
9
Assuming 'cvs_server_active' is equal to 1
10
Taking true branch
99 cwd = "<remote>";
100 } else {
101 if (getcwd(fpath, sizeof(fpath)) == NULL((void *)0))
102 fatal("cvs_history_add: getcwd: %s", strerror(errno(*__errno())));
103 p = fpath;
104 if (cvs_cmdop == CVS_OP_CHECKOUT4 ||
105 cvs_cmdop == CVS_OP_EXPORT9) {
106 if (strlcat(fpath, "/", sizeof(fpath)) >=
107 sizeof(fpath) || strlcat(fpath, argument,
108 sizeof(fpath)) >= sizeof(fpath))
109 fatal("cvs_history_add: string truncation");
110 }
111 if (cvs_homedir != NULL((void *)0) && cvs_homedir[0] != '\0') {
112 len = strlen(cvs_homedir);
113 if (strncmp(cvs_homedir, fpath, len) == 0 &&
114 fpath[len] == '/') {
115 p += len - 1;
116 *p = '~';
117 }
118 }
119
120 history_compress(p, repo);
121 cwd = xstrdup(p);
122 }
123
124 /* construct revision field */
125 revbuf[0] = '\0';
126 rev = revbuf;
127 switch (type) {
11
'Default' branch taken. Execution continues on line 165
128 case CVS_HISTORY_TAG0:
129 strlcpy(revbuf, argument, sizeof(revbuf));
130 break;
131 case CVS_HISTORY_CHECKOUT1:
132 case CVS_HISTORY_EXPORT2:
133 /*
134 * buf_alloc uses xcalloc(), so we are safe even
135 * if neither cvs_specified_tag nor cvs_specified_date
136 * have been supplied.
137 */
138 buf = buf_alloc(128);
139 if (cvs_specified_tag != NULL((void *)0)) {
140 buf_puts(buf, cvs_specified_tag);
141 if (cvs_specified_date != -1)
142 buf_putc(buf, ':');
143 }
144 if (cvs_specified_date != -1) {
145 gmtime_r(&cvs_specified_date, &datetm);
146 strftime(timebuf, sizeof(timebuf),
147 "%Y.%m.%d.%H.%M.%S", &datetm);
148 buf_puts(buf, timebuf);
149 }
150 rev = buf_release(buf);
151 break;
152 case CVS_HISTORY_UPDATE_MERGED6:
153 case CVS_HISTORY_UPDATE_MERGED_ERR7:
154 case CVS_HISTORY_COMMIT_MODIFIED8:
155 case CVS_HISTORY_COMMIT_ADDED9:
156 case CVS_HISTORY_COMMIT_REMOVED10:
157 case CVS_HISTORY_UPDATE_CO5:
158 if ((hrev = rcs_head_get(cf->file_rcs)) == NULL((void *)0))
159 fatal("cvs_history_add: rcs_head_get failed");
160 rcsnum_tostr(hrev, revbuf, sizeof(revbuf));
161 free(hrev);
162 break;
163 }
164
165 (void)xsnprintf(fpath, sizeof(fpath), "%s/%s",
166 current_cvsroot->cr_dir, CVS_PATH_HISTORY"CVSROOT" "/history");
167
168 if ((fd = open(fpath, O_WRONLY0x0001|O_APPEND0x0008)) == -1) {
12
Assuming the condition is true
13
Taking true branch
169 if (errno(*__errno()) != ENOENT2)
14
Assuming the condition is false
15
Taking false branch
170 cvs_log(LP_ERR1, "failed to open history file");
171 } else {
172 if ((fp = fdopen(fd, "a")) != NULL((void *)0)) {
173 fprintf(fp, "%c%08llx|%s|%s|%s|%s|%s\n",
174 historytab[type], (long long)time(NULL((void *)0)),
175 getlogin(), cwd, repo, rev,
176 (cf != NULL((void *)0)) ? cf->file_name : argument);
177 (void)fclose(fp);
178 } else {
179 cvs_log(LP_ERR1, "failed to add entry to history file");
180 (void)close(fd);
181 }
182 }
183
184 if (rev
15.1
'rev' is equal to 'revbuf'
!= revbuf)
16
Taking false branch
185 free(rev);
186 if (cvs_server_active != 1)
17
Assuming 'cvs_server_active' is not equal to 1
18
Taking true branch
187 free(cwd);
19
Argument to free() is the address of a global variable, which is not memory allocated by malloc()
188}
189
190static void
191history_compress(char *wdir, const char *repo)
192{
193 char *p;
194 const char *q;
195 size_t repo_len, wdir_len;
196
197 repo_len = strlen(repo);
198 wdir_len = strlen(wdir);
199
200 p = wdir + wdir_len;
201 q = repo + repo_len;
202
203 while (p >= wdir && q >= repo) {
204 if (*p != *q)
205 break;
206 p--;
207 q--;
208 }
209 p++;
210 q++;
211
212 /* if it's not worth the effort, skip compression */
213 if (repo + repo_len - q < 3)
214 return;
215
216 (void)xsnprintf(p, strlen(p) + 1, "*%zx", q - repo);
217}
218
219int
220cvs_history(int argc, char **argv)
221{
222 int ch, flags;
223
224 flags = 0;
225
226 while ((ch = getopt(argc, argv, cvs_cmd_history.cmd_opts)) != -1) {
227 switch (ch) {
228 case 'a':
229 flags |= HISTORY_ALL_USERS0x01;
230 break;
231 case 'c':
232 flags |= HISTORY_DISPLAY_ARCHIVED0x02;
233 break;
234 default:
235 fatal("%s", cvs_cmd_history.cmd_synopsis);
236 }
237 }
238
239 argc -= optind;
240 argv += optind;
241
242 return (0);
243}