Bug Summary

File:nnc/ccv_nnc_symbolic_graph_chain_decomposition.c
Warning:line 81, column 4
Use of memory allocated with size zero

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ccv_nnc_symbolic_graph_chain_decomposition.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 -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 -target-feature +sse2 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/home/liu/actions-runner/_work/ccv/ccv/lib/nnc -fcoverage-compilation-dir=/home/liu/actions-runner/_work/ccv/ccv/lib/nnc -resource-dir /usr/local/lib/clang/19 -I ../ -I /usr/local/cuda/include -D HAVE_CBLAS -D HAVE_LIBPNG -D HAVE_LIBJPEG -D HAVE_FFTW3 -D HAVE_PTHREAD -D HAVE_LIBLINEAR -D HAVE_TESSERACT -D HAVE_AVCODEC -D HAVE_AVFORMAT -D HAVE_AVUTIL -D HAVE_SWSCALE -D HAVE_SSE2 -D HAVE_GSL -D HAVE_CUDA -D HAVE_CUDNN -D HAVE_NCCL -D USE_SYSTEM_CUB -I /usr/local/include -internal-isystem /usr/local/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/liu/actions-runner/_work/ccv/ccv/_analyze/2024-12-02-182708-529063-1 -x c ccv_nnc_symbolic_graph_chain_decomposition.c
1#include "ccv_nnc.h"
2#include "ccv_nnc_easy.h"
3#include "ccv_nnc_internal.h"
4#include "ccv_internal.h"
5#include "_ccv_nnc_symbolic_graph.h"
6
7// Implement the new method for exec_dep. We use chain decomposition such that each node only needs to log which chain and at which node to be dependent on.
8ccv_nnc_exec_dep_t ccv_nnc_exec_dep_new(const ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_graph_visit_t* const visit, const ccv_nnc_graph_visit_t* const reversed_visit)
9{
10 const int exec_symbol_info_size = graph->exec_symbol_info->rnum;
11 int* chain_ids = ccmallocmalloc(sizeof(int) * exec_symbol_info_size * 2);
12 int* chain_pos = chain_ids + exec_symbol_info_size;
13 int* buf = (int*)ccmallocmalloc(sizeof(int) * exec_symbol_info_size);
14 int* reversed_depth = buf;
15 const ccv_nnc_graph_exec_symbol_info_t* const exec_symbol_info = (ccv_nnc_graph_exec_symbol_info_t*)ccv_array_get(graph->exec_symbol_info, 0)((void*)(((char*)((graph->exec_symbol_info)->data)) + (
size_t)(graph->exec_symbol_info)->rsize * (size_t)(0)))
;
16 int i, j;
17 // Go reverse order to generate the distance from sink.
18 ccv_nnc_graph_visit_for(reversed_visit, exec_symbol_info, node, idx, term){ int _i_; for (_i_ = 0; _i_ < (reversed_visit)->size; _i_
++) { const int idx __attribute__((unused)) = (reversed_visit
)->node[_i_].index; const int term __attribute__((unused))
= (reversed_visit)->node[_i_].term; typeof ((exec_symbol_info
)) const node __attribute__((unused)) = (exec_symbol_info) + idx
;
{
1
Assuming '_i_' is >= field 'size'
2
Loop condition is false. Execution continues on line 36
19 chain_ids[idx] = -1;
20 if (!node->outgoings || node->outgoings->rnum == 0)
21 {
22 reversed_depth[idx] = 0;
23 continue;
24 }
25 const int outgoing = *(int*)ccv_array_get(node->outgoings, 0)((void*)(((char*)((node->outgoings)->data)) + (size_t)(
node->outgoings)->rsize * (size_t)(0)))
;
26 int depth = reversed_depth[outgoing];
27 for (i = 1; i < node->outgoings->rnum; i++)
28 {
29 const int outgoing = *(int*)ccv_array_get(node->outgoings, i)((void*)(((char*)((node->outgoings)->data)) + (size_t)(
node->outgoings)->rsize * (size_t)(i)))
;
30 depth = ccv_max(depth, reversed_depth[outgoing])({ typeof (depth) _a = (depth); typeof (reversed_depth[outgoing
]) _b = (reversed_depth[outgoing]); (_a > _b) ? _a : _b; }
)
;
31 }
32 reversed_depth[idx] = depth + 1;
33 } ccv_nnc_graph_visit_endfor} }
34 // Go in order to generate chain ids (if there are multiple exits, we use the reverse depth to break the tie).
35 // Note that we cannot use depth so-far because then multiple exit nodes are equally good to "inherit" the chain selection.
36 int chain_count = 0;
37 ccv_nnc_graph_visit_for(visit, exec_symbol_info, node, idx, term){ int _i_; for (_i_ = 0; _i_ < (visit)->size; _i_++) { const
int idx __attribute__((unused)) = (visit)->node[_i_].index
; const int term __attribute__((unused)) = (visit)->node[_i_
].term; typeof ((exec_symbol_info)) const node __attribute__(
(unused)) = (exec_symbol_info) + idx;
{
3
Assuming '_i_' is < field 'size'
4
Loop condition is true. Entering loop body
8
Assuming '_i_' is >= field 'size'
9
Loop condition is false. Execution continues on line 62
38 int chain_id = chain_ids[idx];
39 if (chain_ids[idx] < 0)
5
Assuming the condition is false
40 {
41 chain_id = chain_count;
42 chain_ids[idx] = chain_id;
43 chain_pos[idx] = 1; // The first one in this chain. 1-based index because in sparse matrix, 0 is the default value.
44 chain_count += 1;
45 }
46 if (!node->outgoings || node->outgoings->rnum == 0)
6
Assuming field 'outgoings' is null
47 continue;
7
Execution continues on line 37
48 int depth = 0;
49 int next_idx = -1;
50 for (i = 0; i < node->outgoings->rnum; i++)
51 {
52 const int outgoing = *(int*)ccv_array_get(node->outgoings, i)((void*)(((char*)((node->outgoings)->data)) + (size_t)(
node->outgoings)->rsize * (size_t)(i)))
;
53 if (chain_ids[outgoing] < 0 && reversed_depth[outgoing] > depth)
54 depth = reversed_depth[outgoing], next_idx = outgoing;
55 }
56 if (next_idx >= 0)
57 {
58 chain_ids[next_idx] = chain_id;
59 chain_pos[next_idx] = chain_pos[idx] + 1;
60 }
61 } ccv_nnc_graph_visit_endfor} }
62 if (exec_symbol_info_size < chain_count * 3) // Be more conservative on RAM usage.
10
Assuming the condition is true
11
Taking true branch
63 buf = ccreallocrealloc(buf, sizeof(int) * chain_count * 3);
64 ccv_sparse_matrix_t* deps = ccv_sparse_matrix_new(graph->exec_symbol_info->rnum, chain_count, CCV_32S | CCV_C2, CCV_SPARSE_ROW_MAJOR, 0);
65 // It logs which pos on that chain we depend on. We can simply compare that with the chain_pos for a node to know if they are ancestors.
66#define for_block(x, val) \
67 do { \
68 if (((int32_t*)val)[0] > 0) \
69 { \
70 buf[buf_size * 3] = x; \
71 buf[buf_size * 3 + 1] = ((int32_t*)val)[0]; \
72 buf[buf_size * 3 + 2] = ((int32_t*)val)[1] + 1; \
73 ++buf_size; \
74 } \
75 } while (0)
76 int buf_size;
77 ccv_nnc_graph_visit_for(visit, exec_symbol_info, node, idx, term){ int _i_; for (_i_ = 0; _i_ < (visit)->size; _i_++) { const
int idx __attribute__((unused)) = (visit)->node[_i_].index
; const int term __attribute__((unused)) = (visit)->node[_i_
].term; typeof ((exec_symbol_info)) const node __attribute__(
(unused)) = (exec_symbol_info) + idx;
{
12
Loop condition is true. Entering loop body
78 buf_size = 0; /* save all its parent deps to this buffer */
79 ccv_sparse_matrix_vector_t* vector = ccv_get_sparse_matrix_vector(deps, idx);
80 if (vector)
13
Assuming 'vector' is non-null
14
Taking true branch
81 CCV_SPARSE_VECTOR_FOREACH(deps, vector, for_block)do { switch ((((deps)->type) & 0xFF000)) { case CCV_32S
: { do { int _i_; __attribute__((unused)) const size_t _c_ = (
((deps)->type) & 0xFFF); if ((deps)->type & CCV_DENSE_VECTOR
) { for (_i_ = 0; _i_ < (vector)->size; _i_++) { for_block
((_i_), ((vector)->data.i32 + (_i_ * _c_))); } } else { const
size_t _idx_size_ = sizeof(ccv_sparse_matrix_index_t) + ((_ccv_get_data_type_size
[(((deps)->type) & 0xFF000) >> 12] * (((deps)->
type) & 0xFFF) + 3) & -4); uint8_t* const _vidx_ = (uint8_t
*)(vector)->index; for (_i_ = 0; _i_ < (vector)->size
; _i_++) { ccv_sparse_matrix_index_t* const _idx_i_ = (ccv_sparse_matrix_index_t
*)(_vidx_ + _idx_size_ * _i_); if (_idx_i_->ifbit <= 1)
continue; ccv_numeric_data_t _d_ = { .u8 = (uint8_t*)(_idx_i_
+ 1) }; for_block((_idx_i_->i), (_d_.i32 + (0))); } } } while
(0); break; } case CCV_32F: { do { int _i_; __attribute__((unused
)) const size_t _c_ = (((deps)->type) & 0xFFF); if ((deps
)->type & CCV_DENSE_VECTOR) { for (_i_ = 0; _i_ < (
vector)->size; _i_++) { for_block((_i_), ((vector)->data
.f32 + (_i_ * _c_))); } } else { const size_t _idx_size_ = sizeof
(ccv_sparse_matrix_index_t) + ((_ccv_get_data_type_size[(((deps
)->type) & 0xFF000) >> 12] * (((deps)->type) &
0xFFF) + 3) & -4); uint8_t* const _vidx_ = (uint8_t*)(vector
)->index; for (_i_ = 0; _i_ < (vector)->size; _i_++)
{ ccv_sparse_matrix_index_t* const _idx_i_ = (ccv_sparse_matrix_index_t
*)(_vidx_ + _idx_size_ * _i_); if (_idx_i_->ifbit <= 1)
continue; ccv_numeric_data_t _d_ = { .u8 = (uint8_t*)(_idx_i_
+ 1) }; for_block((_idx_i_->i), (_d_.f32 + (0))); } } } while
(0); break; } case CCV_64S: { do { int _i_; __attribute__((unused
)) const size_t _c_ = (((deps)->type) & 0xFFF); if ((deps
)->type & CCV_DENSE_VECTOR) { for (_i_ = 0; _i_ < (
vector)->size; _i_++) { for_block((_i_), ((vector)->data
.i64 + (_i_ * _c_))); } } else { const size_t _idx_size_ = sizeof
(ccv_sparse_matrix_index_t) + ((_ccv_get_data_type_size[(((deps
)->type) & 0xFF000) >> 12] * (((deps)->type) &
0xFFF) + 3) & -4); uint8_t* const _vidx_ = (uint8_t*)(vector
)->index; for (_i_ = 0; _i_ < (vector)->size; _i_++)
{ ccv_sparse_matrix_index_t* const _idx_i_ = (ccv_sparse_matrix_index_t
*)(_vidx_ + _idx_size_ * _i_); if (_idx_i_->ifbit <= 1)
continue; ccv_numeric_data_t _d_ = { .u8 = (uint8_t*)(_idx_i_
+ 1) }; for_block((_idx_i_->i), (_d_.i64 + (0))); } } } while
(0); break; } case CCV_64F: { do { int _i_; __attribute__((unused
)) const size_t _c_ = (((deps)->type) & 0xFFF); if ((deps
)->type & CCV_DENSE_VECTOR) { for (_i_ = 0; _i_ < (
vector)->size; _i_++) { for_block((_i_), ((vector)->data
.f64 + (_i_ * _c_))); } } else { const size_t _idx_size_ = sizeof
(ccv_sparse_matrix_index_t) + ((_ccv_get_data_type_size[(((deps
)->type) & 0xFF000) >> 12] * (((deps)->type) &
0xFFF) + 3) & -4); uint8_t* const _vidx_ = (uint8_t*)(vector
)->index; for (_i_ = 0; _i_ < (vector)->size; _i_++)
{ ccv_sparse_matrix_index_t* const _idx_i_ = (ccv_sparse_matrix_index_t
*)(_vidx_ + _idx_size_ * _i_); if (_idx_i_->ifbit <= 1)
continue; ccv_numeric_data_t _d_ = { .u8 = (uint8_t*)(_idx_i_
+ 1) }; for_block((_idx_i_->i), (_d_.f64 + (0))); } } } while
(0); break; } default: { do { int _i_; __attribute__((unused
)) const size_t _c_ = (((deps)->type) & 0xFFF); if ((deps
)->type & CCV_DENSE_VECTOR) { for (_i_ = 0; _i_ < (
vector)->size; _i_++) { for_block((_i_), ((vector)->data
.u8 + (_i_ * _c_))); } } else { const size_t _idx_size_ = sizeof
(ccv_sparse_matrix_index_t) + ((_ccv_get_data_type_size[(((deps
)->type) & 0xFF000) >> 12] * (((deps)->type) &
0xFFF) + 3) & -4); uint8_t* const _vidx_ = (uint8_t*)(vector
)->index; for (_i_ = 0; _i_ < (vector)->size; _i_++)
{ ccv_sparse_matrix_index_t* const _idx_i_ = (ccv_sparse_matrix_index_t
*)(_vidx_ + _idx_size_ * _i_); if (_idx_i_->ifbit <= 1)
continue; ccv_numeric_data_t _d_ = { .u8 = (uint8_t*)(_idx_i_
+ 1) }; for_block((_idx_i_->i), (_d_.u8 + (0))); } } } while
(0); } } } while (0)
;
15
Control jumps to 'case CCV_32S:' at line 81
16
Assuming the condition is true
17
Taking true branch
18
Assuming '_i_' is < field 'size'
19
Loop condition is true. Entering loop body
20
Assuming the condition is true
21
Taking true branch
22
Use of memory allocated with size zero
82 if (!node->outgoings)
83 continue;
84 const int chain_id = chain_ids[idx];
85 const int pos = chain_pos[idx];
86 for (i = 0; i < node->outgoings->rnum; i++)
87 {
88 const int outgoing = *(int*)ccv_array_get(node->outgoings, i)((void*)(((char*)((node->outgoings)->data)) + (size_t)(
node->outgoings)->rsize * (size_t)(i)))
;
89 const int outgoing_chain_id = chain_ids[outgoing];
90 if (outgoing_chain_id != chain_id)
91 {
92 ccv_numeric_data_t cell = ccv_get_sparse_matrix_cell(deps, outgoing, chain_id);
93 /* If not found, set, if the current node is the destination node, no need
94 * set itself as parent of subsequent nodes because its terminal nature. */
95 if (!cell.i32 || cell.i32[0] == 0 || cell.i32[0] < pos)
96 {
97 int p[2] = { pos, 1 };
98 ccv_set_sparse_matrix_cell(deps, outgoing, chain_id, &p);
99 }
100 }
101 if (buf_size > 0)
102 {
103 ccv_sparse_matrix_vector_t* vector = ccv_get_sparse_matrix_vector(deps, outgoing);
104 for (j = 0; j < buf_size; j++) /* set with all idx's dependencies as well */
105 {
106 if (outgoing_chain_id == buf[j * 3]) // We don't need to add as dependency for the same chain.
107 continue;
108 if (!vector)
109 {
110 ccv_set_sparse_matrix_cell(deps, outgoing, buf[j * 3], &buf[j * 3 + 1]);
111 vector = ccv_get_sparse_matrix_vector(deps, outgoing);
112 continue;
113 }
114 ccv_numeric_data_t cell = ccv_get_sparse_matrix_cell_from_vector(deps, vector, buf[j * 3]);
115 /* If not found, set. Otherwise, set to the latest one only if it is later. */
116 if (!cell.i32)
117 ccv_set_sparse_matrix_cell_from_vector(deps, vector, buf[j * 3], &buf[j * 3 + 1]);
118 else if (cell.i32[0] == 0 || cell.i32[0] < buf[j * 3 + 1])
119 ccv_set_sparse_matrix_cell_from_vector(deps, vector, buf[j * 3], &buf[j * 3 + 1]);
120 else if (cell.i32[0] == buf[j * 3 + 1]) { // If we point to the same one, use the longest.
121 int p[2] = { cell.i32[0], ccv_max(buf[j * 3 + 2], cell.i32[1])({ typeof (buf[j * 3 + 2]) _a = (buf[j * 3 + 2]); typeof (cell
.i32[1]) _b = (cell.i32[1]); (_a > _b) ? _a : _b; })
};
122 ccv_set_sparse_matrix_cell_from_vector(deps, vector, buf[j * 3], &p);
123 }
124 }
125 }
126 }
127 } ccv_nnc_graph_visit_endfor} }
128#undef for_block
129 ccfreefree(buf);
130 ccv_nnc_exec_dep_t exec_dep = {
131 .chain_ids = chain_ids,
132 .chain_pos = chain_pos,
133 .deps = deps
134 };
135 return exec_dep;
136}
137
138int ccv_nnc_exec_dep_hop(const ccv_nnc_exec_dep_t exec_dep, const int d, ccv_sparse_matrix_vector_t* const vector, const int dd)
139{
140 // Check if dd is d's ancestor.
141 const int dd_chain_id = exec_dep.chain_ids[dd];
142 const int dd_chain_pos = exec_dep.chain_pos[dd];
143 if (exec_dep.chain_ids[d] == dd_chain_id)
144 return exec_dep.chain_pos[d] - dd_chain_pos;
145 const ccv_numeric_data_t cell = vector ? ccv_get_sparse_matrix_cell_from_vector(exec_dep.deps, vector, dd_chain_id) : ccv_get_sparse_matrix_cell(exec_dep.deps, d, dd_chain_id);
146 if (cell.i32 && cell.i32[0] > 0 && cell.i32[0] >= dd_chain_pos)
147 {
148 // Check if the chain pos is greater than or equal to dd_chain_pos. If it is, it is an ancestor.
149 return cell.i32[0] - dd_chain_pos + cell.i32[1];
150 }
151 return -1;
152}
153
154int ccv_nnc_exec_dep_check(const ccv_nnc_exec_dep_t exec_dep, const int d, const int dd)
155{
156 // Check if dd is d's ancestor.
157 const int dd_chain_id = exec_dep.chain_ids[dd];
158 const int dd_chain_pos = exec_dep.chain_pos[dd];
159 if (exec_dep.chain_ids[d] == dd_chain_id)
160 return exec_dep.chain_pos[d] > dd_chain_pos;
161 const ccv_numeric_data_t cell = ccv_get_sparse_matrix_cell(exec_dep.deps, d, dd_chain_id);
162 if (cell.i32 && cell.i32[0] > 0)
163 {
164 // Check if the chain pos is greater than or equal to dd_chain_pos. If it is, it is an ancestor.
165 return cell.i32[0] >= dd_chain_pos;
166 }
167 return 0;
168}
169
170void ccv_nnc_exec_dep_free(const ccv_nnc_exec_dep_t exec_dep)
171{
172 ccfreefree(exec_dep.chain_ids);
173 ccv_matrix_free(exec_dep.deps);
174}