clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -main-file-name async_filebuf.cc -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -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 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /w/halld-scifs17exp/home/sdobbs/clang/llvm-project/install/lib/clang/12.0.0 -D HAVE_EVIO -D HAVE_TMVA=1 -I .Linux_CentOS7.7-x86_64-gcc4.8.5/libraries/DAQ -I libraries/DAQ -I . -I libraries -I libraries/include -I /w/halld-scifs17exp/home/sdobbs/clang/halld_recon/Linux_CentOS7.7-x86_64-gcc4.8.5/include -I libraries -I /group/halld/Software/builds/Linux_CentOS7.7-x86_64-gcc4.8.5/evio/evio-4.4.6/Linux-x86_64/include -I /w/halld-scifs17exp/halld2/home/sdobbs/Software/jana/jana_0.8.2/Linux_CentOS7.7-x86_64-gcc4.8.5/include -I /group/halld/Software/builds/Linux_CentOS7.7-x86_64-gcc4.8.5/root/root-6.08.06/include -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5 -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/x86_64-redhat-linux -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/backward -internal-isystem /usr/local/include -internal-isystem /w/halld-scifs17exp/home/sdobbs/clang/llvm-project/install/lib/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /home/sdobbs/work/clang/halld_recon/src -ferror-limit 19 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-01-21-110224-160369-1 -x c++ libraries/DAQ/async_filebuf.cc
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | #ifndef __APPLE__ |
13 | |
14 | #include <string> |
15 | #include <string.h> |
16 | #include <stdexcept> |
17 | |
18 | #include <async_filebuf.h> |
19 | |
20 | async_filebuf::async_filebuf(int segsize, int segcount, int lookback) |
21 | : segment_size(segsize), |
22 | segment_count(segcount), |
23 | segment_lookback(lookback), |
24 | readloop_active(0) |
25 | { |
26 | #if VERBOSE_ASYNC_FILEBUF |
27 | std::cout << THIS_ASYNCFB << "async_filebuf::async_filebuf(" << segsize << "," << segcount << "," << lookback << ")" << std::endl; |
28 | #endif |
29 | if (segment_count < segment_lookback + 2) { |
30 | std::string errmsg("async_filebuf error - insufficient" |
31 | " segment count for look-back."); |
32 | std::cerr << errmsg << std::endl; |
33 | throw std::range_error(errmsg); |
34 | } |
35 | int bufsize = segment_size * segment_count; |
36 | buffer = new char[bufsize]; |
37 | setbuf(buffer, bufsize); |
38 | } |
39 | |
40 | async_filebuf::~async_filebuf() |
41 | { |
42 | #if VERBOSE_ASYNC_FILEBUF |
43 | std::cout << THIS_ASYNCFB << "async_filebuf::~async_filebuf()" << std::endl; |
44 | #endif |
45 | if (is_open()) |
| 1 | Assuming the condition is true | |
|
| |
46 | close(); |
| 3 | | Calling 'async_filebuf::close' | |
|
47 | delete [] buffer; |
48 | } |
49 | |
50 | int async_filebuf::readloop_initiate() |
51 | { |
52 | #if VERBOSE_ASYNC_FILEBUF |
53 | std::cout << THIS_ASYNCFB << "async_filebuf::readloop_initiate()" << std::endl; |
54 | #endif |
55 | if (readloop_active) |
56 | return -1; |
57 | segment_count = 0; |
58 | for (char *p = buffer_start; p < buffer_end; p += segment_size) { |
59 | segment_cond.push_back(sEmpty); |
60 | segment_pos.push_back(0); |
61 | segment_len.push_back(0); |
62 | ++segment_count; |
63 | } |
64 | segment_backstop = 0; |
65 | readloop_active = 1; |
66 | readloop_thread = new std::thread(&async_filebuf::readloop, this); |
67 | buffer_eback = buffer_end; |
68 | buffer_gptr = buffer_end; |
69 | buffer_egptr = buffer_end; |
70 | return 0; |
71 | } |
72 | |
73 | int async_filebuf::readloop_terminate() |
74 | { |
75 | #if VERBOSE_ASYNC_FILEBUF |
76 | std::cout << THIS_ASYNCFB << "async_filebuf::readloop_terminate()" << std::endl; |
77 | #endif |
78 | |
79 | if (readloop_active) { |
| |
80 | std::streampos pos = getpos(); |
| 8 | | Calling 'async_filebuf::getpos' | |
|
| 17 | | Returning from 'async_filebuf::getpos' | |
|
81 | if (readloop_thread) { |
| 18 | | Assuming field 'readloop_thread' is null | |
|
| |
82 | std::unique_lock<std::mutex> lk(readloop_lock); |
83 | readloop_active = 0; |
84 | readloop_wake.notify_one(); |
85 | } |
86 | readloop_thread->join(); |
| 20 | | Called C++ object pointer is null |
|
87 | delete readloop_thread; |
88 | readloop_thread = 0; |
89 | std::filebuf::seekpos(pos, std::ios::in); |
90 | buffer_eback = buffer_end; |
91 | buffer_gptr = buffer_end; |
92 | buffer_egptr = buffer_end; |
93 | segment_cond.clear(); |
94 | segment_pos.clear(); |
95 | segment_len.clear(); |
96 | } |
97 | return 0; |
98 | } |
99 | |
100 | int async_filebuf::readloop() |
101 | { |
102 | #if VERBOSE_ASYNC_FILEBUF |
103 | std::cout << THIS_ASYNCFB << "async_filebuf::readloop()" << std::endl; |
104 | #endif |
105 | int seg = 0; |
106 | while (readloop_active) { |
107 | std::unique_lock<std::mutex> lk(readloop_lock); |
108 | while (readloop_active && segment_cond[seg] != sEmpty) { |
109 | readloop_wake.wait(lk); |
110 | } |
111 | if (! readloop_active) |
112 | break; |
113 | segment_cond[seg] = sFilling; |
114 | lk.unlock(); |
115 | char *sbase = buffer_start + seg * segment_size; |
116 | segment_pos[seg] = this->std::filebuf::seekoff(0, std::ios::cur, std::ios::in); |
117 | std::streamsize nreq = buffer_end - sbase; |
118 | nreq = (nreq > segment_size)? segment_size : nreq; |
119 | segment_len[seg] = std::filebuf::xsgetn(sbase, nreq); |
120 | lk.lock(); |
121 | segment_cond[seg] = sFull; |
122 | readloop_woke.notify_one(); |
123 | seg = (seg + 1) % segment_count; |
124 | } |
125 | return 0; |
126 | } |
127 | |
128 | int async_filebuf::underflow() |
129 | { |
130 | #if VERBOSE_ASYNC_FILEBUF |
131 | std::cout << THIS_ASYNCFB << "async_filebuf::underflow()" << std::endl; |
132 | #endif |
133 | if (!readloop_active) { |
134 | if (segment_lookback > 0) |
135 | readloop_initiate(); |
136 | else |
137 | return std::filebuf::underflow(); |
138 | } |
139 | |
140 | int seg = segment() % segment_count; |
141 | if (segoff() > 0) |
142 | seg = (seg + 1) % segment_count; |
143 | std::unique_lock<std::mutex> lk(readloop_lock); |
144 | while (segment_cond[seg] != sFull) { |
145 | readloop_woke.wait(lk); |
146 | } |
147 | segment_cond[seg] = sEmptying; |
148 | if ((segment_backstop + segment_lookback + 1) % segment_count == seg) { |
149 | segment_cond[segment_backstop] = sEmpty; |
150 | readloop_wake.notify_one(); |
151 | segment_backstop = (segment_backstop + 1) % segment_count; |
152 | } |
153 | buffer_eback = buffer_start + seg * segment_size; |
154 | buffer_egptr = buffer_eback + segment_len[seg]; |
155 | buffer_gptr = buffer_eback; |
156 | if (segment_len[seg] == 0) |
157 | return EOF; |
158 | return (unsigned char)*buffer_gptr; |
159 | } |
160 | |
161 | std::streampos async_filebuf::seekoff(std::streamoff off, std::ios::seekdir way, |
162 | std::ios::openmode which) |
163 | { |
164 | #if VERBOSE_ASYNC_FILEBUF |
165 | std::cout << THIS_ASYNCFB << "async_filebuf::seekoff(" << off << "," << way << "," << which << ")" << std::endl; |
166 | #endif |
167 | if (readloop_active && segment_lookback > 0) { |
168 | if (way == std::ios::beg) |
169 | return seekpos(off, which); |
170 | else if (way == std::ios::cur) |
171 | return seekpos(getpos() + off, which); |
172 | else |
173 | readloop_terminate(); |
174 | } |
175 | return this->std::filebuf::seekoff(off, way, which); |
176 | } |
177 | |
178 | std::streampos async_filebuf::seekpos(std::streampos pos, std::ios::openmode which) |
179 | { |
180 | #if VERBOSE_ASYNC_FILEBUF |
181 | std::cout << THIS_ASYNCFB << "async_filebuf::seekpos(" << pos << "," << which << ")" << std::endl; |
182 | #endif |
183 | if (! readloop_active || segment_lookback == 0) { |
184 | return this->std::filebuf::seekpos(pos, which); |
185 | } |
186 | if (pos < std::streampos(0)) |
187 | pos = std::streampos(0); |
188 | std::streampos curpos = getpos(); |
189 | if (abs(pos - curpos) > segment_lookback * segment_size) { |
190 | if (readloop_active) |
191 | readloop_terminate(); |
192 | return this->std::filebuf::seekpos(pos, which); |
193 | } |
194 | |
195 | int seg = segment(); |
196 | while (pos < segment_pos[seg]) { |
197 | segment_cond[seg] = sFull; |
198 | int prevseg = (seg == 0)? segment_count-1 : seg-1; |
199 | if (segment_cond[prevseg] != sEmptying) { |
200 | if (readloop_active) |
201 | readloop_terminate(); |
202 | return this->std::filebuf::seekpos(pos, which); |
203 | } |
204 | seg = prevseg; |
205 | } |
206 | while (pos >= segment_pos[seg] + segment_len[seg]) { |
207 | buffer_gptr = buffer_egptr; |
208 | if (underflow() == EOF) |
209 | return std::streampos(std::streamoff(-1)); |
210 | seg = (seg + 1) % segment_count; |
211 | } |
212 | int off = pos - segment_pos[seg]; |
213 | buffer_eback = buffer_start + seg * segment_size; |
214 | buffer_gptr = buffer_eback + off; |
215 | buffer_egptr = buffer_eback + segment_len[seg]; |
216 | return pos; |
217 | } |
218 | |
219 | std::streamsize async_filebuf::xsgetn(char* s, std::streamsize n) |
220 | { |
221 | #if VERBOSE_ASYNC_FILEBUF |
222 | std::cout << THIS_ASYNCFB << "async_filebuf::xsgetn(s," << n << ")" << std::endl; |
223 | #endif |
224 | if (segment_lookback == 0) { |
225 | return std::filebuf::xsgetn(s,n); |
226 | } |
227 | |
228 | std::streamsize nleft=n; |
229 | while (nleft > 0) { |
230 | int nbuf = buffer_egptr - buffer_gptr; |
231 | if (nbuf > 0) { |
232 | nbuf = (nbuf < nleft)? nbuf : nleft; |
233 | memcpy(s, buffer_gptr, nbuf); |
234 | #if VERBOSE_ASYNC_FILEBUF |
235 | std::cout << THIS_ASYNCFB << "memcpy(d, s, " << nbuf << ")" << std::endl; |
236 | #endif |
237 | #if SHADOW_DEBUG |
238 | shadow_ifs.seekg(getpos()); |
239 | char *shadowbuf = new char[nbuf]; |
240 | if (shadow_ifs.read(shadowbuf, nbuf) && shadow_ifs.gcount() == nbuf) { |
241 | for (int i=0; i<nbuf; ++i) { |
242 | if (shadowbuf[i] != buffer_gptr[i]) { |
243 | std::cerr << "Error in async_filebuf::xsgetn - " |
244 | "data read from buffer does not match " |
245 | "what reading directly from the file " |
246 | "gives at the same offset! Cannot continue." |
247 | << std::endl; |
248 | exit(6); |
249 | } |
250 | } |
251 | } |
252 | else { |
253 | std::cerr << "Error in async_filebuf::xsgetn - " |
254 | "error reading from the shadow ifstream input. " |
255 | "Cannot continue." |
256 | << std::endl; |
257 | exit(6); |
258 | } |
259 | delete [] shadowbuf; |
260 | #endif |
261 | s += nbuf; |
262 | buffer_gptr += nbuf; |
263 | nleft -= nbuf; |
264 | } |
265 | else if (underflow() == EOF) { |
266 | break; |
267 | } |
268 | } |
269 | return n - nleft; |
270 | } |
271 | |
272 | #else // __APPLE__ |
273 | int async_filebuff_disable_for_mac_osx = 0; |
274 | #endif // __APPLE__ |
275 | |
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | #ifndef _ASYNC_FILEBUF_ |
8 | #define _ASYNC_FILEBUF_ |
9 | |
10 | #include <fstream> |
11 | #include <iostream> |
12 | #include <cstdio> |
13 | #include <vector> |
14 | #include <thread> |
15 | #include <mutex> |
16 | #include <condition_variable> |
17 | |
18 | |
19 | |
20 | |
21 | #define THIS_ASYNCFB "(" << (void*)this << ")" |
22 | |
23 | class async_filebuf : public std::filebuf { |
24 | |
25 | public: |
26 | async_filebuf(int segsize=1000000, int segcount=3, int lookback=1); |
27 | virtual ~async_filebuf(); |
28 | |
29 | async_filebuf* open(const std::string fname, std::ios::openmode mode) { |
30 | #if VERBOSE_ASYNC_FILEBUF |
31 | std::cout << THIS_ASYNCFB << "async_filebuf::open(" << fname << "," << mode << ")" << std::endl; |
32 | #endif |
33 | std::filebuf::open(fname, mode); |
34 | #if SHADOW_DEBUG |
35 | shadow_ifs.open(fname, mode); |
36 | #endif |
37 | return this; |
38 | } |
39 | |
40 | async_filebuf* close() { |
41 | #if VERBOSE_ASYNC_FILEBUF |
42 | std::cout << THIS_ASYNCFB << "async_filebuf::close()" << std::endl; |
43 | #endif |
44 | if (readloop_active) |
| 4 | | Assuming field 'readloop_active' is not equal to 0 | |
|
| |
45 | readloop_terminate(); |
| 6 | | Calling 'async_filebuf::readloop_terminate' | |
|
46 | std::filebuf::close(); |
47 | #if SHADOW_DEBUG |
48 | shadow_ifs.close(); |
49 | #endif |
50 | return this; |
51 | } |
52 | |
53 | std::streamsize in_avail() { |
54 | #if VERBOSE_ASYNC_FILEBUF |
55 | std::cout << THIS_ASYNCFB << "async_filebuf::in_avail()" << std::endl; |
56 | #endif |
57 | if (readloop_active) |
58 | return buffer_egptr - buffer_gptr; |
59 | return std::filebuf::in_avail(); |
60 | } |
61 | |
62 | int snextc() { |
63 | #if VERBOSE_ASYNC_FILEBUF |
64 | std::cout << THIS_ASYNCFB << "async_filebuf::snextc()" << std::endl; |
65 | #endif |
66 | if (readloop_active) { |
67 | if (buffer_gptr < buffer_egptr) |
68 | return (unsigned char)*(++buffer_gptr); |
69 | if (underflow() == EOF) |
70 | return EOF; |
71 | return snextc(); |
72 | } |
73 | return std::filebuf::snextc(); |
74 | } |
75 | |
76 | int sbumpc() { |
77 | if (readloop_active) { |
78 | if (buffer_gptr < buffer_egptr) |
79 | return (unsigned char)*(buffer_gptr++); |
80 | if (underflow() == EOF) |
81 | return EOF; |
82 | return sbumpc(); |
83 | } |
84 | return std::filebuf::sbumpc(); |
85 | } |
86 | |
87 | int sgetc() { |
88 | if (readloop_active) { |
89 | if (buffer_gptr == buffer_egptr) |
90 | return underflow(); |
91 | else |
92 | return (unsigned char)*buffer_gptr; |
93 | } |
94 | return std::filebuf::sgetc(); |
95 | } |
96 | |
97 | int sputbackc(int c) { |
98 | if (readloop_active) { |
99 | int seg = (buffer_gptr - buffer_start) / segment_size; |
100 | char *eback = buffer_start + seg * segment_size; |
101 | if (buffer_gptr > eback || c == (unsigned char)buffer_gptr[-1]) |
102 | return (unsigned char)*(--buffer_gptr); |
103 | else |
104 | return pbackfail(); |
105 | } |
106 | return std::filebuf::sputbackc(c); |
107 | } |
108 | |
109 | int sungetc() { |
110 | if (readloop_active) { |
111 | int seg = (buffer_gptr - buffer_start) / segment_size; |
112 | char *eback = buffer_start + seg * segment_size; |
113 | if (buffer_gptr > eback) |
114 | return (unsigned char)*(--buffer_gptr); |
115 | else |
116 | return pbackfail(); |
117 | } |
118 | return std::filebuf::sungetc(); |
119 | } |
120 | |
121 | protected: |
122 | int pbackfail(char c=EOF) { |
123 | if (readloop_active) |
124 | return EOF; |
125 | return std::filebuf::pbackfail(c); |
126 | } |
127 | |
128 | virtual std::streambuf* setbuf(char* s, std::streamsize n) { |
129 | #if VERBOSE_ASYNC_FILEBUF |
130 | std::cout << THIS_ASYNCFB << "async_filebuf::setbuf(s," << n << ")" << std::endl; |
131 | #endif |
132 | if (! readloop_active) { |
133 | buffer_start = s; |
134 | buffer_end = s + n; |
135 | buffer_eback = buffer_end; |
136 | buffer_gptr = buffer_end; |
137 | buffer_egptr = buffer_end; |
138 | } |
139 | return this; |
140 | } |
141 | |
142 | virtual std::streamsize showmanyc() { |
143 | if (readloop_active) { |
144 | if (buffer_gptr == buffer_egptr) |
145 | underflow(); |
146 | return buffer_egptr - buffer_gptr; |
147 | } |
148 | return std::filebuf::showmanyc(); |
149 | } |
150 | |
151 | virtual int uflow() { |
152 | #if VERBOSE_ASYNC_FILEBUF |
153 | std::cout << THIS_ASYNCFB << "async_filebuf::uflow()" << std::endl; |
154 | #endif |
155 | if (readloop_active) { |
156 | if (underflow() == EOF) |
157 | return EOF; |
158 | return (unsigned char)*buffer_gptr++; |
159 | } |
160 | return std::filebuf::uflow(); |
161 | } |
162 | |
163 | virtual int underflow(); |
164 | |
165 | virtual std::streamsize xsgetn(char* s, std::streamsize n); |
166 | |
167 | virtual std::streampos seekoff(std::streamoff off, std::ios::seekdir way, |
168 | std::ios::openmode which); |
169 | |
170 | virtual std::streampos seekpos(std::streampos pos, std::ios::openmode which); |
171 | |
172 | protected: |
173 | char *buffer; |
174 | char *buffer_start; |
175 | char *buffer_end; |
176 | char *buffer_eback; |
177 | char *buffer_gptr; |
178 | char *buffer_egptr; |
179 | |
180 | enum segment_state {sFull, sEmptying, sEmpty, sFilling}; |
181 | std::vector<segment_state> segment_cond; |
182 | std::vector<std::streampos> segment_pos; |
183 | std::vector<std::streamsize> segment_len; |
184 | int segment_size; |
185 | int segment_count; |
186 | int segment_lookback; |
187 | int segment_backstop; |
188 | int readloop_active; |
189 | std::mutex readloop_lock; |
190 | std::condition_variable readloop_wake; |
191 | std::condition_variable readloop_woke; |
192 | std::thread *readloop_thread; |
193 | |
194 | #if SHADOW_DEBUG |
195 | std::ifstream shadow_ifs; |
196 | #endif |
197 | |
198 | protected: |
199 | int readloop_initiate(); |
200 | int readloop_terminate(); |
201 | int readloop(); |
202 | |
203 | int segment() { return (buffer_gptr - buffer_start) / segment_size; } |
204 | int segoff() { return (buffer_gptr - buffer_start) % segment_size; } |
205 | |
206 | std::streampos getpos() { |
207 | if (! readloop_active) |
| |
208 | return this->std::filebuf::seekoff(0, std::ios::cur, std::ios::in); |
209 | else if (buffer_gptr == buffer_egptr) { |
| 10 | | Assuming field 'buffer_gptr' is equal to field 'buffer_egptr' | |
|
| |
210 | if (segment_len[segment()] > 0) |
| 12 | | Assuming the condition is false | |
|
| |
211 | underflow(); |
212 | if (buffer_gptr == buffer_egptr) |
| 14 | | Assuming field 'buffer_gptr' is equal to field 'buffer_egptr' | |
|
| |
213 | return this->std::filebuf::seekoff(0, std::ios::cur, std::ios::in); |
| 16 | | Value assigned to field 'readloop_thread' | |
|
214 | } |
215 | std::streampos pos = segment_pos[segment()] + std::streamsize(segoff()); |
216 | #if VERBOSE_ASYNC_FILEBUF |
217 | std::cout << THIS_ASYNCFB << "async_filebuf::getpos() returns " << pos << " in segment " << segment() << std::endl; |
218 | #endif |
219 | return pos; |
220 | } |
221 | }; |
222 | |
223 | #endif |