@@ -23,7 +23,7 @@ predicate exprMayBeString(Expr exp) {
23
23
fctmp .getAnArgument ( ) .( VariableAccess ) .getTarget ( ) = exp .( VariableAccess ) .getTarget ( ) or
24
24
globalValueNumber ( fctmp .getAnArgument ( ) ) = globalValueNumber ( exp )
25
25
) and
26
- fctmp .getTarget ( ) .hasGlobalOrStdName ( [ "strlen" , "strcat" , "strncat" , "strcpy" , "sptintf" ] )
26
+ fctmp .getTarget ( ) .hasName ( [ "strlen" , "strcat" , "strncat" , "strcpy" , "sptintf" , "printf "] )
27
27
)
28
28
or
29
29
exists ( AssignExpr astmp |
@@ -62,48 +62,176 @@ predicate argMacro(Expr exp) {
62
62
)
63
63
}
64
64
65
- from FunctionCall fc , string msg
66
- where
67
- exists ( Loop lptmp | lptmp = fc .getEnclosingStmt ( ) .getParentStmt * ( ) ) and
68
- fc .getTarget ( ) .hasGlobalOrStdName ( [ "mbtowc" , "mbrtowc" ] ) and
69
- not fc .getArgument ( 0 ) .isConstant ( ) and
70
- not fc .getArgument ( 1 ) .isConstant ( ) and
71
- (
72
- exprMayBeString ( fc .getArgument ( 1 ) ) and
73
- argConstOrSizeof ( fc .getArgument ( 2 ) ) and
74
- fc .getArgument ( 2 ) .getValue ( ) .toInt ( ) < 5 and
75
- not argMacro ( fc .getArgument ( 2 ) ) and
76
- msg = "Size can be less than maximum character length, use macro MB_CUR_MAX."
77
- or
78
- not exprMayBeString ( fc .getArgument ( 1 ) ) and
65
+ /** Holds if erroneous situations of using functions `mbtowc` and `mbrtowc` are detected. */
66
+ predicate findUseCharacterConversion ( Expr exp , string msg ) {
67
+ exists ( FunctionCall fc |
68
+ fc = exp and
79
69
(
80
- argConstOrSizeof ( fc .getArgument ( 2 ) )
81
- or
82
- argMacro ( fc .getArgument ( 2 ) )
83
- or
84
- exists ( DecrementOperation dotmp |
85
- globalValueNumber ( dotmp .getAnOperand ( ) ) = globalValueNumber ( fc .getArgument ( 2 ) ) and
86
- not exists ( AssignSubExpr aetmp |
70
+ exists ( Loop lptmp | lptmp = fc .getEnclosingStmt ( ) .getParentStmt * ( ) ) and
71
+ fc .getTarget ( ) .hasName ( [ "mbtowc" , "mbrtowc" ] ) and
72
+ not fc .getArgument ( 0 ) .isConstant ( ) and
73
+ not fc .getArgument ( 1 ) .isConstant ( ) and
74
+ (
75
+ exprMayBeString ( fc .getArgument ( 1 ) ) and
76
+ argConstOrSizeof ( fc .getArgument ( 2 ) ) and
77
+ fc .getArgument ( 2 ) .getValue ( ) .toInt ( ) < 5 and
78
+ not argMacro ( fc .getArgument ( 2 ) ) and
79
+ msg = "Size can be less than maximum character length, use macro MB_CUR_MAX."
80
+ or
81
+ not exprMayBeString ( fc .getArgument ( 1 ) ) and
82
+ (
83
+ argConstOrSizeof ( fc .getArgument ( 2 ) )
84
+ or
85
+ argMacro ( fc .getArgument ( 2 ) )
86
+ or
87
+ exists ( DecrementOperation dotmp |
88
+ globalValueNumber ( dotmp .getAnOperand ( ) ) = globalValueNumber ( fc .getArgument ( 2 ) ) and
89
+ not exists ( AssignSubExpr aetmp |
90
+ (
91
+ aetmp .getLValue ( ) .( VariableAccess ) .getTarget ( ) =
92
+ fc .getArgument ( 2 ) .( VariableAccess ) .getTarget ( ) or
93
+ globalValueNumber ( aetmp .getLValue ( ) ) = globalValueNumber ( fc .getArgument ( 2 ) )
94
+ ) and
95
+ globalValueNumber ( aetmp .getRValue ( ) ) = globalValueNumber ( fc )
96
+ )
97
+ )
98
+ ) and
99
+ msg =
100
+ "Access beyond the allocated memory is possible, the length can change without changing the pointer."
101
+ or
102
+ exists ( AssignPointerAddExpr aetmp |
87
103
(
88
104
aetmp .getLValue ( ) .( VariableAccess ) .getTarget ( ) =
89
- fc .getArgument ( 2 ) .( VariableAccess ) .getTarget ( ) or
90
- globalValueNumber ( aetmp .getLValue ( ) ) = globalValueNumber ( fc .getArgument ( 2 ) )
105
+ fc .getArgument ( 0 ) .( VariableAccess ) .getTarget ( ) or
106
+ globalValueNumber ( aetmp .getLValue ( ) ) = globalValueNumber ( fc .getArgument ( 0 ) )
91
107
) and
92
108
globalValueNumber ( aetmp .getRValue ( ) ) = globalValueNumber ( fc )
93
- )
109
+ ) and
110
+ msg = "Maybe you're using the function's return value incorrectly."
94
111
)
95
- ) and
112
+ )
113
+ )
114
+ }
115
+
116
+ /** Holds if detecting erroneous situations of working with multibyte characters. */
117
+ predicate findUseMultibyteCharacter ( Expr exp , string msg ) {
118
+ exists ( ArrayType arrayType , ArrayExpr arrayExpr |
119
+ arrayExpr = exp and
120
+ arrayExpr .getArrayBase ( ) .( VariableAccess ) .getTarget ( ) .getADeclarationEntry ( ) .getType ( ) =
121
+ arrayType and
122
+ (
123
+ exists ( AssignExpr assZero , SizeofExprOperator sizeofArray , Expr oneValue |
124
+ oneValue .getValue ( ) = "1" and
125
+ sizeofArray .getExprOperand ( ) .getType ( ) = arrayType and
126
+ assZero .getLValue ( ) = arrayExpr and
127
+ arrayExpr .getArrayOffset ( ) .( SubExpr ) .hasOperands ( sizeofArray , oneValue ) and
128
+ assZero .getRValue ( ) .getValue ( ) = "0"
129
+ ) and
130
+ arrayType .getArraySize ( ) != arrayType .getByteSize ( ) and
131
+ msg =
132
+ "The size of the array element is greater than one byte, so the offset will point outside the array."
133
+ or
134
+ exists ( FunctionCall mbFunction |
135
+ (
136
+ mbFunction .getTarget ( ) .getName ( ) .matches ( "_mbs%" ) or
137
+ mbFunction .getTarget ( ) .getName ( ) .matches ( "mbs%" ) or
138
+ mbFunction .getTarget ( ) .getName ( ) .matches ( "_mbc%" ) or
139
+ mbFunction .getTarget ( ) .getName ( ) .matches ( "mbc%" )
140
+ ) and
141
+ mbFunction .getAnArgument ( ) .( VariableAccess ) .getTarget ( ) .getADeclarationEntry ( ) .getType ( ) =
142
+ arrayType
143
+ ) and
144
+ exists ( Loop loop , SizeofExprOperator sizeofArray , AssignExpr assignExpr |
145
+ arrayExpr .getEnclosingStmt ( ) .getParentStmt * ( ) = loop and
146
+ sizeofArray .getExprOperand ( ) .getType ( ) = arrayType and
147
+ assignExpr .getLValue ( ) = arrayExpr and
148
+ loop .getCondition ( ) .( LTExpr ) .getLeftOperand ( ) .( VariableAccess ) .getTarget ( ) =
149
+ arrayExpr .getArrayOffset ( ) .getAChild * ( ) .( VariableAccess ) .getTarget ( ) and
150
+ loop .getCondition ( ) .( LTExpr ) .getRightOperand ( ) = sizeofArray
151
+ ) and
152
+ msg =
153
+ "This buffer may contain multibyte characters, so attempting to copy may result in part of the last character being lost."
154
+ )
155
+ )
156
+ or
157
+ exists ( FunctionCall mbccpy , Loop loop , SizeofExprOperator sizeofOp |
158
+ mbccpy .getTarget ( ) .hasName ( "_mbccpy" ) and
159
+ mbccpy .getArgument ( 0 ) = exp and
160
+ exp .getEnclosingStmt ( ) .getParentStmt * ( ) = loop and
161
+ sizeofOp .getExprOperand ( ) .getType ( ) =
162
+ exp .getAChild * ( ) .( VariableAccess ) .getTarget ( ) .getADeclarationEntry ( ) .getType ( ) and
163
+ loop .getCondition ( ) .( LTExpr ) .getLeftOperand ( ) .( VariableAccess ) .getTarget ( ) =
164
+ exp .getAChild * ( ) .( VariableAccess ) .getTarget ( ) and
165
+ loop .getCondition ( ) .( LTExpr ) .getRightOperand ( ) = sizeofOp and
96
166
msg =
97
- "Access beyond the allocated memory is possible, the length can change without changing the pointer."
98
- or
99
- exists ( AssignPointerAddExpr aetmp |
167
+ "This buffer may contain multibyte characters, so an attempt to copy may result in an overflow."
168
+ )
169
+ }
170
+
171
+ /** Holds if erroneous situations of using functions `MultiByteToWideChar` and `WideCharToMultiByte` or `mbstowcs` and `_mbstowcs_l` and `mbsrtowcs` are detected. */
172
+ predicate findUseStringConversion (
173
+ Expr exp , string msg , int posBufSrc , int posBufDst , int posSizeDst , string nameCalls
174
+ ) {
175
+ exists ( FunctionCall fc |
176
+ fc = exp and
177
+ posBufSrc in [ 0 .. fc .getNumberOfArguments ( ) - 1 ] and
178
+ posSizeDst in [ 0 .. fc .getNumberOfArguments ( ) - 1 ] and
179
+ (
180
+ fc .getTarget ( ) .hasName ( nameCalls ) and
100
181
(
101
- aetmp .getLValue ( ) .( VariableAccess ) .getTarget ( ) =
102
- fc .getArgument ( 0 ) .( VariableAccess ) .getTarget ( ) or
103
- globalValueNumber ( aetmp .getLValue ( ) ) = globalValueNumber ( fc .getArgument ( 0 ) )
104
- ) and
105
- globalValueNumber ( aetmp .getRValue ( ) ) = globalValueNumber ( fc )
106
- ) and
107
- msg = "Maybe you're using the function's return value incorrectly."
182
+ globalValueNumber ( fc .getArgument ( posBufDst ) ) = globalValueNumber ( fc .getArgument ( posBufSrc ) ) and
183
+ msg =
184
+ "According to the definition of the functions, if the source buffer and the destination buffer are the same, undefined behavior is possible."
185
+ or
186
+ exists ( ArrayType arrayDst |
187
+ fc .getArgument ( posBufDst ) .( VariableAccess ) .getTarget ( ) .getADeclarationEntry ( ) .getType ( ) =
188
+ arrayDst and
189
+ fc .getArgument ( posSizeDst ) .getValue ( ) .toInt ( ) >= arrayDst .getArraySize ( ) and
190
+ not exists ( AssignExpr assZero |
191
+ assZero .getLValue ( ) .( ArrayExpr ) .getArrayBase ( ) .( VariableAccess ) .getTarget ( ) =
192
+ fc .getArgument ( posBufDst ) .( VariableAccess ) .getTarget ( ) and
193
+ assZero .getRValue ( ) .getValue ( ) = "0"
194
+ ) and
195
+ not exists ( Expr someExp , FunctionCall checkSize |
196
+ checkSize .getASuccessor * ( ) = fc and
197
+ checkSize .getTarget ( ) .hasName ( nameCalls ) and
198
+ checkSize .getArgument ( posSizeDst ) .getValue ( ) = "0" and
199
+ globalValueNumber ( checkSize ) = globalValueNumber ( someExp ) and
200
+ someExp .getEnclosingStmt ( ) .getParentStmt * ( ) instanceof IfStmt
201
+ ) and
202
+ exprMayBeString ( fc .getArgument ( posBufDst ) ) and
203
+ msg =
204
+ "According to the definition of the functions, it is not guaranteed to write a null character at the end of the string, so access beyond the bounds of the destination buffer is possible."
205
+ )
206
+ or
207
+ exists ( FunctionCall allocMem |
208
+ allocMem .getTarget ( ) .hasName ( [ "calloc" , "malloc" ] ) and
209
+ globalValueNumber ( fc .getArgument ( posBufDst ) ) = globalValueNumber ( allocMem ) and
210
+ (
211
+ allocMem .getArgument ( allocMem .getNumberOfArguments ( ) - 1 ) .getValue ( ) = "1" or
212
+ not exists ( SizeofOperator sizeofOperator |
213
+ globalValueNumber ( allocMem
214
+ .getArgument ( allocMem .getNumberOfArguments ( ) - 1 )
215
+ .getAChild * ( ) ) = globalValueNumber ( sizeofOperator )
216
+ )
217
+ ) and
218
+ msg =
219
+ "The buffer destination has a type other than char, you need to take this into account when allocating memory."
220
+ )
221
+ or
222
+ fc .getArgument ( posBufDst ) .getValue ( ) = "0" and
223
+ fc .getArgument ( posSizeDst ) .getValue ( ) != "0" and
224
+ msg =
225
+ "If the destination buffer is NULL and its size is not 0, then undefined behavior is possible."
226
+ )
227
+ )
108
228
)
109
- select fc , msg
229
+ }
230
+
231
+ from Expr exp , string msg
232
+ where
233
+ findUseCharacterConversion ( exp , msg ) or
234
+ findUseMultibyteCharacter ( exp , msg ) or
235
+ findUseStringConversion ( exp , msg , 1 , 0 , 2 , [ "mbstowcs" , "_mbstowcs_l" , "mbsrtowcs" ] ) or
236
+ findUseStringConversion ( exp , msg , 2 , 4 , 5 , [ "MultiByteToWideChar" , "WideCharToMultiByte" ] )
237
+ select exp , msg + exp .getEnclosingFunction ( ) .getName ( )
0 commit comments