Merge branch 'main' into oldpaths1 (some generated files are left unmerged).

This commit is contained in:
Geoffrey White
2025-08-27 16:56:06 +01:00
111 changed files with 1922 additions and 569 deletions

View File

@@ -0,0 +1,21 @@
extensions:
- addsTo:
pack: codeql/cpp-all
extensible: summaryModel
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
- ["Microsoft::WRL", "ComPtr", True, "ComPtr<T>", "(T *)", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["Microsoft::WRL", "ComPtr", True, "ComPtr", "(const ComPtr &)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["Microsoft::WRL", "ComPtr", True, "ComPtr", "(ComPtr &&)", "", "Argument[*0].Element[@]", "Argument[-1].Element[@]", "value", "manual"]
- ["Microsoft::WRL", "ComPtr", True, "As", "", "", "Argument[-1]", "Argument[*0]", "value", "manual"]
- ["Microsoft::WRL", "ComPtr", True, "AsIID", "", "", "Argument[-1]", "Argument[*1]", "value", "manual"]
- ["Microsoft::WRL", "ComPtr", True, "AsWeak", "", "", "Argument[-1]", "Argument[*0]", "value", "manual"]
- ["Microsoft::WRL", "ComPtr", True, "Attach", "", "", "Argument[*@0]", "Argument[-1].Element[@]", "value", "manual"]
- ["Microsoft::WRL", "ComPtr<T>", True, "CopyTo", "(T **)", "", "Argument[-1].Element[@]", "Argument[**@0]", "value", "manual"]
- ["Microsoft::WRL", "ComPtr", True, "CopyTo<T>", "(T **)", "", "Argument[-1].Element[@]", "Argument[**@0]", "value", "manual"]
- ["Microsoft::WRL", "ComPtr", True, "CopyTo", "(REFIID,void **)", "", "Argument[-1].Element[@]", "Argument[**@1]", "value", "manual"]
- ["Microsoft::WRL", "ComPtr", True, "Detach", "", "", "Argument[-1].Element[@]", "ReturnValue[*]", "value", "manual"]
- ["Microsoft::WRL", "ComPtr", True, "Get", "", "", "Argument[-1].Element[@]", "ReturnValue[*]", "value", "manual"]
- ["Microsoft::WRL", "ComPtr", True, "GetAddressOf", "", "", "Argument[-1].Element[@]", "ReturnValue[**]", "value", "manual"]
- ["Microsoft::WRL", "ComPtr", True, "ReleaseAndGetAddressOf", "", "", "Argument[-1].Element[@]", "ReturnValue[**]", "value", "manual"]
- ["Microsoft::WRL", "ComPtr", True, "Swap", "", "", "Argument[-1]", "Argument[*0]", "value", "manual"]
- ["Microsoft::WRL", "ComPtr", True, "Swap", "", "", "Argument[*0]", "Argument[-1]", "value", "manual"]

View File

@@ -147,8 +147,8 @@ module ExecTaintConfig implements DataFlow::StateConfigSig {
predicate isBarrier(DataFlow::Node node) { isBarrierImpl(node) } predicate isBarrier(DataFlow::Node node) { isBarrierImpl(node) }
predicate isBarrierOut(DataFlow::Node node) { predicate isBarrierOut(DataFlow::Node node, FlowState state) {
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers isSink(node, state) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
} }
predicate observeDiffInformedIncrementalMode() { any() } predicate observeDiffInformedIncrementalMode() { any() }

View File

@@ -503,6 +503,7 @@
| Dubious signature "(CURLU *,CURLUPart,const char *,unsigned int)" in summary model. | | Dubious signature "(CURLU *,CURLUPart,const char *,unsigned int)" in summary model. |
| Dubious signature "(CURLU *,const char *)" in summary model. | | Dubious signature "(CURLU *,const char *)" in summary model. |
| Dubious signature "(CURLU *,const char *,char **,OperationConfig *)" in summary model. | | Dubious signature "(CURLU *,const char *,char **,OperationConfig *)" in summary model. |
| Dubious signature "(ComPtr &&)" in summary model. |
| Dubious signature "(CompoundDictionary *,const PreparedDictionary *)" in summary model. | | Dubious signature "(CompoundDictionary *,const PreparedDictionary *)" in summary model. |
| Dubious signature "(Curl_cfilter *)" in summary model. | | Dubious signature "(Curl_cfilter *)" in summary model. |
| Dubious signature "(Curl_cfilter **,Curl_easy *)" in summary model. | | Dubious signature "(Curl_cfilter **,Curl_easy *)" in summary model. |
@@ -2130,6 +2131,7 @@
| Dubious signature "(RAND_POOL *,unsigned char *)" in summary model. | | Dubious signature "(RAND_POOL *,unsigned char *)" in summary model. |
| Dubious signature "(RAND_POOL *,unsigned int)" in summary model. | | Dubious signature "(RAND_POOL *,unsigned int)" in summary model. |
| Dubious signature "(RECORD_LAYER *,SSL_CONNECTION *)" in summary model. | | Dubious signature "(RECORD_LAYER *,SSL_CONNECTION *)" in summary model. |
| Dubious signature "(REFIID,void **)" in summary model. |
| Dubious signature "(RIO_NOTIFIER *)" in summary model. | | Dubious signature "(RIO_NOTIFIER *)" in summary model. |
| Dubious signature "(RIPEMD160_CTX *,const unsigned char *)" in summary model. | | Dubious signature "(RIPEMD160_CTX *,const unsigned char *)" in summary model. |
| Dubious signature "(RIPEMD160_CTX *,const void *,size_t)" in summary model. | | Dubious signature "(RIPEMD160_CTX *,const void *,size_t)" in summary model. |
@@ -2431,6 +2433,8 @@
| Dubious signature "(Strent *)" in summary model. | | Dubious signature "(Strent *)" in summary model. |
| Dubious signature "(Strtab *,const char *,size_t)" in summary model. | | Dubious signature "(Strtab *,const char *,size_t)" in summary model. |
| Dubious signature "(Strtab *,size_t *)" in summary model. | | Dubious signature "(Strtab *,size_t *)" in summary model. |
| Dubious signature "(T *)" in summary model. |
| Dubious signature "(T **)" in summary model. |
| Dubious signature "(TLS_FEATURE *)" in summary model. | | Dubious signature "(TLS_FEATURE *)" in summary model. |
| Dubious signature "(TLS_RL_RECORD *,const unsigned char *)" in summary model. | | Dubious signature "(TLS_RL_RECORD *,const unsigned char *)" in summary model. |
| Dubious signature "(TS_ACCURACY *)" in summary model. | | Dubious signature "(TS_ACCURACY *)" in summary model. |
@@ -3155,6 +3159,7 @@
| Dubious signature "(const CT_POLICY_EVAL_CTX *)" in summary model. | | Dubious signature "(const CT_POLICY_EVAL_CTX *)" in summary model. |
| Dubious signature "(const CURLU *)" in summary model. | | Dubious signature "(const CURLU *)" in summary model. |
| Dubious signature "(const CURLU *,CURLUPart,char **,unsigned int)" in summary model. | | Dubious signature "(const CURLU *,CURLUPart,char **,unsigned int)" in summary model. |
| Dubious signature "(const ComPtr &)" in summary model. |
| Dubious signature "(const Command *,const size_t,const BlockSplit *,const BlockSplit *,const BlockSplit *,const uint8_t *,size_t,size_t,uint8_t,uint8_t,const ContextType *,HistogramLiteral *,HistogramCommand *,HistogramDistance *)" in summary model. | | Dubious signature "(const Command *,const size_t,const BlockSplit *,const BlockSplit *,const BlockSplit *,const uint8_t *,size_t,size_t,uint8_t,uint8_t,const ContextType *,HistogramLiteral *,HistogramCommand *,HistogramDistance *)" in summary model. |
| Dubious signature "(const Curl_easy *,const connectdata *,int)" in summary model. | | Dubious signature "(const Curl_easy *,const connectdata *,int)" in summary model. |
| Dubious signature "(const DH *)" in summary model. | | Dubious signature "(const DH *)" in summary model. |

View File

@@ -1241,4 +1241,140 @@ namespace ATL {
sink(static_cast<CStrBufT<char>::PCXSTR>(b)); // $ ir sink(static_cast<CStrBufT<char>::PCXSTR>(b)); // $ ir
sink(static_cast<CStrBufT<char>::PXSTR>(b)); // $ ir sink(static_cast<CStrBufT<char>::PXSTR>(b)); // $ ir
} }
}
namespace Microsoft {
namespace WRL {
template <typename T>
class ComPtr;
struct GUID;
typedef GUID IID;
typedef IID *REFIID;
class IUnknown;
class WeakRef;
template <typename T>
class ComPtr
{
public:
using InterfaceType = T;
ComPtr();
ComPtr(const ComPtr &);
ComPtr(ComPtr &&);
template <typename U>
ComPtr(U *);
~ComPtr();
template <typename U>
HRESULT As(ComPtr<U> *p) const;
HRESULT AsWeak(WeakRef *);
void Attach(InterfaceType *);
HRESULT CopyTo(InterfaceType **);
HRESULT CopyTo(REFIID, void **) const;
template <typename U>
HRESULT CopyTo(U **) const;
T *Detach();
T *Get() const;
T *const *GetAddressOf() const;
T **GetAddressOf();
T **ReleaseAndGetAddressOf();
unsigned long Reset();
void Swap(ComPtr &&r);
void Swap(ComPtr &r);
};
}
}
namespace std {
template<class T> T&& move(T& t) noexcept; // simplified signature
}
void test_constructor()
{
Microsoft::WRL::ComPtr<int> p0;
sink(*p0.Get()); // clean
int x = source<int>();
Microsoft::WRL::ComPtr<int> p1(new int(x));
sink(*p1.Get()); // $ ir MISSING: ast
sink(*p1.Detach()); // $ ir MISSING: ast
Microsoft::WRL::ComPtr<int> p2(p1);
sink(*p2.Get()); // $ ir MISSING: ast
Microsoft::WRL::ComPtr<int> p3(std::move(p1));
sink(*p3.Get()); // $ ir MISSING: ast
}
void test_As()
{
int x = source<int>();
Microsoft::WRL::ComPtr<int> p1(new int(x));
Microsoft::WRL::ComPtr<int> p2;
p1.As(&p2);
sink(*p2.Get()); // $ ir MISSING: ast
}
void test_CopyTo()
{
int x = source<int>();
Microsoft::WRL::ComPtr<int> p1(new int(x));
int *raw = nullptr;
p1.CopyTo(&raw);
sink(*raw); // $ ir MISSING: ast
Microsoft::WRL::ComPtr<int> p2;
p1.CopyTo(nullptr, (void**)&raw);
sink(*raw); // $ ir MISSING: ast
Microsoft::WRL::ComPtr<int> p3(new int(x));
int* raw2 = nullptr;
p3.CopyTo<int>(&raw2);
sink(*raw2); // $ ir MISSING: ast
}
void test_Swap()
{
int x = source<int>();
Microsoft::WRL::ComPtr<int> p1(new int(x));
Microsoft::WRL::ComPtr<int> p2;
p1.Swap(p2);
sink(*p2.Get()); // $ ir MISSING: ast
sink(*p1.Get()); // $ SPURIOUS: ir
}
void test_GetAddressOf()
{
int x = source<int>();
Microsoft::WRL::ComPtr<int> p1(new int(x));
sink(**p1.GetAddressOf()); // $ ir MISSING: ast
const Microsoft::WRL::ComPtr<int> p2(new int(x));
sink(**p2.GetAddressOf()); // $ ir MISSING: ast
Microsoft::WRL::ComPtr<int> p3(new int(x));
int **pp = p3.ReleaseAndGetAddressOf();
sink(**pp); // $ ir MISSING: ast
} }

View File

@@ -1278,6 +1278,131 @@ WARNING: module 'TaintTracking' has been deprecated and may be removed in future
| atl.cpp:1240:22:1240:30 | call to CStrBufT | atl.cpp:1241:46:1241:46 | b | | | atl.cpp:1240:22:1240:30 | call to CStrBufT | atl.cpp:1241:46:1241:46 | b | |
| atl.cpp:1240:22:1240:30 | call to CStrBufT | atl.cpp:1242:45:1242:45 | b | | | atl.cpp:1240:22:1240:30 | call to CStrBufT | atl.cpp:1242:45:1242:45 | b | |
| atl.cpp:1241:46:1241:46 | ref arg b | atl.cpp:1242:45:1242:45 | b | | | atl.cpp:1241:46:1241:46 | ref arg b | atl.cpp:1242:45:1242:45 | b | |
| atl.cpp:1315:31:1315:32 | call to ComPtr | atl.cpp:1316:9:1316:10 | p0 | |
| atl.cpp:1315:31:1315:32 | call to ComPtr | atl.cpp:1328:1:1328:1 | p0 | |
| atl.cpp:1316:9:1316:10 | ref arg p0 | atl.cpp:1328:1:1328:1 | p0 | |
| atl.cpp:1316:12:1316:14 | call to Get | atl.cpp:1316:8:1316:16 | * ... | TAINT |
| atl.cpp:1318:11:1318:21 | call to source | atl.cpp:1319:42:1319:42 | x | |
| atl.cpp:1319:34:1319:43 | new | atl.cpp:1319:34:1319:44 | call to ComPtr | TAINT |
| atl.cpp:1319:34:1319:44 | call to ComPtr | atl.cpp:1320:9:1320:10 | p1 | |
| atl.cpp:1319:34:1319:44 | call to ComPtr | atl.cpp:1321:9:1321:10 | p1 | |
| atl.cpp:1319:34:1319:44 | call to ComPtr | atl.cpp:1323:34:1323:35 | p1 | |
| atl.cpp:1319:34:1319:44 | call to ComPtr | atl.cpp:1326:44:1326:45 | p1 | |
| atl.cpp:1319:34:1319:44 | call to ComPtr | atl.cpp:1328:1:1328:1 | p1 | |
| atl.cpp:1319:42:1319:42 | x | atl.cpp:1319:34:1319:43 | new | |
| atl.cpp:1320:9:1320:10 | ref arg p1 | atl.cpp:1321:9:1321:10 | p1 | |
| atl.cpp:1320:9:1320:10 | ref arg p1 | atl.cpp:1323:34:1323:35 | p1 | |
| atl.cpp:1320:9:1320:10 | ref arg p1 | atl.cpp:1326:44:1326:45 | p1 | |
| atl.cpp:1320:9:1320:10 | ref arg p1 | atl.cpp:1328:1:1328:1 | p1 | |
| atl.cpp:1320:12:1320:14 | call to Get | atl.cpp:1320:8:1320:16 | * ... | TAINT |
| atl.cpp:1321:9:1321:10 | ref arg p1 | atl.cpp:1323:34:1323:35 | p1 | |
| atl.cpp:1321:9:1321:10 | ref arg p1 | atl.cpp:1326:44:1326:45 | p1 | |
| atl.cpp:1321:9:1321:10 | ref arg p1 | atl.cpp:1328:1:1328:1 | p1 | |
| atl.cpp:1321:12:1321:17 | call to Detach | atl.cpp:1321:8:1321:19 | * ... | TAINT |
| atl.cpp:1323:34:1323:35 | p1 | atl.cpp:1323:34:1323:36 | call to ComPtr | |
| atl.cpp:1323:34:1323:36 | call to ComPtr | atl.cpp:1324:9:1324:10 | p2 | |
| atl.cpp:1323:34:1323:36 | call to ComPtr | atl.cpp:1328:1:1328:1 | p2 | |
| atl.cpp:1324:9:1324:10 | ref arg p2 | atl.cpp:1328:1:1328:1 | p2 | |
| atl.cpp:1324:12:1324:14 | call to Get | atl.cpp:1324:8:1324:16 | * ... | TAINT |
| atl.cpp:1326:34:1326:42 | call to move | atl.cpp:1326:34:1326:47 | call to ComPtr | TAINT |
| atl.cpp:1326:34:1326:42 | ref arg call to move | atl.cpp:1326:44:1326:45 | p1 [inner post update] | |
| atl.cpp:1326:34:1326:42 | ref arg call to move | atl.cpp:1328:1:1328:1 | p1 | |
| atl.cpp:1326:34:1326:47 | call to ComPtr | atl.cpp:1327:9:1327:10 | p3 | |
| atl.cpp:1326:34:1326:47 | call to ComPtr | atl.cpp:1328:1:1328:1 | p3 | |
| atl.cpp:1326:44:1326:45 | p1 | atl.cpp:1326:34:1326:42 | call to move | TAINT |
| atl.cpp:1326:44:1326:45 | p1 | atl.cpp:1326:34:1326:47 | call to ComPtr | |
| atl.cpp:1327:9:1327:10 | ref arg p3 | atl.cpp:1328:1:1328:1 | p3 | |
| atl.cpp:1327:12:1327:14 | call to Get | atl.cpp:1327:8:1327:16 | * ... | TAINT |
| atl.cpp:1332:11:1332:21 | call to source | atl.cpp:1333:42:1333:42 | x | |
| atl.cpp:1333:34:1333:43 | new | atl.cpp:1333:34:1333:44 | call to ComPtr | TAINT |
| atl.cpp:1333:34:1333:44 | call to ComPtr | atl.cpp:1335:3:1335:4 | p1 | |
| atl.cpp:1333:34:1333:44 | call to ComPtr | atl.cpp:1337:1:1337:1 | p1 | |
| atl.cpp:1333:42:1333:42 | x | atl.cpp:1333:34:1333:43 | new | |
| atl.cpp:1334:31:1334:32 | call to ComPtr | atl.cpp:1335:10:1335:11 | p2 | |
| atl.cpp:1334:31:1334:32 | call to ComPtr | atl.cpp:1336:9:1336:10 | p2 | |
| atl.cpp:1334:31:1334:32 | call to ComPtr | atl.cpp:1337:1:1337:1 | p2 | |
| atl.cpp:1335:9:1335:11 | ref arg & ... | atl.cpp:1335:10:1335:11 | p2 [inner post update] | |
| atl.cpp:1335:9:1335:11 | ref arg & ... | atl.cpp:1336:9:1336:10 | p2 | |
| atl.cpp:1335:9:1335:11 | ref arg & ... | atl.cpp:1337:1:1337:1 | p2 | |
| atl.cpp:1335:10:1335:11 | p2 | atl.cpp:1335:9:1335:11 | & ... | |
| atl.cpp:1336:9:1336:10 | ref arg p2 | atl.cpp:1337:1:1337:1 | p2 | |
| atl.cpp:1336:12:1336:14 | call to Get | atl.cpp:1336:8:1336:16 | * ... | TAINT |
| atl.cpp:1341:11:1341:21 | call to source | atl.cpp:1342:42:1342:42 | x | |
| atl.cpp:1341:11:1341:21 | call to source | atl.cpp:1351:42:1351:42 | x | |
| atl.cpp:1342:34:1342:43 | new | atl.cpp:1342:34:1342:44 | call to ComPtr | TAINT |
| atl.cpp:1342:34:1342:44 | call to ComPtr | atl.cpp:1344:3:1344:4 | p1 | |
| atl.cpp:1342:34:1342:44 | call to ComPtr | atl.cpp:1348:3:1348:4 | p1 | |
| atl.cpp:1342:34:1342:44 | call to ComPtr | atl.cpp:1356:1:1356:1 | p1 | |
| atl.cpp:1342:42:1342:42 | x | atl.cpp:1342:34:1342:43 | new | |
| atl.cpp:1343:14:1343:20 | 0 | atl.cpp:1344:14:1344:16 | raw | |
| atl.cpp:1343:14:1343:20 | 0 | atl.cpp:1345:9:1345:11 | raw | |
| atl.cpp:1343:14:1343:20 | 0 | atl.cpp:1348:31:1348:33 | raw | |
| atl.cpp:1343:14:1343:20 | 0 | atl.cpp:1349:9:1349:11 | raw | |
| atl.cpp:1344:3:1344:4 | ref arg p1 | atl.cpp:1348:3:1348:4 | p1 | |
| atl.cpp:1344:3:1344:4 | ref arg p1 | atl.cpp:1356:1:1356:1 | p1 | |
| atl.cpp:1344:13:1344:16 | ref arg & ... | atl.cpp:1344:14:1344:16 | raw [inner post update] | |
| atl.cpp:1344:13:1344:16 | ref arg & ... | atl.cpp:1345:9:1345:11 | raw | |
| atl.cpp:1344:13:1344:16 | ref arg & ... | atl.cpp:1348:31:1348:33 | raw | |
| atl.cpp:1344:13:1344:16 | ref arg & ... | atl.cpp:1349:9:1349:11 | raw | |
| atl.cpp:1344:14:1344:16 | raw | atl.cpp:1344:13:1344:16 | & ... | |
| atl.cpp:1345:9:1345:11 | raw | atl.cpp:1345:8:1345:11 | * ... | TAINT |
| atl.cpp:1347:31:1347:32 | call to ComPtr | atl.cpp:1356:1:1356:1 | p2 | |
| atl.cpp:1348:30:1348:33 | ref arg & ... | atl.cpp:1348:31:1348:33 | raw [inner post update] | |
| atl.cpp:1348:30:1348:33 | ref arg & ... | atl.cpp:1349:9:1349:11 | raw | |
| atl.cpp:1348:31:1348:33 | raw | atl.cpp:1348:30:1348:33 | & ... | |
| atl.cpp:1349:9:1349:11 | raw | atl.cpp:1349:8:1349:11 | * ... | TAINT |
| atl.cpp:1351:34:1351:43 | new | atl.cpp:1351:34:1351:44 | call to ComPtr | TAINT |
| atl.cpp:1351:34:1351:44 | call to ComPtr | atl.cpp:1354:3:1354:4 | p3 | |
| atl.cpp:1351:34:1351:44 | call to ComPtr | atl.cpp:1356:1:1356:1 | p3 | |
| atl.cpp:1351:42:1351:42 | x | atl.cpp:1351:34:1351:43 | new | |
| atl.cpp:1353:15:1353:21 | 0 | atl.cpp:1354:19:1354:22 | raw2 | |
| atl.cpp:1353:15:1353:21 | 0 | atl.cpp:1355:9:1355:12 | raw2 | |
| atl.cpp:1354:18:1354:22 | ref arg & ... | atl.cpp:1354:19:1354:22 | raw2 [inner post update] | |
| atl.cpp:1354:18:1354:22 | ref arg & ... | atl.cpp:1355:9:1355:12 | raw2 | |
| atl.cpp:1354:19:1354:22 | raw2 | atl.cpp:1354:18:1354:22 | & ... | |
| atl.cpp:1355:9:1355:12 | raw2 | atl.cpp:1355:8:1355:12 | * ... | TAINT |
| atl.cpp:1360:11:1360:21 | call to source | atl.cpp:1361:42:1361:42 | x | |
| atl.cpp:1361:34:1361:43 | new | atl.cpp:1361:34:1361:44 | call to ComPtr | TAINT |
| atl.cpp:1361:34:1361:44 | call to ComPtr | atl.cpp:1363:3:1363:4 | p1 | |
| atl.cpp:1361:34:1361:44 | call to ComPtr | atl.cpp:1365:9:1365:10 | p1 | |
| atl.cpp:1361:34:1361:44 | call to ComPtr | atl.cpp:1366:1:1366:1 | p1 | |
| atl.cpp:1361:42:1361:42 | x | atl.cpp:1361:34:1361:43 | new | |
| atl.cpp:1362:31:1362:32 | call to ComPtr | atl.cpp:1363:11:1363:12 | p2 | |
| atl.cpp:1362:31:1362:32 | call to ComPtr | atl.cpp:1364:9:1364:10 | p2 | |
| atl.cpp:1362:31:1362:32 | call to ComPtr | atl.cpp:1366:1:1366:1 | p2 | |
| atl.cpp:1363:3:1363:4 | ref arg p1 | atl.cpp:1365:9:1365:10 | p1 | |
| atl.cpp:1363:3:1363:4 | ref arg p1 | atl.cpp:1366:1:1366:1 | p1 | |
| atl.cpp:1363:11:1363:12 | ref arg p2 | atl.cpp:1364:9:1364:10 | p2 | |
| atl.cpp:1363:11:1363:12 | ref arg p2 | atl.cpp:1366:1:1366:1 | p2 | |
| atl.cpp:1364:9:1364:10 | ref arg p2 | atl.cpp:1366:1:1366:1 | p2 | |
| atl.cpp:1364:12:1364:14 | call to Get | atl.cpp:1364:8:1364:16 | * ... | TAINT |
| atl.cpp:1365:9:1365:10 | ref arg p1 | atl.cpp:1366:1:1366:1 | p1 | |
| atl.cpp:1365:12:1365:14 | call to Get | atl.cpp:1365:8:1365:16 | * ... | TAINT |
| atl.cpp:1370:11:1370:21 | call to source | atl.cpp:1371:42:1371:42 | x | |
| atl.cpp:1370:11:1370:21 | call to source | atl.cpp:1374:48:1374:48 | x | |
| atl.cpp:1370:11:1370:21 | call to source | atl.cpp:1377:42:1377:42 | x | |
| atl.cpp:1371:34:1371:43 | new | atl.cpp:1371:34:1371:44 | call to ComPtr | TAINT |
| atl.cpp:1371:34:1371:44 | call to ComPtr | atl.cpp:1372:10:1372:11 | p1 | |
| atl.cpp:1371:34:1371:44 | call to ComPtr | atl.cpp:1380:1:1380:1 | p1 | |
| atl.cpp:1371:42:1371:42 | x | atl.cpp:1371:34:1371:43 | new | |
| atl.cpp:1372:9:1372:26 | * ... | atl.cpp:1372:8:1372:26 | * ... | TAINT |
| atl.cpp:1372:10:1372:11 | ref arg p1 | atl.cpp:1380:1:1380:1 | p1 | |
| atl.cpp:1372:13:1372:24 | call to GetAddressOf | atl.cpp:1372:9:1372:26 | * ... | TAINT |
| atl.cpp:1374:40:1374:49 | new | atl.cpp:1374:40:1374:50 | call to ComPtr | TAINT |
| atl.cpp:1374:40:1374:50 | call to ComPtr | atl.cpp:1375:10:1375:11 | p2 | |
| atl.cpp:1374:40:1374:50 | call to ComPtr | atl.cpp:1380:1:1380:1 | p2 | |
| atl.cpp:1374:48:1374:48 | x | atl.cpp:1374:40:1374:49 | new | |
| atl.cpp:1375:9:1375:26 | * ... | atl.cpp:1375:8:1375:26 | * ... | TAINT |
| atl.cpp:1375:10:1375:11 | ref arg p2 | atl.cpp:1380:1:1380:1 | p2 | |
| atl.cpp:1375:13:1375:24 | call to GetAddressOf | atl.cpp:1375:9:1375:26 | * ... | TAINT |
| atl.cpp:1377:34:1377:43 | new | atl.cpp:1377:34:1377:44 | call to ComPtr | TAINT |
| atl.cpp:1377:34:1377:44 | call to ComPtr | atl.cpp:1378:14:1378:15 | p3 | |
| atl.cpp:1377:34:1377:44 | call to ComPtr | atl.cpp:1380:1:1380:1 | p3 | |
| atl.cpp:1377:42:1377:42 | x | atl.cpp:1377:34:1377:43 | new | |
| atl.cpp:1378:14:1378:15 | ref arg p3 | atl.cpp:1380:1:1380:1 | p3 | |
| atl.cpp:1378:17:1378:38 | call to ReleaseAndGetAddressOf | atl.cpp:1379:10:1379:11 | pp | |
| atl.cpp:1379:9:1379:11 | * ... | atl.cpp:1379:8:1379:11 | * ... | TAINT |
| atl.cpp:1379:10:1379:11 | pp | atl.cpp:1379:9:1379:11 | * ... | TAINT |
| bsd.cpp:17:11:17:16 | call to source | bsd.cpp:20:18:20:18 | s | | | bsd.cpp:17:11:17:16 | call to source | bsd.cpp:20:18:20:18 | s | |
| bsd.cpp:18:12:18:15 | addr | bsd.cpp:20:22:20:25 | addr | | | bsd.cpp:18:12:18:15 | addr | bsd.cpp:20:22:20:25 | addr | |
| bsd.cpp:18:12:18:15 | addr | bsd.cpp:23:8:23:11 | addr | | | bsd.cpp:18:12:18:15 | addr | bsd.cpp:23:8:23:11 | addr | |

View File

@@ -5567,6 +5567,15 @@ signatureMatches
| atl.cpp:1231:5:1231:12 | CStrBufT | (const char *,const char *,unsigned long) | | __ngettext | 2 | | atl.cpp:1231:5:1231:12 | CStrBufT | (const char *,const char *,unsigned long) | | __ngettext | 2 |
| atl.cpp:1231:5:1231:12 | CStrBufT | (unsigned char *,int,unsigned long) | | UTF8_putc | 1 | | atl.cpp:1231:5:1231:12 | CStrBufT | (unsigned char *,int,unsigned long) | | UTF8_putc | 1 |
| atl.cpp:1231:5:1231:12 | CStrBufT | (unsigned char *,int,unsigned long) | | UTF8_putc | 2 | | atl.cpp:1231:5:1231:12 | CStrBufT | (unsigned char *,int,unsigned long) | | UTF8_putc | 2 |
| atl.cpp:1268:5:1268:10 | ComPtr | (const ComPtr &) | ComPtr | ComPtr | 0 |
| atl.cpp:1269:5:1269:10 | ComPtr | (ComPtr &&) | ComPtr | ComPtr | 0 |
| atl.cpp:1272:5:1272:10 | ComPtr | (T *) | ComPtr | ComPtr<T> | 0 |
| atl.cpp:1283:13:1283:18 | CopyTo | (T **) | ComPtr<T> | CopyTo | 0 |
| atl.cpp:1285:13:1285:18 | CopyTo | (Curl_easy *,void **) | | Curl_resolver_init | 1 |
| atl.cpp:1285:13:1285:18 | CopyTo | (REFIID,void **) | ComPtr | CopyTo | 0 |
| atl.cpp:1285:13:1285:18 | CopyTo | (REFIID,void **) | ComPtr | CopyTo | 1 |
| atl.cpp:1285:13:1285:18 | CopyTo | (size_t,void **) | | __libc_alloc_buffer_allocate | 1 |
| atl.cpp:1288:13:1288:18 | CopyTo | (T **) | ComPtr | CopyTo<T> | 0 |
| bsd.cpp:12:5:12:10 | accept | (CURLM *,curl_socket_t,int *) | | curl_multi_socket | 2 | | bsd.cpp:12:5:12:10 | accept | (CURLM *,curl_socket_t,int *) | | curl_multi_socket | 2 |
| bsd.cpp:12:5:12:10 | accept | (Curl_easy *,ssize_t *,int *) | | Curl_GetFTPResponse | 2 | | bsd.cpp:12:5:12:10 | accept | (Curl_easy *,ssize_t *,int *) | | Curl_GetFTPResponse | 2 |
| bsd.cpp:12:5:12:10 | accept | (EVP_CIPHER_CTX *,unsigned char *,int *) | | EVP_CipherFinal | 2 | | bsd.cpp:12:5:12:10 | accept | (EVP_CIPHER_CTX *,unsigned char *,int *) | | EVP_CipherFinal | 2 |
@@ -21750,6 +21759,7 @@ getSignatureParameterName
| (CURLU *,const char *,char **,OperationConfig *) | | ipfs_url_rewrite | 1 | const char * | | (CURLU *,const char *,char **,OperationConfig *) | | ipfs_url_rewrite | 1 | const char * |
| (CURLU *,const char *,char **,OperationConfig *) | | ipfs_url_rewrite | 2 | char ** | | (CURLU *,const char *,char **,OperationConfig *) | | ipfs_url_rewrite | 2 | char ** |
| (CURLU *,const char *,char **,OperationConfig *) | | ipfs_url_rewrite | 3 | OperationConfig * | | (CURLU *,const char *,char **,OperationConfig *) | | ipfs_url_rewrite | 3 | OperationConfig * |
| (ComPtr &&) | ComPtr | ComPtr | 0 | ComPtr && |
| (CompoundDictionary *,const PreparedDictionary *) | | AttachPreparedDictionary | 0 | CompoundDictionary * | | (CompoundDictionary *,const PreparedDictionary *) | | AttachPreparedDictionary | 0 | CompoundDictionary * |
| (CompoundDictionary *,const PreparedDictionary *) | | AttachPreparedDictionary | 1 | const PreparedDictionary * | | (CompoundDictionary *,const PreparedDictionary *) | | AttachPreparedDictionary | 1 | const PreparedDictionary * |
| (Curl_cfilter *) | | Curl_conn_cf_is_ssl | 0 | Curl_cfilter * | | (Curl_cfilter *) | | Curl_conn_cf_is_ssl | 0 | Curl_cfilter * |
@@ -28580,6 +28590,8 @@ getSignatureParameterName
| (RAND_POOL *,unsigned int) | | ossl_rand_pool_bytes_needed | 1 | unsigned int | | (RAND_POOL *,unsigned int) | | ossl_rand_pool_bytes_needed | 1 | unsigned int |
| (RECORD_LAYER *,SSL_CONNECTION *) | | RECORD_LAYER_init | 0 | RECORD_LAYER * | | (RECORD_LAYER *,SSL_CONNECTION *) | | RECORD_LAYER_init | 0 | RECORD_LAYER * |
| (RECORD_LAYER *,SSL_CONNECTION *) | | RECORD_LAYER_init | 1 | SSL_CONNECTION * | | (RECORD_LAYER *,SSL_CONNECTION *) | | RECORD_LAYER_init | 1 | SSL_CONNECTION * |
| (REFIID,void **) | ComPtr | CopyTo | 0 | REFIID |
| (REFIID,void **) | ComPtr | CopyTo | 1 | void ** |
| (RIO_NOTIFIER *) | | ossl_rio_notifier_cleanup | 0 | RIO_NOTIFIER * | | (RIO_NOTIFIER *) | | ossl_rio_notifier_cleanup | 0 | RIO_NOTIFIER * |
| (RIPEMD160_CTX *,const unsigned char *) | | RIPEMD160_Transform | 0 | RIPEMD160_CTX * | | (RIPEMD160_CTX *,const unsigned char *) | | RIPEMD160_Transform | 0 | RIPEMD160_CTX * |
| (RIPEMD160_CTX *,const unsigned char *) | | RIPEMD160_Transform | 1 | const unsigned char * | | (RIPEMD160_CTX *,const unsigned char *) | | RIPEMD160_Transform | 1 | const unsigned char * |
@@ -30163,6 +30175,9 @@ getSignatureParameterName
| (Strtab *,const char *,size_t) | | strtabadd | 2 | size_t | | (Strtab *,const char *,size_t) | | strtabadd | 2 | size_t |
| (Strtab *,size_t *) | | strtabfinalize | 0 | Strtab * | | (Strtab *,size_t *) | | strtabfinalize | 0 | Strtab * |
| (Strtab *,size_t *) | | strtabfinalize | 1 | size_t * | | (Strtab *,size_t *) | | strtabfinalize | 1 | size_t * |
| (T *) | ComPtr | ComPtr<T> | 0 | func:0 * |
| (T **) | ComPtr | CopyTo<T> | 0 | func:0 ** |
| (T **) | ComPtr<T> | CopyTo | 0 | class:0 ** |
| (TLS_FEATURE *) | | TLS_FEATURE_free | 0 | TLS_FEATURE * | | (TLS_FEATURE *) | | TLS_FEATURE_free | 0 | TLS_FEATURE * |
| (TLS_RL_RECORD *,const unsigned char *) | | ossl_tls_rl_record_set_seq_num | 0 | TLS_RL_RECORD * | | (TLS_RL_RECORD *,const unsigned char *) | | ossl_tls_rl_record_set_seq_num | 0 | TLS_RL_RECORD * |
| (TLS_RL_RECORD *,const unsigned char *) | | ossl_tls_rl_record_set_seq_num | 1 | const unsigned char * | | (TLS_RL_RECORD *,const unsigned char *) | | ossl_tls_rl_record_set_seq_num | 1 | const unsigned char * |
@@ -33305,6 +33320,7 @@ getSignatureParameterName
| (const CURLU *,CURLUPart,char **,unsigned int) | | curl_url_get | 1 | CURLUPart | | (const CURLU *,CURLUPart,char **,unsigned int) | | curl_url_get | 1 | CURLUPart |
| (const CURLU *,CURLUPart,char **,unsigned int) | | curl_url_get | 2 | char ** | | (const CURLU *,CURLUPart,char **,unsigned int) | | curl_url_get | 2 | char ** |
| (const CURLU *,CURLUPart,char **,unsigned int) | | curl_url_get | 3 | unsigned int | | (const CURLU *,CURLUPart,char **,unsigned int) | | curl_url_get | 3 | unsigned int |
| (const ComPtr &) | ComPtr | ComPtr | 0 | const ComPtr & |
| (const Command *,const size_t,const BlockSplit *,const BlockSplit *,const BlockSplit *,const uint8_t *,size_t,size_t,uint8_t,uint8_t,const ContextType *,HistogramLiteral *,HistogramCommand *,HistogramDistance *) | | BrotliBuildHistogramsWithContext | 0 | const Command * | | (const Command *,const size_t,const BlockSplit *,const BlockSplit *,const BlockSplit *,const uint8_t *,size_t,size_t,uint8_t,uint8_t,const ContextType *,HistogramLiteral *,HistogramCommand *,HistogramDistance *) | | BrotliBuildHistogramsWithContext | 0 | const Command * |
| (const Command *,const size_t,const BlockSplit *,const BlockSplit *,const BlockSplit *,const uint8_t *,size_t,size_t,uint8_t,uint8_t,const ContextType *,HistogramLiteral *,HistogramCommand *,HistogramDistance *) | | BrotliBuildHistogramsWithContext | 1 | const size_t | | (const Command *,const size_t,const BlockSplit *,const BlockSplit *,const BlockSplit *,const uint8_t *,size_t,size_t,uint8_t,uint8_t,const ContextType *,HistogramLiteral *,HistogramCommand *,HistogramDistance *) | | BrotliBuildHistogramsWithContext | 1 | const size_t |
| (const Command *,const size_t,const BlockSplit *,const BlockSplit *,const BlockSplit *,const uint8_t *,size_t,size_t,uint8_t,uint8_t,const ContextType *,HistogramLiteral *,HistogramCommand *,HistogramDistance *) | | BrotliBuildHistogramsWithContext | 2 | const BlockSplit * | | (const Command *,const size_t,const BlockSplit *,const BlockSplit *,const BlockSplit *,const uint8_t *,size_t,size_t,uint8_t,uint8_t,const ContextType *,HistogramLiteral *,HistogramCommand *,HistogramDistance *) | | BrotliBuildHistogramsWithContext | 2 | const BlockSplit * |
@@ -46404,6 +46420,18 @@ getParameterTypeName
| atl.cpp:1231:5:1231:12 | CStrBufT | 1 | int | | atl.cpp:1231:5:1231:12 | CStrBufT | 1 | int |
| atl.cpp:1231:5:1231:12 | CStrBufT | 2 | DWORD | | atl.cpp:1231:5:1231:12 | CStrBufT | 2 | DWORD |
| atl.cpp:1231:5:1231:12 | CStrBufT | 2 | unsigned long | | atl.cpp:1231:5:1231:12 | CStrBufT | 2 | unsigned long |
| atl.cpp:1268:5:1268:10 | ComPtr | 0 | const ComPtr & |
| atl.cpp:1269:5:1269:10 | ComPtr | 0 | ComPtr && |
| atl.cpp:1272:5:1272:10 | ComPtr | 0 | func:0 * |
| atl.cpp:1277:13:1277:14 | As | 0 | ComPtr * |
| atl.cpp:1283:13:1283:18 | CopyTo | 0 | Interfaceclass:0ype ** |
| atl.cpp:1283:13:1283:18 | CopyTo | 0 | class:0 ** |
| atl.cpp:1285:13:1285:18 | CopyTo | 0 | GUID * |
| atl.cpp:1285:13:1285:18 | CopyTo | 0 | REFIID |
| atl.cpp:1285:13:1285:18 | CopyTo | 1 | void ** |
| atl.cpp:1288:13:1288:18 | CopyTo | 0 | func:0 ** |
| atl.cpp:1303:10:1303:13 | Swap | 0 | ComPtr & |
| atl.cpp:1310:25:1310:28 | move | 0 | func:0 & |
| bsd.cpp:6:8:6:8 | operator= | 0 | const sockaddr & | | bsd.cpp:6:8:6:8 | operator= | 0 | const sockaddr & |
| bsd.cpp:6:8:6:8 | operator= | 0 | sockaddr && | | bsd.cpp:6:8:6:8 | operator= | 0 | sockaddr && |
| bsd.cpp:12:5:12:10 | accept | 0 | int | | bsd.cpp:12:5:12:10 | accept | 0 | int |

View File

@@ -0,0 +1,108 @@
.. _codeql-cli-2.22.4:
==========================
CodeQL 2.22.4 (2025-08-21)
==========================
.. contents:: Contents
:depth: 2
:local:
:backlinks: none
This is an overview of changes in the CodeQL CLI and relevant CodeQL query and library packs. For additional updates on changes to the CodeQL code scanning experience, check out the `code scanning section on the GitHub blog <https://github.blog/tag/code-scanning/>`__, `relevant GitHub Changelog updates <https://github.blog/changelog/label/code-scanning/>`__, `changes in the CodeQL extension for Visual Studio Code <https://marketplace.visualstudio.com/items/GitHub.vscode-codeql/changelog>`__, and the `CodeQL Action changelog <https://github.com/github/codeql-action/blob/main/CHANGELOG.md>`__.
Security Coverage
-----------------
CodeQL 2.22.4 runs a total of 478 security queries when configured with the Default suite (covering 169 CWE). The Extended suite enables an additional 130 queries (covering 32 more CWE). 2 security queries have been added with this release.
CodeQL CLI
----------
There are no user-facing CLI changes in this release.
Query Packs
-----------
Minor Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
C/C++
"""""
* The :code:`cpp/short-global-name` query will no longer give alerts for instantiations of template variables, only for the template itself.
* Fixed a false positive in :code:`cpp/overflow-buffer` when the type of the destination buffer is a reference to a class/struct type.
Golang
""""""
* Go 1.25 is now supported.
JavaScript/TypeScript
"""""""""""""""""""""
* The :code:`js/regex-injection` query no longer considers environment variables as sources by default. Environment variables can be re-enabled as sources by setting the threat model to include the "environment" category.
New Queries
~~~~~~~~~~~
Rust
""""
* Added a new query, :code:`rust/cleartext-storage-database`, for detecting cases where sensitive information is stored non-encrypted in a database.
Language Libraries
------------------
Bug Fixes
~~~~~~~~~
Ruby
""""
* Made the following changes to :code:`NetHttpRequest`
* Adds :code:`connectionNode`, like other Ruby HTTP clients
* Makes :code:`requestNode` and :code:`connectionNode` public so subclasses can use them
* Adds detection of :code:`Net::HTTP.start`, a common way to make HTTP requests in Ruby
Major Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Java/Kotlin
"""""""""""
* Added library models for the relevant method calls under :code:`jakarta.servlet.ServletRequest` and :code:`jakarta.servlet.http.HttpServletRequest` as remote flow sources.
Minor Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
C/C++
"""""
* The guards libraries (:code:`semmle.code.cpp.controlflow.Guards` and :code:`semmle.code.cpp.controlflow.IRGuards`) have been improved to recognize more guards.
* Improved dataflow through global variables in the new dataflow library (:code:`semmle.code.cpp.dataflow.new.DataFlow` and :code:`semmle.code.cpp.dataflow.new.TaintTracking`). Queries based on these libraries will produce more results on codebases with many global variables.
* The global value numbering library (:code:`semmle.code.cpp.valuenumbering.GlobalValueNumbering` and :code:`semmle.code.cpp.ir.ValueNumbering`) has been improved so more expressions are assigned the same value number.
Java/Kotlin
"""""""""""
* Guard implication logic involving wrapper methods has been improved. In particular, this means fewer false positives for :code:`java/dereferenced-value-may-be-null`.
JavaScript/TypeScript
"""""""""""""""""""""
* Improved modeling of command-line argument parsing libraries `arg <https://www.npmjs.com/package/arg>`__, `args <https://www.npmjs.com/package/args>`__, `command-line-args <https://www.npmjs.com/package/command-line-args>`__ and `commander <https://www.npmjs.com/package/commander>`__
Rust
""""
* |link-code-let-chains-in-code-if-and-code-while-1|_ are now supported, as well as |link-code-if-let-guards-in-code-match-expressions-2|_.
* Added more detail to models of :code:`postgres`, :code:`rusqlite`, :code:`sqlx` and :code:`tokio-postgres`. This may improve query results, particularly for :code:`rust/sql-injection` and :code:`rust/cleartext-storage-database`.
.. |link-code-let-chains-in-code-if-and-code-while-1| replace:: :code:`let` chains in :code:`if` and :code:`while`\
.. _link-code-let-chains-in-code-if-and-code-while-1: https://doc.rust-lang.org/edition-guide/rust-2024/let-chains.html
.. |link-code-if-let-guards-in-code-match-expressions-2| replace:: :code:`if let` guards in :code:`match` expressions
.. _link-code-if-let-guards-in-code-match-expressions-2: https://rust-lang.github.io/rfcs/2294-if-let-guard.html

View File

@@ -11,6 +11,7 @@ A list of queries for each suite and language `is available here <https://docs.g
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
codeql-cli-2.22.4
codeql-cli-2.22.3 codeql-cli-2.22.3
codeql-cli-2.22.2 codeql-cli-2.22.2
codeql-cli-2.22.1 codeql-cli-2.22.1

View File

@@ -82,6 +82,7 @@ ql/java/ql/src/Violations of Best Practice/Records/IgnoredSerializationMembersOf
ql/java/ql/src/Violations of Best Practice/SpecialCharactersInLiterals/NonExplicitControlAndWhitespaceCharsInLiterals.ql ql/java/ql/src/Violations of Best Practice/SpecialCharactersInLiterals/NonExplicitControlAndWhitespaceCharsInLiterals.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToRunFinalizersOnExit.ql ql/java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToRunFinalizersOnExit.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToStringToString.ql ql/java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToStringToString.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToSystemExit.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/DefaultToString.ql ql/java/ql/src/Violations of Best Practice/Undesirable Calls/DefaultToString.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/DoNotCallFinalize.ql ql/java/ql/src/Violations of Best Practice/Undesirable Calls/DoNotCallFinalize.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/PrintLnArray.ql ql/java/ql/src/Violations of Best Practice/Undesirable Calls/PrintLnArray.ql

View File

@@ -27,6 +27,7 @@ ql/java/ql/src/Security/CWE/CWE-113/ResponseSplitting.ql
ql/java/ql/src/Security/CWE/CWE-1204/StaticInitializationVector.ql ql/java/ql/src/Security/CWE/CWE-1204/StaticInitializationVector.ql
ql/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatString.ql ql/java/ql/src/Security/CWE/CWE-134/ExternallyControlledFormatString.ql
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuatorsConfig/SpringBootActuatorsConfig.ql
ql/java/ql/src/Security/CWE/CWE-209/SensitiveDataExposureThroughErrorMessage.ql ql/java/ql/src/Security/CWE/CWE-209/SensitiveDataExposureThroughErrorMessage.ql
ql/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql ql/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql
ql/java/ql/src/Security/CWE/CWE-266/IntentUriPermissionManipulation.ql ql/java/ql/src/Security/CWE/CWE-266/IntentUriPermissionManipulation.ql

View File

@@ -143,6 +143,7 @@ ql/java/ql/src/Security/CWE/CWE-200/AndroidSensitiveTextField.ql
ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsAllowsContentAccess.ql ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsAllowsContentAccess.ql
ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsFileAccess.ql ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsFileAccess.ql
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuatorsConfig/SpringBootActuatorsConfig.ql
ql/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql ql/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql
ql/java/ql/src/Security/CWE/CWE-209/SensitiveDataExposureThroughErrorMessage.ql ql/java/ql/src/Security/CWE/CWE-209/SensitiveDataExposureThroughErrorMessage.ql
ql/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql ql/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql

View File

@@ -46,6 +46,7 @@ ql/java/ql/src/Security/CWE/CWE-200/AndroidSensitiveTextField.ql
ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsAllowsContentAccess.ql ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsAllowsContentAccess.ql
ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsFileAccess.ql ql/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsFileAccess.ql
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuators.ql
ql/java/ql/src/Security/CWE/CWE-200/SpringBootActuatorsConfig/SpringBootActuatorsConfig.ql
ql/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql ql/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql
ql/java/ql/src/Security/CWE/CWE-209/SensitiveDataExposureThroughErrorMessage.ql ql/java/ql/src/Security/CWE/CWE-209/SensitiveDataExposureThroughErrorMessage.ql
ql/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql ql/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql

View File

@@ -66,7 +66,6 @@ ql/java/ql/src/Frameworks/Spring/XML Configuration Errors/MissingSetters.ql
ql/java/ql/src/Language Abuse/CastThisToTypeParameter.ql ql/java/ql/src/Language Abuse/CastThisToTypeParameter.ql
ql/java/ql/src/Language Abuse/DubiousDowncastOfThis.ql ql/java/ql/src/Language Abuse/DubiousDowncastOfThis.ql
ql/java/ql/src/Language Abuse/DubiousTypeTestOfThis.ql ql/java/ql/src/Language Abuse/DubiousTypeTestOfThis.ql
ql/java/ql/src/Language Abuse/EmptyStatement.ql
ql/java/ql/src/Language Abuse/EnumIdentifier.ql ql/java/ql/src/Language Abuse/EnumIdentifier.ql
ql/java/ql/src/Language Abuse/ImplementsAnnotation.ql ql/java/ql/src/Language Abuse/ImplementsAnnotation.ql
ql/java/ql/src/Language Abuse/MissedTernaryOpportunity.ql ql/java/ql/src/Language Abuse/MissedTernaryOpportunity.ql
@@ -187,7 +186,6 @@ ql/java/ql/src/Violations of Best Practice/Magic Constants/MagicNumbersUseConsta
ql/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.ql ql/java/ql/src/Violations of Best Practice/Magic Constants/MagicStringsUseConstant.ql
ql/java/ql/src/Violations of Best Practice/Naming Conventions/ConfusingOverridesNames.ql ql/java/ql/src/Violations of Best Practice/Naming Conventions/ConfusingOverridesNames.ql
ql/java/ql/src/Violations of Best Practice/Naming Conventions/LocalShadowsField.ql ql/java/ql/src/Violations of Best Practice/Naming Conventions/LocalShadowsField.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/CallsToSystemExit.ql
ql/java/ql/src/Violations of Best Practice/Undesirable Calls/GarbageCollection.ql ql/java/ql/src/Violations of Best Practice/Undesirable Calls/GarbageCollection.ql
ql/java/ql/src/Violations of Best Practice/legacy/AutoBoxing.ql ql/java/ql/src/Violations of Best Practice/legacy/AutoBoxing.ql
ql/java/ql/src/Violations of Best Practice/legacy/FinallyMayNotComplete.ql ql/java/ql/src/Violations of Best Practice/legacy/FinallyMayNotComplete.ql
@@ -196,7 +194,6 @@ ql/java/ql/src/Violations of Best Practice/legacy/ParameterAssignment.ql
ql/java/ql/src/Violations of Best Practice/legacy/UnnecessaryCast.ql ql/java/ql/src/Violations of Best Practice/legacy/UnnecessaryCast.ql
ql/java/ql/src/Violations of Best Practice/legacy/UnnecessaryImport.ql ql/java/ql/src/Violations of Best Practice/legacy/UnnecessaryImport.ql
ql/java/ql/src/definitions.ql ql/java/ql/src/definitions.ql
ql/java/ql/src/experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql
ql/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql ql/java/ql/src/experimental/Security/CWE/CWE-020/Log4jJndiInjection.ql
ql/java/ql/src/experimental/Security/CWE/CWE-036/OpenStream.ql ql/java/ql/src/experimental/Security/CWE/CWE-036/OpenStream.ql
ql/java/ql/src/experimental/Security/CWE/CWE-073/FilePathInjection.ql ql/java/ql/src/experimental/Security/CWE/CWE-073/FilePathInjection.ql

View File

@@ -70,7 +70,12 @@ class ConfigValue extends @configValue, ConfigLocatable {
override string toString() { result = this.getValue() } override string toString() { result = this.getValue() }
} }
/** A `.properties` file. */
class PropertiesFile extends File {
PropertiesFile() { this.getExtension() = "properties" }
}
/** A Java property is a name-value pair in a `.properties` file. */ /** A Java property is a name-value pair in a `.properties` file. */
class JavaProperty extends ConfigPair { class JavaProperty extends ConfigPair {
JavaProperty() { this.getFile().getExtension() = "properties" } JavaProperty() { this.getFile() instanceof PropertiesFile }
} }

View File

@@ -0,0 +1,128 @@
/** Provides classes and predicates to reason about Spring Boot actuators exposed in configuration files. */
overlay[local?]
module;
import java
private import semmle.code.configfiles.ConfigFiles
private import semmle.code.xml.MavenPom
/** The parent node of the `org.springframework.boot` group. */
private class SpringBootParent extends Parent {
SpringBootParent() { this.getGroup().getValue() = "org.springframework.boot" }
}
/** A `Pom` with a Spring Boot parent node. */
private class SpringBootPom extends Pom {
SpringBootPom() { this.getParentElement() instanceof SpringBootParent }
/** Holds if the Spring Boot Security module is used in the project. */
predicate isSpringBootSecurityUsed() {
this.getADependency().getArtifact().getValue() = "spring-boot-starter-security"
}
}
/** A dependency with artifactId `spring-boot-starter-actuator`. */
class SpringBootStarterActuatorDependency extends Dependency {
SpringBootStarterActuatorDependency() {
this.getArtifact().getValue() = "spring-boot-starter-actuator"
}
}
/** The Spring Boot configuration property `management.security.enabled`. */
private class ManagementSecurityEnabledProperty extends JavaProperty {
ManagementSecurityEnabledProperty() {
this.getNameElement().getName() = "management.security.enabled"
}
/** Gets the whitespace-trimmed value of this property. */
string getValue() { result = this.getValueElement().getValue().trim() }
/** Holds if `management.security.enabled` is set to `false`. */
predicate hasSecurityDisabled() { this.getValue() = "false" }
}
/**
* The Spring Boot configuration property `management.endpoints.web.exposure.include`
* or `management.endpoints.web.expose`.
*/
private class ManagementEndpointsExposeProperty extends JavaProperty {
ManagementEndpointsExposeProperty() {
this.getNameElement().getName() = "management.endpoints.web." + ["exposure.include", "expose"]
}
/** Gets the whitespace-trimmed value of this property. */
string getValue() { result = this.getValueElement().getValue().trim() }
}
private newtype TOption =
TNone() or
TSome(JavaProperty jp)
/**
* An option type that is either a singleton `None` or a `Some` wrapping
* the `JavaProperty` type.
*/
class JavaPropertyOption extends TOption {
/** Gets a textual representation of this element. */
string toString() {
this = TNone() and result = "(none)"
or
result = this.asSome().toString()
}
/** Gets the location of this element. */
Location getLocation() { result = this.asSome().getLocation() }
/** Gets the wrapped element, if any. */
JavaProperty asSome() { this = TSome(result) }
/** Holds if this option is the singleton `None`. */
predicate isNone() { this = TNone() }
}
/**
* Holds if `JavaPropertyOption` jpOption of a repository using `SpringBootStarterActuatorDependency`
* d exposes sensitive Spring Boot Actuator endpoints.
*/
predicate exposesSensitiveEndpoint(
SpringBootStarterActuatorDependency d, JavaPropertyOption jpOption
) {
exists(PropertiesFile propFile, SpringBootPom pom |
d = pom.getADependency() and
not pom.isSpringBootSecurityUsed() and
propFile
.getParentContainer()
.getAbsolutePath()
.matches(pom.getFile().getParentContainer().getAbsolutePath() + "%") and // in the same sub-directory
exists(string springBootVersion |
springBootVersion = pom.getParentElement().getVersionString()
|
springBootVersion.regexpMatch("1\\.[0-4].*") and // version 1.0, 1.1, ..., 1.4
not exists(ManagementSecurityEnabledProperty ep | ep.getFile() = propFile) and
jpOption.isNone()
or
springBootVersion.regexpMatch("1\\.[0-5].*") and // version 1.0, 1.1, ..., 1.5
exists(ManagementSecurityEnabledProperty ep |
ep.hasSecurityDisabled() and ep.getFile() = propFile and ep = jpOption.asSome()
)
or
springBootVersion.matches(["2.%", "3.%"]) and //version 2.x and 3.x
exists(ManagementEndpointsExposeProperty ep |
ep.getFile() = propFile and
ep = jpOption.asSome() and
(
// all endpoints are exposed
ep.getValue() = "*"
or
// version 2.x: exposes health and info only by default
springBootVersion.matches("2.%") and
not ep.getValue() = ["health", "info"]
or
// version 3.x: exposes health only by default
springBootVersion.matches("3.%") and
not ep.getValue() = "health"
)
)
)
)
}

View File

@@ -0,0 +1,39 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>Spring Boot includes features called actuators that let you monitor and interact with your web
application. Exposing unprotected actuator endpoints through configuration files can lead to
information disclosure or even to remote code execution.</p>
</overview>
<recommendation>
<p>Since actuator endpoints may contain sensitive information, carefully consider when to expose them,
and secure them as you would any sensitive URL. If you need to expose actuator endpoints, use Spring
Security, which secures actuators by default, or define a custom security configuration.
</p>
</recommendation>
<example>
<p>The following examples show <code>application.properties</code> configurations that expose sensitive
actuator endpoints.</p>
<sample src="application_bad.properties" />
<p>The below configurations ensure that sensitive actuator endpoints are not exposed.</p>
<sample src="application_good.properties" />
<p>To use Spring Security, which secures actuators by default, add the <code>spring-boot-starter-security</code>
dependency in your Maven <code>pom.xml</code> file.</p>
<sample src="pom_good.xml" />
</example>
<references>
<li>
Spring Boot Reference Documentation:
<a href="https://docs.spring.io/spring-boot/reference/actuator/endpoints.html">Endpoints</a>.
</li>
<li>
HackerOne Report:
<a href="https://hackerone.com/reports/862589">Spring Actuator endpoints publicly available, leading to account takeover</a>
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,20 @@
/**
* @name Exposed Spring Boot actuators in configuration file
* @description Exposing Spring Boot actuators through configuration files may lead to information leak from
* the internal application, or even to remote code execution.
* @kind problem
* @problem.severity error
* @security-severity 6.5
* @precision high
* @id java/spring-boot-exposed-actuators-config
* @tags security
* external/cwe/cwe-200
*/
import java
import semmle.code.xml.MavenPom
import semmle.code.java.security.SpringBootActuatorsConfigQuery
from SpringBootStarterActuatorDependency d, JavaPropertyOption jpOption
where exposesSensitiveEndpoint(d, jpOption)
select d, "Insecure Spring Boot actuator $@ exposes sensitive endpoints.", jpOption, "configuration"

View File

@@ -0,0 +1,10 @@
# vulnerable configuration (Spring Boot 1.0 - 1.4): exposes endpoints by default
# vulnerable configuration (Spring Boot 1.5): false value exposes endpoints
management.security.enabled=false
# vulnerable configuration (Spring Boot 2.x): exposes all endpoints
management.endpoints.web.exposure.include=*
# vulnerable configuration (Spring Boot 3.x): exposes all endpoints
management.endpoints.web.exposure.include=*

View File

@@ -0,0 +1,11 @@
# safe configuration (Spring Boot 1.0 - 1.4)
management.security.enabled=true
# safe configuration (Spring Boot 1.5+)
management.security.enabled=true
# safe configuration (Spring Boot 2.x): exposes health and info only by default
management.endpoints.web.exposure.include=health,info
# safe configuration (Spring Boot 3.x): exposes health only by default
management.endpoints.web.exposure.include=health

View File

@@ -0,0 +1,12 @@
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- GOOD: Enable Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
...

View File

@@ -4,7 +4,7 @@ class FileOutput {
try { try {
output.write(s.getBytes()); output.write(s.getBytes());
} catch (IOException e) { } catch (IOException e) {
System.exit(1); System.exit(1); // BAD: Should handle or propagate error instead of exiting
} }
return true; return true;
} }
@@ -16,9 +16,30 @@ class Action {
// ... // ...
// Perform tasks ... // Perform tasks ...
// ... // ...
System.exit(0); System.exit(0); // BAD: Should return status or throw exception
} }
public static void main(String[] args) { public static void main(String[] args) {
new Action(args).run(); new Action().run();
} }
} }
// Good example: Proper error handling
class BetterAction {
public int run() throws Exception {
// ...
// Perform tasks ...
// ...
return 0; // Return status instead of calling System.exit
}
public static void main(String[] args) {
try {
BetterAction action = new BetterAction();
int exitCode = action.run();
System.exit(exitCode); // GOOD: Exit from main method
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
System.exit(1); // GOOD: Exit from main method on error
}
}
}

View File

@@ -13,17 +13,20 @@ program state from being written to disk consistently.</p>
<p>It is sometimes considered acceptable to call <code>System.exit</code> <p>It is sometimes considered acceptable to call <code>System.exit</code>
from a program's <code>main</code> method in order to indicate the overall exit status from a program's <code>main</code> method in order to indicate the overall exit status
of the program. Such calls are an exception to this rule.</p> of the program. The <code>main</code> method should be the primary place
where exit conditions are handled, as it represents the natural termination point
of the application. Such calls are an exception to this rule.</p>
</overview> </overview>
<recommendation> <recommendation>
<p>It is usually preferable to use a different mechanism for reporting <p>Instead of calling <code>System.exit</code> from non-main methods, prefer to propagate
failure conditions. Consider returning a special value (perhaps errors upward to the <code>main</code> method where they can be handled appropriately.
<code>null</code>) that users of the current method check for and Consider returning a special value (perhaps <code>null</code>) that users of the current
recover from appropriately. Alternatively, throw a suitable exception, which method check for and recover from appropriately. Alternatively, throw a suitable exception,
unwinds the stack and allows properly written code to clean up after itself, which unwinds the stack and allows properly written code to clean up after itself,
while leaving other threads undisturbed.</p> while leaving other threads undisturbed. The <code>main</code> method can then catch
these exceptions and decide whether to exit the program and with what exit code.</p>
</recommendation> </recommendation>
<example> <example>
@@ -38,12 +41,14 @@ upwards and be handled by a method that knows how to recover.</p>
<p>Problem 2 is more subtle. In this example, there is just one entry point to <p>Problem 2 is more subtle. In this example, there is just one entry point to
the program (the <code>main</code> method), which constructs an the program (the <code>main</code> method), which constructs an
<code>Action</code> and performs it. <code>Action.run</code> calls <code>Action</code> and performs it. <code>Action.run</code> calls
<code>System.exit</code> to indicate successful completion. Consider, <code>System.exit</code> to indicate successful completion. Instead, the
however, how this code might be integrated in an application server that <code>run</code> method should return a status code or throw an exception
constructs <code>Action</code> instances and calls on failure, allowing the <code>main</code> method to decide whether to exit
and with what exit code. Consider how this code might be integrated in an
application server that constructs <code>Action</code> instances and calls
<code>run</code> on them without going through <code>main</code>. <code>run</code> on them without going through <code>main</code>.
The fact that <code>run</code> terminates the JVM instead of returning its The fact that <code>run</code> terminates the JVM instead of returning its
exit code as an integer makes that use-case impossible.</p> exit code makes that use-case impossible.</p>
<sample src="CallsToSystemExit.java" /> <sample src="CallsToSystemExit.java" />

View File

@@ -4,26 +4,80 @@
* reuse and prevent important cleanup steps from running. * reuse and prevent important cleanup steps from running.
* @kind problem * @kind problem
* @problem.severity warning * @problem.severity warning
* @precision low * @precision medium
* @id java/jvm-exit * @id java/jvm-exit
* @tags reliability * @previous-id java/jvm-exit-prevents-cleanup-and-reuse
* maintainability * @tags quality
* reliability
* correctness
* external/cwe/cwe-382 * external/cwe/cwe-382
*/ */
import java import java
from Method m, MethodCall sysexitCall, Method sysexit, Class system /**
where * A `Method` which, when called, causes the JVM to exit or halt.
sysexitCall = m.getACallSite(sysexit) and *
(sysexit.hasName("exit") or sysexit.hasName("halt")) and * Explicitly includes these methods from the java standard library:
sysexit.getDeclaringType() = system and * - `java.lang.System.exit`
( * - `java.lang.Runtime.halt`
system.hasQualifiedName("java.lang", "System") or * - `java.lang.Runtime.exit`
system.hasQualifiedName("java.lang", "Runtime") */
) and class ExitOrHaltMethod extends Method {
m.fromSource() and ExitOrHaltMethod() {
not m instanceof MainMethod exists(Class system | this.getDeclaringType() = system |
select sysexitCall, this.hasName("exit") and
"Avoid calls to " + sysexit.getDeclaringType().getName() + "." + sysexit.getName() + system.hasQualifiedName("java.lang", ["System", "Runtime"])
"() as this makes code harder to reuse." or
this.hasName("halt") and
system.hasQualifiedName("java.lang", "Runtime")
)
}
}
/** A `MethodCall` to an `ExitOrHaltMethod`, which causes the JVM to exit abruptly. */
class ExitOrHaltMethodCall extends MethodCall {
ExitOrHaltMethodCall() {
exists(ExitOrHaltMethod exitMethod | this.getMethod() = exitMethod |
exists(SourceMethodNotMainOrTest srcMethod | this = srcMethod.getACallSite(exitMethod))
)
}
}
/**
* An intentional `MethodCall` to a system or runtime "exit" method, such as for
* functions which exist for the purpose of exiting the program. Assumes that an exit method
* call within a method is intentional if the exit code is passed from a parameter of the
* enclosing method.
*/
class IntentionalExitMethodCall extends ExitOrHaltMethodCall {
IntentionalExitMethodCall() {
this.getMethod().hasName("exit") and
this.getAnArgument() = this.getEnclosingCallable().getAParameter().getAnAccess()
}
}
/**
* A `Method` that is defined in source code and is not a `MainMethod` or a `LikelyTestMethod`.
*/
class SourceMethodNotMainOrTest extends Method {
SourceMethodNotMainOrTest() {
this.fromSource() and
not this instanceof MainMethod and
not (
this.getEnclosingCallable*() instanceof LikelyTestMethod
or
this.getDeclaringType()
.getEnclosingType*()
.(LocalClassOrInterface)
.getLocalTypeDeclStmt()
.getEnclosingCallable() instanceof LikelyTestMethod
)
}
}
from ExitOrHaltMethodCall mc
where not mc instanceof IntentionalExitMethodCall
select mc,
"Avoid calls to " + mc.getMethod().getDeclaringType().getName() + "." + mc.getMethod().getName() +
"() as this prevents runtime cleanup and makes code harder to reuse."

View File

@@ -0,0 +1,4 @@
---
category: newQuery
---
* The query `java/insecure-spring-actuator-config` has been promoted from experimental to the main query pack as `java/spring-boot-exposed-actuators-config`. Its results will now appear by default. This query detects exposure of Spring Boot actuators through configuration files. It was originally submitted as an experimental query [by @luchua-bc](https://github.com/github/codeql/pull/5384).

View File

@@ -1,47 +0,0 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>Spring Boot is a popular framework that facilitates the development of stand-alone applications
and micro services. Spring Boot Actuator helps to expose production-ready support features against
Spring Boot applications.</p>
<p>Endpoints of Spring Boot Actuator allow to monitor and interact with a Spring Boot application.
Exposing unprotected actuator endpoints through configuration files can lead to information disclosure
or even remote code execution vulnerability.</p>
<p>Rather than programmatically permitting endpoint requests or enforcing access control, frequently
developers simply leave management endpoints publicly accessible in the application configuration file
<code>application.properties</code> without enforcing access control through Spring Security.</p>
</overview>
<recommendation>
<p>Declare the Spring Boot Starter Security module in XML configuration or programmatically enforce
security checks on management endpoints using Spring Security. Otherwise accessing management endpoints
on a different HTTP port other than the port that the web application is listening on also helps to
improve the security.</p>
</recommendation>
<example>
<p>The following examples show both 'BAD' and 'GOOD' configurations. In the 'BAD' configuration,
no security module is declared and sensitive management endpoints are exposed. In the 'GOOD' configuration,
security is enforced and only endpoints requiring exposure are exposed.</p>
<sample src="pom_good.xml" />
<sample src="pom_bad.xml" />
<sample src="application.properties" />
</example>
<references>
<li>
Spring Boot documentation:
<a href="https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html">Spring Boot Actuator: Production-ready Features</a>
</li>
<li>
VERACODE Blog:
<a href="https://www.veracode.com/blog/research/exploiting-spring-boot-actuators">Exploiting Spring Boot Actuators</a>
</li>
<li>
HackerOne Report:
<a href="https://hackerone.com/reports/862589">Spring Actuator endpoints publicly available, leading to account takeover</a>
</li>
</references>
</qhelp>

View File

@@ -1,121 +0,0 @@
/**
* @name Insecure Spring Boot Actuator Configuration
* @description Exposed Spring Boot Actuator through configuration files without declarative or procedural
* security enforcement leads to information leak or even remote code execution.
* @kind problem
* @problem.severity error
* @precision high
* @id java/insecure-spring-actuator-config
* @tags security
* experimental
* external/cwe/cwe-016
*/
/*
* Note this query requires properties files to be indexed before it can produce results.
* If creating your own database with the CodeQL CLI, you should run
* `codeql database index-files --language=properties ...`
* If using lgtm.com, you should add `properties_files: true` to the index block of your
* lgtm.yml file (see https://lgtm.com/help/lgtm/java-extraction)
*/
import java
import semmle.code.configfiles.ConfigFiles
import semmle.code.xml.MavenPom
/** The parent node of the `org.springframework.boot` group. */
class SpringBootParent extends Parent {
SpringBootParent() { this.getGroup().getValue() = "org.springframework.boot" }
}
/** Class of Spring Boot dependencies. */
class SpringBootPom extends Pom {
SpringBootPom() { this.getParentElement() instanceof SpringBootParent }
/** Holds if the Spring Boot Actuator module `spring-boot-starter-actuator` is used in the project. */
predicate isSpringBootActuatorUsed() {
this.getADependency().getArtifact().getValue() = "spring-boot-starter-actuator"
}
/**
* Holds if the Spring Boot Security module is used in the project, which brings in other security
* related libraries.
*/
predicate isSpringBootSecurityUsed() {
this.getADependency().getArtifact().getValue() = "spring-boot-starter-security"
}
}
/** The properties file `application.properties`. */
class ApplicationProperties extends ConfigPair {
ApplicationProperties() { this.getFile().getBaseName() = "application.properties" }
}
/** The configuration property `management.security.enabled`. */
class ManagementSecurityConfig extends ApplicationProperties {
ManagementSecurityConfig() { this.getNameElement().getName() = "management.security.enabled" }
/** Gets the whitespace-trimmed value of this property. */
string getValue() { result = this.getValueElement().getValue().trim() }
/** Holds if `management.security.enabled` is set to `false`. */
predicate hasSecurityDisabled() { this.getValue() = "false" }
/** Holds if `management.security.enabled` is set to `true`. */
predicate hasSecurityEnabled() { this.getValue() = "true" }
}
/** The configuration property `management.endpoints.web.exposure.include`. */
class ManagementEndPointInclude extends ApplicationProperties {
ManagementEndPointInclude() {
this.getNameElement().getName() = "management.endpoints.web.exposure.include"
}
/** Gets the whitespace-trimmed value of this property. */
string getValue() { result = this.getValueElement().getValue().trim() }
}
/**
* Holds if `ApplicationProperties` ap of a repository managed by `SpringBootPom` pom
* has a vulnerable configuration of Spring Boot Actuator management endpoints.
*/
predicate hasConfidentialEndPointExposed(SpringBootPom pom, ApplicationProperties ap) {
pom.isSpringBootActuatorUsed() and
not pom.isSpringBootSecurityUsed() and
ap.getFile()
.getParentContainer()
.getAbsolutePath()
.matches(pom.getFile().getParentContainer().getAbsolutePath() + "%") and // in the same sub-directory
exists(string springBootVersion | springBootVersion = pom.getParentElement().getVersionString() |
springBootVersion.regexpMatch("1\\.[0-4].*") and // version 1.0, 1.1, ..., 1.4
not exists(ManagementSecurityConfig me |
me.hasSecurityEnabled() and me.getFile() = ap.getFile()
)
or
springBootVersion.matches("1.5%") and // version 1.5
exists(ManagementSecurityConfig me | me.hasSecurityDisabled() and me.getFile() = ap.getFile())
or
springBootVersion.matches("2.%") and //version 2.x
exists(ManagementEndPointInclude mi |
mi.getFile() = ap.getFile() and
(
mi.getValue() = "*" // all endpoints are enabled
or
mi.getValue()
.matches([
"%dump%", "%trace%", "%logfile%", "%shutdown%", "%startup%", "%mappings%", "%env%",
"%beans%", "%sessions%"
]) // confidential endpoints to check although all endpoints apart from '/health' and '/info' are considered sensitive by Spring
)
)
)
}
deprecated query predicate problems(Dependency d, string message) {
exists(SpringBootPom pom |
hasConfidentialEndPointExposed(pom, _) and
d = pom.getADependency() and
d.getArtifact().getValue() = "spring-boot-starter-actuator"
) and
message = "Insecure configuration of Spring Boot Actuator exposes sensitive endpoints."
}

View File

@@ -1,22 +0,0 @@
#management.endpoints.web.base-path=/admin
#### BAD: All management endpoints are accessible ####
# vulnerable configuration (spring boot 1.0 - 1.4): exposes actuators by default
# vulnerable configuration (spring boot 1.5+): requires value false to expose sensitive actuators
management.security.enabled=false
# vulnerable configuration (spring boot 2+): exposes health and info only by default, here overridden to expose everything
management.endpoints.web.exposure.include=*
#### GOOD: All management endpoints have access control ####
# safe configuration (spring boot 1.0 - 1.4): exposes actuators by default
management.security.enabled=true
# safe configuration (spring boot 1.5+): requires value false to expose sensitive actuators
management.security.enabled=true
# safe configuration (spring boot 2+): exposes health and info only by default, here overridden to expose one additional endpoint which we assume is intentional and safe.
management.endpoints.web.exposure.include=beans,info,health

View File

@@ -1 +0,0 @@
| pom.xml:29:9:32:22 | dependency | Insecure configuration of Spring Boot Actuator exposes sensitive endpoints. |

View File

@@ -1 +0,0 @@
experimental/Security/CWE/CWE-016/InsecureSpringActuatorConfig.ql

View File

@@ -1,13 +0,0 @@
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class SensitiveInfo {
@RequestMapping
public void handleLogin(@RequestParam String username, @RequestParam String password) throws Exception {
if (!username.equals("") && password.equals("")) {
//Blank processing
}
}
}

View File

@@ -1,14 +0,0 @@
#management.endpoints.web.base-path=/admin
# vulnerable configuration (spring boot 1.0 - 1.4): exposes actuators by default
# vulnerable configuration (spring boot 1.5+): requires value false to expose sensitive actuators
management.security.enabled=false
# vulnerable configuration (spring boot 2+): exposes health and info only by default, here overridden to expose everything
management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=beans
management.endpoint.shutdown.enabled=true
management.endpoint.health.show-details=when_authorized

View File

@@ -0,0 +1,6 @@
| ExampleRuntimeExit.java:22:17:22:44 | exit(...) | Avoid calls to Runtime.exit() as this prevents runtime cleanup and makes code harder to reuse. |
| ExampleRuntimeExit.java:25:17:25:44 | exit(...) | Avoid calls to Runtime.exit() as this prevents runtime cleanup and makes code harder to reuse. |
| ExampleRuntimeHalt.java:18:17:18:44 | halt(...) | Avoid calls to Runtime.halt() as this prevents runtime cleanup and makes code harder to reuse. |
| ExampleRuntimeHalt.java:21:17:21:44 | halt(...) | Avoid calls to Runtime.halt() as this prevents runtime cleanup and makes code harder to reuse. |
| ExampleSystemExit.java:22:17:22:30 | exit(...) | Avoid calls to System.exit() as this prevents runtime cleanup and makes code harder to reuse. |
| ExampleSystemExit.java:25:17:25:30 | exit(...) | Avoid calls to System.exit() as this prevents runtime cleanup and makes code harder to reuse. |

View File

@@ -0,0 +1,2 @@
query: Violations of Best Practice/Undesirable Calls/CallsToSystemExit.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -0,0 +1,37 @@
import java.io.FileOutputStream;
import java.io.IOException;
public class ExampleRuntimeExit {
public static void main(String[] args) {
Action action = new Action();
try {
action.run();
} catch (Exception e) {
printUsageAndExit(e.getMessage(), 1);
}
Runtime.getRuntime().exit(0); // COMPLIANT
}
static class Action {
public void run() {
try {
FileOutputStream fos = new FileOutputStream("output.txt");
fos.write("Hello, World!".getBytes());
fos.close();
Runtime.getRuntime().exit(0); // $ Alert
} catch (IOException e) {
e.printStackTrace();
Runtime.getRuntime().exit(1); // $ Alert
} catch (Exception e) {
// re-throw the exception
throw e;
}
}
}
protected static void printUsageAndExit(final String message, final int exitCode) {
System.err.println("Usage: <example_cmd> <example_args> : " + message);
Runtime.getRuntime().exit(exitCode); // COMPLIANT
}
}

View File

@@ -0,0 +1,25 @@
import java.io.FileOutputStream;
import java.io.IOException;
public class ExampleRuntimeHalt {
public static void main(String[] args) {
Action action = new Action();
action.run();
Runtime.getRuntime().halt(0); // COMPLIANT
}
static class Action {
public void run() {
try {
FileOutputStream fos = new FileOutputStream("output.txt");
fos.write("Hello, World!".getBytes());
fos.close();
Runtime.getRuntime().halt(0); // $ Alert
} catch (IOException e) {
e.printStackTrace();
Runtime.getRuntime().halt(1); // $ Alert
}
}
}
}

View File

@@ -0,0 +1,37 @@
import java.io.FileOutputStream;
import java.io.IOException;
public class ExampleSystemExit {
public static void main(String[] args) {
Action action = new Action();
try {
action.run();
} catch (Exception e) {
printUsageAndExit(e.getMessage(), 1);
}
System.exit(0); // COMPLIANT
}
static class Action {
public void run() {
try {
FileOutputStream fos = new FileOutputStream("output.txt");
fos.write("Hello, World!".getBytes());
fos.close();
System.exit(0); // $ Alert
} catch (IOException e) {
e.printStackTrace();
System.exit(1); // $ Alert
} catch (Exception e) {
// re-throw the exception
throw e;
}
}
}
protected static void printUsageAndExit(final String message, final int exitCode) {
System.err.println("Usage: <example_cmd> <example_args> : " + message);
System.exit(exitCode); // COMPLIANT
}
}

View File

@@ -0,0 +1,26 @@
public class LocalClassInTestMethod {
public void testNestedCase() {
class OuterLocalClass {
void func() {
class NestedLocalClass {
void nestedMethod() {
System.exit(4);
Runtime.getRuntime().halt(5);
}
}
}
}
OuterLocalClass outer = new OuterLocalClass();
outer.func();
}
public void testNestedCase2() {
class OuterLocalClass {
class NestedLocalClass {
void nestedMethod() {
System.exit(4);
Runtime.getRuntime().halt(5);
}
}
}
}
}

View File

@@ -0,0 +1,8 @@
| Version1.0.x-1.4.x/bad/default/pom.xml:29:9:32:22 | dependency | Insecure Spring Boot actuator $@ exposes sensitive endpoints. | file://:0:0:0:0 | (none) | configuration |
| Version1.0.x-1.4.x/bad/false/pom.xml:29:9:32:22 | dependency | Insecure Spring Boot actuator $@ exposes sensitive endpoints. | Version1.0.x-1.4.x/bad/false/application.properties:2:1:2:33 | management.security.enabled=false | configuration |
| Version1.5.x/bad/pom.xml:29:9:32:22 | dependency | Insecure Spring Boot actuator $@ exposes sensitive endpoints. | Version1.5.x/bad/application.properties:2:1:2:33 | management.security.enabled=false | configuration |
| Version2.x/bad/expose/pom.xml:29:9:32:22 | dependency | Insecure Spring Boot actuator $@ exposes sensitive endpoints. | Version2.x/bad/expose/application.properties:2:1:2:33 | management.endpoints.web.expose=* | configuration |
| Version2.x/bad/exposure-include/all-exposed/pom.xml:29:9:32:22 | dependency | Insecure Spring Boot actuator $@ exposes sensitive endpoints. | Version2.x/bad/exposure-include/all-exposed/application.properties:2:1:2:43 | management.endpoints.web.exposure.include=* | configuration |
| Version2.x/bad/exposure-include/some-exposed/pom.xml:29:9:32:22 | dependency | Insecure Spring Boot actuator $@ exposes sensitive endpoints. | Version2.x/bad/exposure-include/some-exposed/application.properties:2:1:2:59 | management.endpoints.web.exposure.include=health,info,beans | configuration |
| Version3.x/bad/all-exposed/pom.xml:29:9:32:22 | dependency | Insecure Spring Boot actuator $@ exposes sensitive endpoints. | Version3.x/bad/all-exposed/application.properties:2:1:2:43 | management.endpoints.web.exposure.include=* | configuration |
| Version3.x/bad/some-exposed/pom.xml:29:9:32:22 | dependency | Insecure Spring Boot actuator $@ exposes sensitive endpoints. | Version3.x/bad/some-exposed/application.properties:2:1:2:59 | management.endpoints.web.exposure.include=health,info,beans | configuration |

View File

@@ -0,0 +1,2 @@
query: Security/CWE/CWE-200/SpringBootActuatorsConfig/SpringBootActuatorsConfig.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -0,0 +1 @@
# vulnerable configuration (spring boot 1.0 - 1.4): exposes actuators by default

View File

@@ -17,7 +17,7 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.8.RELEASE</version> <version>1.2.6.RELEASE</version>
<relativePath/> <relativePath/>
</parent> </parent>
@@ -29,18 +29,15 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId> <artifactId>spring-boot-starter-actuator</artifactId>
</dependency> </dependency> <!-- $ Alert -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId> <artifactId>spring-boot-devtools</artifactId>
</dependency> </dependency>
<!-- BAD: No Spring Security enabled -->
<!-- dependency> <!-- dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId> <artifactId>spring-boot-starter-security</artifactId>
</dependency --> </dependency -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId> <artifactId>spring-boot-test</artifactId>

View File

@@ -0,0 +1,2 @@
# vulnerable configuration (spring boot 1.0 - 1.4): exposes actuators by default
management.security.enabled=false

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>spring-boot-actuator-app</groupId>
<artifactId>spring-boot-actuator-app</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.6.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency> <!-- $ Alert -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,2 @@
# safe configuration (spring boot 1.0 - 1.4): exposes actuators by default
management.security.enabled=true

View File

@@ -17,7 +17,7 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.8.RELEASE</version> <version>1.2.6.RELEASE</version>
<relativePath/> <relativePath/>
</parent> </parent>
@@ -34,13 +34,10 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId> <artifactId>spring-boot-devtools</artifactId>
</dependency> </dependency>
<!-- GOOD: Enable Spring Security -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId> <artifactId>spring-boot-starter-security</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId> <artifactId>spring-boot-test</artifactId>

View File

@@ -0,0 +1,2 @@
# safe configuration (spring boot 1.5+): requires value false to expose sensitive actuators
management.security.enabled=false

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>spring-boot-actuator-app</groupId>
<artifactId>spring-boot-actuator-app</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency> <!-- $ Alert -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,2 @@
# vulnerable configuration (spring boot 1.5+): requires value false to expose sensitive actuators
management.security.enabled=true

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>spring-boot-actuator-app</groupId>
<artifactId>spring-boot-actuator-app</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,2 @@
# vulnerable configuration (spring boot 2.0.0.RC1): exposes health and info only by default, here overridden to expose everything
management.endpoints.web.expose=*

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>spring-boot-actuator-app</groupId>
<artifactId>spring-boot-actuator-app</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency> <!-- $ Alert -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,2 @@
# vulnerable configuration (spring boot 2+): exposes health and info only by default, here overridden to expose everything
management.endpoints.web.exposure.include=*

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>spring-boot-actuator-app</groupId>
<artifactId>spring-boot-actuator-app</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency> <!-- $ Alert -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,2 @@
# vulnerable configuration (spring boot 2+): exposes health and info only by default, here overridden to also expose beans
management.endpoints.web.exposure.include=health,info,beans

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>spring-boot-actuator-app</groupId>
<artifactId>spring-boot-actuator-app</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency> <!-- $ Alert -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,2 @@
# safe configuration (spring boot 2+): exposes health and info only by default
management.endpoints.web.exposure.include=info,health

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>spring-boot-actuator-app</groupId>
<artifactId>spring-boot-actuator-app</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,2 @@
# vulnerable configuration (spring boot 3+): exposes health only by default, here overridden to expose everything
management.endpoints.web.exposure.include=*

View File

@@ -17,7 +17,7 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.8.RELEASE</version> <version>3.3.5</version>
<relativePath/> <relativePath/>
</parent> </parent>
@@ -29,7 +29,7 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId> <artifactId>spring-boot-starter-actuator</artifactId>
</dependency> </dependency> <!-- $ Alert -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId> <artifactId>spring-boot-devtools</artifactId>

View File

@@ -0,0 +1,2 @@
# vulnerable configuration (spring boot 3+): exposes health only by default, here overridden to also expose info and beans
management.endpoints.web.exposure.include=health,info,beans

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>spring-boot-actuator-app</groupId>
<artifactId>spring-boot-actuator-app</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency> <!-- $ Alert -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,2 @@
# safe configuration (spring boot 3+): exposes health only by default.
management.endpoints.web.exposure.include=health

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>spring-boot-actuator-app</groupId>
<artifactId>spring-boot-actuator-app</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.8.x //semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../../stubs/springframework-5.8.x

View File

@@ -1,16 +0,0 @@
#Incorrect unhashable class
class MyMutableThing(object):
def __init__(self):
pass
def __hash__(self):
raise NotImplementedError("%r is unhashable" % self)
#Make class unhashable in the standard way
class MyCorrectMutableThing(object):
def __init__(self):
pass
__hash__ = None

View File

@@ -5,11 +5,11 @@
<overview> <overview>
<p>User-defined classes interact with the Python virtual machine via special methods (also called "magic methods"). <p>User-defined classes interact with the Python virtual machine via special methods (also called "magic methods").
For example, for a class to support addition it must implement the <code>__add__</code> and <code>__radd__</code> special methods. For example, for a class to support addition it must implement the <code>__add__</code> and <code>__radd__</code> special methods.
When the expression <code>a + b</code> is evaluated the Python virtual machine will call <code>type(a).__add__(a, b)</code> and if that When the expression <code>a + b</code> is evaluated, the Python virtual machine will call <code>type(a).__add__(a, b)</code>, and if that
is not implemented it will call <code>type(b).__radd__(b, a)</code>.</p> is not implemented it will call <code>type(b).__radd__(b, a)</code>.</p>
<p> <p>
Since the virtual machine calls these special methods for common expressions, users of the class will expect these operations to raise standard exceptions. Since the virtual machine calls these special methods for common expressions, users of the class will expect these operations to raise standard exceptions.
For example, users would expect that the expression <code>a.b</code> might raise an <code>AttributeError</code> For example, users would expect that the expression <code>a.b</code> may raise an <code>AttributeError</code>
if the object <code>a</code> does not have an attribute <code>b</code>. if the object <code>a</code> does not have an attribute <code>b</code>.
If a <code>KeyError</code> were raised instead, If a <code>KeyError</code> were raised instead,
then this would be unexpected and may break code that expected an <code>AttributeError</code>, but not a <code>KeyError</code>. then this would be unexpected and may break code that expected an <code>AttributeError</code>, but not a <code>KeyError</code>.
@@ -20,50 +20,48 @@ Therefore, if a method is unable to perform the expected operation then its resp
</p> </p>
<ul> <ul>
<li>Attribute access, <code>a.b</code>: Raise <code>AttributeError</code></li> <li>Attribute access, <code>a.b</code> (<code>__getattr__</code>): Raise <code>AttributeError</code>.</li>
<li>Arithmetic operations, <code>a + b</code>: Do not raise an exception, return <code>NotImplemented</code> instead.</li> <li>Arithmetic operations, <code>a + b</code> (<code>__add__</code>): Do not raise an exception, return <code>NotImplemented</code> instead.</li>
<li>Indexing, <code>a[b]</code>: Raise <code>KeyError</code>.</li> <li>Indexing, <code>a[b]</code> (<code>__getitem__</code>): Raise <code>KeyError</code> or <code>IndexError</code>.</li>
<li>Hashing, <code>hash(a)</code>: Use <code>__hash__ = None</code> to indicate that an object is unhashable.</li> <li>Hashing, <code>hash(a)</code> (<code>__hash__</code>): Should not raise an exception. Use <code>__hash__ = None</code> to indicate that an object is unhashable rather than raising an exception.</li>
<li>Equality methods, <code>a != b</code>: Never raise an exception, always return <code>True</code> or <code>False</code>.</li> <li>Equality methods, <code>a == b</code> (<code>__eq__</code>): Never raise an exception, always return <code>True</code> or <code>False</code>.</li>
<li>Ordering comparison methods, <code>a &lt; b</code>: Raise a <code>TypeError</code> if the objects cannot be ordered.</li> <li>Ordering comparison methods, <code>a &lt; b</code> (<code>__lt__</code>): Raise a <code>TypeError</code> if the objects cannot be ordered.</li>
<li>Most others: Ideally, do not implement the method at all, otherwise raise <code>TypeError</code> to indicate that the operation is unsupported.</li> <li>Most others: If the operation is never supported, the method often does not need to be implemented at all; otherwise a <code>TypeError</code> should be raised.</li>
</ul> </ul>
</overview> </overview>
<recommendation> <recommendation>
<p>If the method is meant to be abstract, then declare it so using the <code>@abstractmethod</code> decorator. <p>If the method always raises as exception, then if it is intended to be an abstract method, the <code>@abstractmethod</code> decorator should be used.
Otherwise, either remove the method or ensure that the method raises an exception of the correct type. Otherwise, ensure that the method raises an exception of the correct type, or remove the method if the operation does not need to be supported.
</p> </p>
</recommendation> </recommendation>
<example> <example>
<p> <p>
This example shows two unhashable classes. The first class is unhashable in a non-standard way which may cause maintenance problems. In the following example, the <code>__add__</code> method of <code>A</code> raises a <code>TypeError</code> if <code>other</code> is of the wrong type.
The second, corrected, class uses the standard idiom for unhashable classes. However, it should return <code>NotImplemented</code> instead of rising an exception, to allow other classes to support adding to <code>A</code>.
This is demonstrated in the class <code>B</code>.
</p> </p>
<sample src="IncorrectRaiseInSpecialMethod.py" /> <sample src="examples/IncorrectRaiseInSpecialMethod.py" />
<p> <p>
In this example, the first class is implicitly abstract; the <code>__add__</code> method is unimplemented, In the following example, the <code>__getitem__</code> method of <code>C</code> raises a <code>ValueError</code>, rather than a <code>KeyError</code> or <code>IndexError</code> as expected.
presumably with the expectation that it will be implemented by sub-classes.
The second class makes this explicit with an <code>@abstractmethod</code> decoration on the unimplemented <code>__add__</code> method.
</p> </p>
<sample src="IncorrectRaiseInSpecialMethod2.py" /> <sample src="examples/IncorrectRaiseInSpecialMethod2.py" />
<p> <p>
In this last example, the first class implements a collection backed by the file store. In the following example, the class <code>__hash__</code> method of <code>D</code> raises <code>NotImplementedError</code>.
However, should an <code>IOError</code> be raised in the <code>__getitem__</code> it will propagate to the caller. This causes <code>D</code> to be incorrectly identified as hashable by <code>isinstance(obj, collections.abc.Hashable)</code>; so the correct
The second class handles any <code>IOError</code> by reraising a <code>KeyError</code> which is the standard exception for way to make a class unhashable is to set <code>__hash__ = None</code>.
the <code>__getitem__</code> method.
</p> </p>
<sample src="IncorrectRaiseInSpecialMethod3.py" /> <sample src="examples/IncorrectRaiseInSpecialMethod3.py" />
</example> </example>
<references> <references>
<li>Python Language Reference: <a href="http://docs.python.org/dev/reference/datamodel.html#special-method-names">Special Method Names</a>.</li> <li>Python Language Reference: <a href="http://docs.python.org/dev/reference/datamodel.html#special-method-names">Special Method Names</a>.</li>
<li>Python Library Reference: <a href="https://docs.python.org/2/library/exceptions.html">Exceptions</a>.</li> <li>Python Library Reference: <a href="https://docs.python.org/3/library/exceptions.html">Exceptions</a>.</li>

View File

@@ -7,114 +7,188 @@
* error-handling * error-handling
* @problem.severity recommendation * @problem.severity recommendation
* @sub-severity high * @sub-severity high
* @precision very-high * @precision high
* @id py/unexpected-raise-in-special-method * @id py/unexpected-raise-in-special-method
*/ */
import python import python
import semmle.python.ApiGraphs
import semmle.python.dataflow.new.internal.DataFlowDispatch
private predicate attribute_method(string name) { /** Holds if `name` is the name of a special method for attribute access such as `a.b`, that should raise an `AttributeError`. */
name = "__getattribute__" or name = "__getattr__" or name = "__setattr__" private predicate attributeMethod(string name) {
name = ["__getattribute__", "__getattr__", "__delattr__"] // __setattr__ excluded as it makes sense to raise different kinds of errors based on the `value` parameter
} }
private predicate indexing_method(string name) { /** Holds if `name` is the name of a special method for indexing operations such as `a[b]`, that should raise a `LookupError`. */
name = "__getitem__" or name = "__setitem__" or name = "__delitem__" private predicate indexingMethod(string name) {
name = ["__getitem__", "__delitem__"] // __setitem__ excluded as it makes sense to raise different kinds of errors based on the `value` parameter
} }
private predicate arithmetic_method(string name) { /** Holds if `name` is the name of a special method for arithmetic operations. */
name in [ private predicate arithmeticMethod(string name) {
"__add__", "__sub__", "__or__", "__xor__", "__rshift__", "__pow__", "__mul__", "__neg__", name =
"__radd__", "__rsub__", "__rdiv__", "__rfloordiv__", "__div__", "__rdiv__", "__rlshift__", [
"__rand__", "__ror__", "__rxor__", "__rrshift__", "__rpow__", "__rmul__", "__truediv__", "__add__", "__sub__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__pow__",
"__rtruediv__", "__pos__", "__iadd__", "__isub__", "__idiv__", "__ifloordiv__", "__idiv__", "__mul__", "__div__", "__divmod__", "__truediv__", "__floordiv__", "__matmul__", "__radd__",
"__ilshift__", "__iand__", "__ior__", "__ixor__", "__irshift__", "__abs__", "__ipow__", "__rsub__", "__rand__", "__ror__", "__rxor__", "__rlshift__", "__rrshift__", "__rpow__",
"__imul__", "__itruediv__", "__floordiv__", "__div__", "__divmod__", "__lshift__", "__and__" "__rmul__", "__rdiv__", "__rdivmod__", "__rtruediv__", "__rfloordiv__", "__rmatmul__",
"__iadd__", "__isub__", "__iand__", "__ior__", "__ixor__", "__ilshift__", "__irshift__",
"__ipow__", "__imul__", "__idiv__", "__idivmod__", "__itruediv__", "__ifloordiv__",
"__imatmul__", "__pos__", "__neg__", "__abs__", "__invert__",
] ]
} }
private predicate ordering_method(string name) { /** Holds if `name is the name of a special method for ordering operations such as `a < b`. */
name = "__lt__" private predicate orderingMethod(string name) {
or name =
name = "__le__" [
or "__lt__",
name = "__gt__" "__le__",
or "__gt__",
name = "__ge__" "__ge__",
or ]
name = "__cmp__" and major_version() = 2
} }
private predicate cast_method(string name) { /** Holds if `name` is the name of a special method for casting an object to a numeric type, such as `int(x)` */
name = "__nonzero__" and major_version() = 2 private predicate castMethod(string name) {
or name =
name = "__int__" [
or "__int__",
name = "__float__" "__float__",
or "__index__",
name = "__long__" "__trunc__",
or "__complex__"
name = "__trunc__" ] // __bool__ excluded as it makes sense to allow it to always raise
or
name = "__complex__"
} }
predicate correct_raise(string name, ClassObject ex) { /** Holds if we allow a special method named `name` to raise `exec` as an exception. */
ex.getAnImproperSuperType() = theTypeErrorType() and predicate correctRaise(string name, Expr exec) {
execIsOfType(exec, "TypeError") and
( (
name = "__copy__" or indexingMethod(name) or
name = "__deepcopy__" or attributeMethod(name) or
name = "__call__" or // Allow add methods to raise a TypeError, as they can be used for sequence concatenation as well as arithmetic
indexing_method(name) or name = ["__add__", "__iadd__", "__radd__"]
attribute_method(name)
) )
or or
preferred_raise(name, ex) exists(string execName |
or preferredRaise(name, execName, _) and
preferred_raise(name, ex.getASuperType()) execIsOfType(exec, execName)
)
} }
predicate preferred_raise(string name, ClassObject ex) { /** Holds if it is preferred for `name` to raise exceptions of type `execName`. `message` is the alert message. */
attribute_method(name) and ex = theAttributeErrorType() predicate preferredRaise(string name, string execName, string message) {
attributeMethod(name) and
execName = "AttributeError" and
message = "should raise an AttributeError instead."
or or
indexing_method(name) and ex = Object::builtin("LookupError") indexingMethod(name) and
execName = "LookupError" and
message = "should raise a LookupError (KeyError or IndexError) instead."
or or
ordering_method(name) and ex = theTypeErrorType() orderingMethod(name) and
execName = "TypeError" and
message = "should raise a TypeError or return NotImplemented instead."
or or
arithmetic_method(name) and ex = Object::builtin("ArithmeticError") arithmeticMethod(name) and
execName = "ArithmeticError" and
message = "should raise an ArithmeticError or return NotImplemented instead."
or or
name = "__bool__" and ex = theTypeErrorType() name = "__bool__" and
execName = "TypeError" and
message = "should raise a TypeError instead."
} }
predicate no_need_to_raise(string name, string message) { /** Holds if `exec` is an exception object of the type named `execName`. */
name = "__hash__" and message = "use __hash__ = None instead" predicate execIsOfType(Expr exec, string execName) {
or // Might make sense to have execName be an IPA type here. Or part of a more general API modeling builtin/stdlib subclass relations.
cast_method(name) and message = "there is no need to implement the method at all." exists(string subclass |
} execName = "TypeError" and
subclass = "TypeError"
predicate is_abstract(FunctionObject func) {
func.getFunction().getADecorator().(Name).getId().matches("%abstract%")
}
predicate always_raises(FunctionObject f, ClassObject ex) {
ex = f.getARaisedType() and
strictcount(f.getARaisedType()) = 1 and
not exists(f.getFunction().getANormalExit()) and
/* raising StopIteration is equivalent to a return in a generator */
not ex = theStopIterationType()
}
from FunctionObject f, ClassObject cls, string message
where
f.getFunction().isSpecialMethod() and
not is_abstract(f) and
always_raises(f, cls) and
(
no_need_to_raise(f.getName(), message) and not cls.getName() = "NotImplementedError"
or or
not correct_raise(f.getName(), cls) and execName = "LookupError" and
not cls.getName() = "NotImplementedError" and subclass = ["LookupError", "KeyError", "IndexError"]
exists(ClassObject preferred | preferred_raise(f.getName(), preferred) | or
message = "raise " + preferred.getName() + " instead" execName = "ArithmeticError" and
subclass = ["ArithmeticError", "FloatingPointError", "OverflowError", "ZeroDivisionError"]
or
execName = "AttributeError" and
subclass = "AttributeError"
|
exec = API::builtin(subclass).getACall().asExpr()
or
exec = API::builtin(subclass).getASubclass().getACall().asExpr()
)
}
/**
* Holds if `meth` need not be implemented if it always raises. `message` is the alert message, and `allowNotImplemented` is true
* if we still allow the method to always raise `NotImplementedError`.
*/
predicate noNeedToAlwaysRaise(Function meth, string message, boolean allowNotImplemented) {
meth.getName() = "__hash__" and
message = "use __hash__ = None instead." and
allowNotImplemented = false
or
castMethod(meth.getName()) and
message = "this method does not need to be implemented." and
allowNotImplemented = true and
// Allow an always raising cast method if it's overriding other behavior
not exists(Function overridden |
overridden.getName() = meth.getName() and
overridden.getScope() = getADirectSuperclass+(meth.getScope()) and
not alwaysRaises(overridden, _)
)
}
/** Holds if `func` has a decorator likely marking it as an abstract method. */
predicate isAbstract(Function func) { func.getADecorator().(Name).getId().matches("%abstract%") }
/** Holds if `f` always raises the exception `exec`. */
predicate alwaysRaises(Function f, Expr exec) {
directlyRaises(f, exec) and
strictcount(Expr e | directlyRaises(f, e)) = 1 and
not exists(f.getANormalExit())
}
/** Holds if `f` directly raises `exec` using a `raise` statement. */
predicate directlyRaises(Function f, Expr exec) {
exists(Raise r |
r.getScope() = f and
exec = r.getException() and
exec instanceof Call
)
}
/** Holds if `exec` is a `NotImplementedError`. */
predicate isNotImplementedError(Expr exec) {
exec = API::builtin("NotImplementedError").getACall().asExpr()
}
/** Gets the name of the builtin exception type `exec` constructs, if it can be determined. */
string getExecName(Expr exec) { result = exec.(Call).getFunc().(Name).getId() }
from Function f, Expr exec, string message
where
f.isSpecialMethod() and
not isAbstract(f) and
directlyRaises(f, exec) and
(
exists(boolean allowNotImplemented, string subMessage |
alwaysRaises(f, exec) and
noNeedToAlwaysRaise(f, subMessage, allowNotImplemented) and
(allowNotImplemented = true implies not isNotImplementedError(exec)) and // don't alert if it's a NotImplementedError and that's ok
message = "This method always raises $@ - " + subMessage
)
or
not isNotImplementedError(exec) and
not correctRaise(f.getName(), exec) and
exists(string subMessage | preferredRaise(f.getName(), _, subMessage) |
if alwaysRaises(f, exec)
then message = "This method always raises $@ - " + subMessage
else message = "This method raises $@ - " + subMessage
) )
) )
select f, "Function always raises $@; " + message, cls, cls.toString() select f, message, exec, getExecName(exec)

View File

@@ -1,15 +0,0 @@
#Abstract base class, but don't declare it.
class ImplicitAbstractClass(object):
def __add__(self, other):
raise NotImplementedError()
#Make abstractness explicit.
class ExplicitAbstractClass:
__metaclass__ = ABCMeta
@abstractmethod
def __add__(self, other):
raise NotImplementedError()

View File

@@ -1,27 +0,0 @@
#Incorrect file-backed table
class FileBackedTable(object):
def __getitem__(self, key):
if key not in self.index:
raise IOError("Key '%s' not in table" % key)
else:
#May raise an IOError
return self.backing.get_row(key)
#Correct by transforming exception
class ObjectLikeFileBackedTable(object):
def get_from_key(self, key):
if key not in self.index:
raise IOError("Key '%s' not in table" % key)
else:
#May raise an IOError
return self.backing.get_row(key)
def __getitem__(self, key):
try:
return self.get_from_key(key)
except IOError:
raise KeyError(key)

View File

@@ -0,0 +1,22 @@
class A:
def __init__(self, a):
self.a = a
def __add__(self, other):
# BAD: Should return NotImplemented instead of raising
if not isinstance(other,A):
raise TypeError(f"Cannot add A to {other.__class__}")
return A(self.a + other.a)
class B:
def __init__(self, a):
self.a = a
def __add__(self, other):
# GOOD: Returning NotImplemented allows for the operation to fallback to other implementations to allow other classes to support adding to B.
if not isinstance(other,B):
return NotImplemented
return B(self.a + other.a)

View File

@@ -0,0 +1,7 @@
class C:
def __getitem__(self, idx):
if self.idx < 0:
# BAD: Should raise a KeyError or IndexError instead.
raise ValueError("Invalid index")
return self.lookup(idx)

View File

@@ -0,0 +1,4 @@
class D:
def __hash__(self):
# BAD: Use `__hash__ = None` instead.
raise NotImplementedError(f"{self.__class__} is unhashable.")

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* The `py/unexpected-raise-in-special-method` query has been modernized. It produces additional results in cases where the exception is
only raised conditionally. Its precision has been changed from `very-high` to `high`.

View File

@@ -0,0 +1,6 @@
| test.py:6:5:6:33 | Function __getitem__ | This method always raises $@ - should raise a LookupError (KeyError or IndexError) instead. | test.py:7:15:7:33 | ZeroDivisionError() | ZeroDivisionError |
| test.py:9:5:9:32 | Function __getattr__ | This method always raises $@ - should raise an AttributeError instead. | test.py:10:15:10:33 | ZeroDivisionError() | ZeroDivisionError |
| test.py:12:5:12:23 | Function __bool__ | This method always raises $@ - should raise a TypeError instead. | test.py:13:15:13:26 | ValueError() | ValueError |
| test.py:15:5:15:22 | Function __int__ | This method always raises $@ - this method does not need to be implemented. | test.py:16:15:16:26 | ValueError() | ValueError |
| test.py:24:5:24:23 | Function __hash__ | This method always raises $@ - use __hash__ = None instead. | test.py:25:15:25:35 | NotImplementedError() | NotImplementedError |
| test.py:28:5:28:29 | Function __sub__ | This method raises $@ - should raise an ArithmeticError or return NotImplemented instead. | test.py:30:19:30:29 | TypeError() | TypeError |

View File

@@ -0,0 +1,2 @@
query: Functions/IncorrectRaiseInSpecialMethod.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -0,0 +1,66 @@
class A:
def __add__(self, other): # No alert - Always allow NotImplementedError
raise NotImplementedError()
def __getitem__(self, index): # $ Alert
raise ZeroDivisionError()
def __getattr__(self, name): # $ Alert
raise ZeroDivisionError()
def __bool__(self): # $ Alert
raise ValueError()
def __int__(self): # $ Alert # Cast method need not be defined to always raise
raise ValueError()
def __float__(self): # No alert - OK to raise conditionally
if self.z:
return 0
else:
raise ValueError()
def __hash__(self): # $ Alert # should use __hash__=None rather than stub implementation to make class unhashable
raise NotImplementedError()
class B:
def __sub__(self, other): # $ Alert # should return NotImplemented instead
if not isinstance(other,B):
raise TypeError()
return self
def __add__(self, other): # No alert - allow add to raise a TypeError, as it is sometimes used for sequence concatenation as well as arithmetic
if not isinstance(other,B):
raise TypeError()
return self
def __setitem__(self, key, val): # No alert - allow setitem to raise arbitrary exceptions as they could be due to the value, rather than a LookupError relating to the key
if val < 0:
raise ValueError()
def __getitem__(self, key): # No alert - indexing method allowed to raise TypeError or subclasses of LookupError.
if not isinstance(key, int):
raise TypeError()
if key < 0:
raise KeyError()
return 3
def __getattribute__(self, name):
if name != "a":
raise AttributeError()
return 2
def __div__(self, other):
if other == 0:
raise ZeroDivisionError()
return self
class D:
def __int__(self):
return 2
class E(D):
def __int__(self): # No alert - cast method may override to raise exception
raise TypeError()

View File

@@ -1,3 +0,0 @@
| protocols.py:98:5:98:33 | Function __getitem__ | Function always raises $@; raise LookupError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError |
| protocols.py:101:5:101:26 | Function __getattr__ | Function always raises $@; raise AttributeError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError |
| protocols.py:104:5:104:23 | Function __bool__ | Function always raises $@; raise TypeError instead | file://:Compiled Code:0:0:0:0 | builtin-class ZeroDivisionError | builtin-class ZeroDivisionError |

View File

@@ -1 +0,0 @@
Functions/IncorrectRaiseInSpecialMethod.ql

View File

@@ -1,5 +1,5 @@
use crate::diagnostics::{ExtractionStep, emit_extraction_diagnostics}; use crate::diagnostics::{ExtractionStep, emit_extraction_diagnostics};
use crate::rust_analyzer::path_to_file_id; use crate::rust_analyzer::{RustAnalyzerNoSemantics, path_to_file_id};
use crate::translate::SourceKind; use crate::translate::SourceKind;
use crate::trap::TrapId; use crate::trap::TrapId;
use anyhow::Context; use anyhow::Context;
@@ -85,14 +85,12 @@ impl<'a> Extractor<'a> {
translator.emit_parse_error(&ast, &err); translator.emit_parse_error(&ast, &err);
} }
let no_location = (LineCol { line: 0, col: 0 }, LineCol { line: 0, col: 0 }); let no_location = (LineCol { line: 0, col: 0 }, LineCol { line: 0, col: 0 });
if let Err(reason) = semantics_info { if let Err(RustAnalyzerNoSemantics { severity, reason }) = semantics_info {
if !reason.is_empty() { if !reason.is_empty() {
let message = format!("semantic analyzer unavailable ({reason})"); let message = format!("semantic analyzer unavailable ({reason})");
let full_message = format!( let full_message = format!("{message}: macro expansion will be skipped.");
"{message}: macro expansion, call graph, and type inference will be skipped."
);
translator.emit_diagnostic( translator.emit_diagnostic(
trap::DiagnosticSeverity::Warning, severity,
"semantics".to_owned(), "semantics".to_owned(),
message, message,
full_message, full_message,
@@ -131,10 +129,10 @@ impl<'a> Extractor<'a> {
&mut self, &mut self,
file: &Path, file: &Path,
source_kind: SourceKind, source_kind: SourceKind,
reason: &str, err: RustAnalyzerNoSemantics,
) { ) {
self.extract( self.extract(
&RustAnalyzer::WithoutSemantics { reason }, &RustAnalyzer::from(err),
file, file,
source_kind, source_kind,
); );
@@ -158,21 +156,25 @@ impl<'a> Extractor<'a> {
file: &Path, file: &Path,
semantics: &Semantics<'_, RootDatabase>, semantics: &Semantics<'_, RootDatabase>,
vfs: &Vfs, vfs: &Vfs,
) -> Result<(), String> { ) -> Result<(), RustAnalyzerNoSemantics> {
let before = Instant::now(); let before = Instant::now();
let Some(id) = path_to_file_id(file, vfs) else { let Some(id) = path_to_file_id(file, vfs) else {
return Err("not included in files loaded from manifest".to_string()); return Err(RustAnalyzerNoSemantics::warning(
"not included in files loaded from manifest",
));
}; };
match semantics.file_to_module_def(id) { match semantics.file_to_module_def(id) {
None => return Err("not included as a module".to_string()), None => {
return Err(RustAnalyzerNoSemantics::info("not included as a module"));
}
Some(module) Some(module)
if module if module
.as_source_file_id(semantics.db) .as_source_file_id(semantics.db)
.is_none_or(|mod_file_id| mod_file_id.file_id(semantics.db) != id) => .is_none_or(|mod_file_id| mod_file_id.file_id(semantics.db) != id) =>
{ {
return Err( return Err(RustAnalyzerNoSemantics::info(
"not loaded as its own module, probably included by `!include`".to_string(), "not loaded as its own module, probably included by `!include`",
); ));
} }
_ => {} _ => {}
}; };
@@ -274,7 +276,11 @@ fn main() -> anyhow::Result<()> {
continue 'outer; continue 'outer;
} }
} }
extractor.extract_without_semantics(file, SourceKind::Source, "no manifest found"); extractor.extract_without_semantics(
file,
SourceKind::Source,
RustAnalyzerNoSemantics::warning("no manifest found"),
);
} }
let cwd = cwd()?; let cwd = cwd()?;
let (cargo_config, load_cargo_config) = cfg.to_cargo_config(&cwd); let (cargo_config, load_cargo_config) = cfg.to_cargo_config(&cwd);
@@ -308,7 +314,7 @@ fn main() -> anyhow::Result<()> {
vfs, vfs,
source_mode, source_mode,
), ),
Err(reason) => extractor.extract_without_semantics(file, source_mode, &reason), Err(e) => extractor.extract_without_semantics(file, source_mode, e),
}; };
} }
for (file_id, file) in vfs.iter() { for (file_id, file) in vfs.iter() {
@@ -335,7 +341,7 @@ fn main() -> anyhow::Result<()> {
extractor.extract_without_semantics( extractor.extract_without_semantics(
file, file,
SourceKind::Source, SourceKind::Source,
"unable to load manifest", RustAnalyzerNoSemantics::warning("unable to load manifest"),
); );
} }
} }
@@ -347,7 +353,7 @@ fn main() -> anyhow::Result<()> {
let entry = entry.context("failed to read builtins directory")?; let entry = entry.context("failed to read builtins directory")?;
let path = entry.path(); let path = entry.path();
if path.extension().is_some_and(|ext| ext == "rs") { if path.extension().is_some_and(|ext| ext == "rs") {
extractor.extract_without_semantics(&path, SourceKind::Library, ""); extractor.extract_without_semantics(&path, SourceKind::Library, Default::default());
} }
} }

View File

@@ -1,3 +1,4 @@
use crate::trap;
use itertools::Itertools; use itertools::Itertools;
use ra_ap_base_db::{EditionedFileId, FileText, RootQueryDb, SourceDatabase}; use ra_ap_base_db::{EditionedFileId, FileText, RootQueryDb, SourceDatabase};
use ra_ap_hir::Semantics; use ra_ap_hir::Semantics;
@@ -23,16 +24,47 @@ use std::rc::Rc;
use tracing::{debug, error, info, trace, warn}; use tracing::{debug, error, info, trace, warn};
use triomphe::Arc; use triomphe::Arc;
#[derive(Clone, Default)]
pub struct RustAnalyzerNoSemantics {
pub severity: trap::DiagnosticSeverity,
pub reason: &'static str,
}
impl RustAnalyzerNoSemantics {
pub fn warning(reason: &'static str) -> Self {
RustAnalyzerNoSemantics {
severity: trap::DiagnosticSeverity::Warning,
reason,
}
}
pub fn info(reason: &'static str) -> Self {
RustAnalyzerNoSemantics {
severity: trap::DiagnosticSeverity::Info,
reason,
}
}
}
pub enum RustAnalyzer<'a> { pub enum RustAnalyzer<'a> {
WithSemantics { WithSemantics {
vfs: &'a Vfs, vfs: &'a Vfs,
semantics: &'a Semantics<'a, RootDatabase>, semantics: &'a Semantics<'a, RootDatabase>,
}, },
WithoutSemantics { WithoutSemantics {
reason: &'a str, severity: trap::DiagnosticSeverity,
reason: &'static str,
}, },
} }
impl From<RustAnalyzerNoSemantics> for RustAnalyzer<'static> {
fn from(value: RustAnalyzerNoSemantics) -> Self {
RustAnalyzer::WithoutSemantics {
severity: value.severity,
reason: value.reason,
}
}
}
pub struct FileSemanticInformation<'a> { pub struct FileSemanticInformation<'a> {
pub file_id: EditionedFileId, pub file_id: EditionedFileId,
pub semantics: &'a Semantics<'a, RootDatabase>, pub semantics: &'a Semantics<'a, RootDatabase>,
@@ -42,7 +74,7 @@ pub struct ParseResult<'a> {
pub ast: SourceFile, pub ast: SourceFile,
pub text: Arc<str>, pub text: Arc<str>,
pub errors: Vec<SyntaxError>, pub errors: Vec<SyntaxError>,
pub semantics_info: Result<FileSemanticInformation<'a>, &'a str>, pub semantics_info: Result<FileSemanticInformation<'a>, RustAnalyzerNoSemantics>,
} }
impl<'a> RustAnalyzer<'a> { impl<'a> RustAnalyzer<'a> {
@@ -52,7 +84,7 @@ impl<'a> RustAnalyzer<'a> {
load_config: &LoadCargoConfig, load_config: &LoadCargoConfig,
) -> Option<(RootDatabase, Vfs)> { ) -> Option<(RootDatabase, Vfs)> {
let progress = |t| trace!("progress: {t}"); let progress = |t| trace!("progress: {t}");
let manifest = project.manifest_path(); let manifest: &ManifestPath = project.manifest_path();
match load_workspace_at(manifest.as_ref(), config, load_config, &progress) { match load_workspace_at(manifest.as_ref(), config, load_config, &progress) {
Ok((db, vfs, _macro_server)) => Some((db, vfs)), Ok((db, vfs, _macro_server)) => Some((db, vfs)),
Err(err) => { Err(err) => {
@@ -67,16 +99,25 @@ impl<'a> RustAnalyzer<'a> {
fn get_file_data( fn get_file_data(
&self, &self,
path: &Path, path: &Path,
) -> Result<(&Semantics<'_, RootDatabase>, EditionedFileId, FileText), &str> { ) -> Result<(&Semantics<'_, RootDatabase>, EditionedFileId, FileText), RustAnalyzerNoSemantics>
{
match self { match self {
RustAnalyzer::WithoutSemantics { reason } => Err(reason), RustAnalyzer::WithoutSemantics { severity, reason } => Err(RustAnalyzerNoSemantics {
severity: *severity,
reason,
}),
RustAnalyzer::WithSemantics { vfs, semantics } => { RustAnalyzer::WithSemantics { vfs, semantics } => {
let file_id = path_to_file_id(path, vfs).ok_or("file not found in project")?; let file_id = path_to_file_id(path, vfs).ok_or(
let input = std::panic::catch_unwind(|| semantics.db.file_text(file_id)) RustAnalyzerNoSemantics::warning("file not found in project"),
.or(Err("no text available for the file in the project"))?; )?;
let editioned_file_id = semantics let input = std::panic::catch_unwind(|| semantics.db.file_text(file_id)).or(
.attach_first_edition(file_id) Err(RustAnalyzerNoSemantics::warning(
.ok_or("failed to determine rust edition")?; "no text available for the file in the project",
)),
)?;
let editioned_file_id = semantics.attach_first_edition(file_id).ok_or(
RustAnalyzerNoSemantics::warning("failed to determine rust edition"),
)?;
Ok((semantics, editioned_file_id, input)) Ok((semantics, editioned_file_id, input))
} }
} }

View File

@@ -470,7 +470,7 @@ impl<'a> Translator<'a> {
mcall, mcall,
&SyntaxError::new( &SyntaxError::new(
format!( format!(
"macro expansion failed: could not resolve macro '{}'", "macro expansion failed for '{}'",
mcall.path().map(|p| p.to_string()).unwrap_or_default() mcall.path().map(|p| p.to_string()).unwrap_or_default()
), ),
range.unwrap_or_else(|| TextRange::empty(TextSize::from(0))), range.unwrap_or_else(|| TextRange::empty(TextSize::from(0))),

View File

@@ -127,9 +127,10 @@ pub struct TrapFile {
compression: Compression, compression: Compression,
} }
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
pub enum DiagnosticSeverity { pub enum DiagnosticSeverity {
Debug = 10, Debug = 10,
#[default]
Info = 20, Info = 20,
Warning = 30, Warning = 30,
Error = 40, Error = 40,

View File

@@ -1,4 +1,4 @@
lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll 06394c1314f09d65b8ade88732f1114202e1896ebeb8d687f8ee230cea01127b 7a9223854ec30cae886b237d7930120ce073ab49af486b0d3bc971df2a039e62 lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll 11c7521ec2231a4d0447f30fc3d0bb14aebb659bd8cf75935af1050673a3b1d6 d0a77b572a032e43f1c47622315c0cdfe17e68c2b057534b9322fc528029fb40
lib/codeql/rust/elements/Abi.qll 485a2e79f6f7bfd1c02a6e795a71e62dede3c3e150149d5f8f18b761253b7208 6159ba175e7ead0dd2e3f2788f49516c306ee11b1a443bd4bdc00b7017d559bd lib/codeql/rust/elements/Abi.qll 485a2e79f6f7bfd1c02a6e795a71e62dede3c3e150149d5f8f18b761253b7208 6159ba175e7ead0dd2e3f2788f49516c306ee11b1a443bd4bdc00b7017d559bd
lib/codeql/rust/elements/Addressable.qll 13011bfd2e1556694c3d440cc34af8527da4df49ad92b62f2939d3699ff2cea5 ddb25935f7553a1a384b1abe2e4b4fa90ab50b952dadec32fd867afcb054f4be lib/codeql/rust/elements/Addressable.qll 13011bfd2e1556694c3d440cc34af8527da4df49ad92b62f2939d3699ff2cea5 ddb25935f7553a1a384b1abe2e4b4fa90ab50b952dadec32fd867afcb054f4be
lib/codeql/rust/elements/Adt.qll c2afed4ac2e17039ccd98f74ea22111f4d765c4e232c50ccd3128da0d26da837 1380bde2eb667c6ec2ef5f8710aa24e926851c9e321ebc72ba514fa92c369dc3 lib/codeql/rust/elements/Adt.qll c2afed4ac2e17039ccd98f74ea22111f4d765c4e232c50ccd3128da0d26da837 1380bde2eb667c6ec2ef5f8710aa24e926851c9e321ebc72ba514fa92c369dc3
@@ -146,7 +146,7 @@ lib/codeql/rust/elements/Static.qll 9dca6d4fb80fb4ead49a3de89bec2b02bae6f96fbc26
lib/codeql/rust/elements/Stmt.qll 532b12973037301246daf7d8c0177f734202f43d9261c7a4ca6f5080eea8ca64 b838643c4f2b4623d2c816cddad0e68ca3e11f2879ab7beaece46f489ec4b1f3 lib/codeql/rust/elements/Stmt.qll 532b12973037301246daf7d8c0177f734202f43d9261c7a4ca6f5080eea8ca64 b838643c4f2b4623d2c816cddad0e68ca3e11f2879ab7beaece46f489ec4b1f3
lib/codeql/rust/elements/StmtList.qll e874859ce03672d0085e47e0ca5e571b92b539b31bf0d5a8802f9727bef0c6b0 e5fe83237f713cdb57c446a6e1c20f645c2f49d9f5ef2c984032df83acb3c0de lib/codeql/rust/elements/StmtList.qll e874859ce03672d0085e47e0ca5e571b92b539b31bf0d5a8802f9727bef0c6b0 e5fe83237f713cdb57c446a6e1c20f645c2f49d9f5ef2c984032df83acb3c0de
lib/codeql/rust/elements/Struct.qll 297d3ea732fc7fbb8b8fb5479c1873ce84705146853ff752c84a6f70af12b923 3df0e5fd50a910a0b5611c3a860a1d7c318f6925c3a0727006d91840caf04812 lib/codeql/rust/elements/Struct.qll 297d3ea732fc7fbb8b8fb5479c1873ce84705146853ff752c84a6f70af12b923 3df0e5fd50a910a0b5611c3a860a1d7c318f6925c3a0727006d91840caf04812
lib/codeql/rust/elements/StructExpr.qll af9059c01a97755e94f1a8b60c66d9c7663ed0705b2845b086b8953f16019fab 2d33d86b035a15c1b31c3e07e0e74c4bbe57a71c5a55d60e720827814e73b7ba lib/codeql/rust/elements/StructExpr.qll 84f384ef74c723796e514186037a91dd9666556f62c717f133ce22e9dda4425f 176497835252cfdfe110e58ebde9fbde553d03e44e07d3e4d8041e835dbf31b9
lib/codeql/rust/elements/StructExprField.qll 3eb9f17ecd1ad38679689eb4ecc169d3a0b5b7a3fc597ae5a957a7aea2f74e4f 8fcd26f266f203004899a60447ba16e7eae4e3a654fbec7f54e26857730ede93 lib/codeql/rust/elements/StructExprField.qll 3eb9f17ecd1ad38679689eb4ecc169d3a0b5b7a3fc597ae5a957a7aea2f74e4f 8fcd26f266f203004899a60447ba16e7eae4e3a654fbec7f54e26857730ede93
lib/codeql/rust/elements/StructExprFieldList.qll 6efb2ec4889b38556dc679bb89bbd4bd76ed6a60014c41f8e232288fc23b2d52 dc867a0a4710621e04b36bbec7d317d6f360e0d6ac68b79168c8b714babde31d lib/codeql/rust/elements/StructExprFieldList.qll 6efb2ec4889b38556dc679bb89bbd4bd76ed6a60014c41f8e232288fc23b2d52 dc867a0a4710621e04b36bbec7d317d6f360e0d6ac68b79168c8b714babde31d
lib/codeql/rust/elements/StructField.qll c43a552ce22c768c7f4c878501f08ecd4eae3554c5cd885dcd2e8625fe705233 bfd7934835ca41eb70e4064198d9b40ec9812842fb4349e412d1aaf98c3cd625 lib/codeql/rust/elements/StructField.qll c43a552ce22c768c7f4c878501f08ecd4eae3554c5cd885dcd2e8625fe705233 bfd7934835ca41eb70e4064198d9b40ec9812842fb4349e412d1aaf98c3cd625
@@ -159,7 +159,7 @@ lib/codeql/rust/elements/TokenTree.qll 23e57fd945ce509df5122aa46f7971360788945cb
lib/codeql/rust/elements/Trait.qll f78a917c2f2e5a0dfcd7c36e95ad67b1fa218484ee509610db8ca38453bebd4c 2a12f03870ebf86e104bdc3b61aae8512bfafbbf79a0cff5c3c27a04635926af lib/codeql/rust/elements/Trait.qll f78a917c2f2e5a0dfcd7c36e95ad67b1fa218484ee509610db8ca38453bebd4c 2a12f03870ebf86e104bdc3b61aae8512bfafbbf79a0cff5c3c27a04635926af
lib/codeql/rust/elements/TraitAlias.qll 1d82d043f24dbac04baa7aa3882c6884b8ffbc5d9b97669ce8efb7e2c8d3d2c8 505ba5426e87b3c49721f440fbc9ad6b0e7d89d1b1a51ca3fa3a6cc2d36f8b82 lib/codeql/rust/elements/TraitAlias.qll 1d82d043f24dbac04baa7aa3882c6884b8ffbc5d9b97669ce8efb7e2c8d3d2c8 505ba5426e87b3c49721f440fbc9ad6b0e7d89d1b1a51ca3fa3a6cc2d36f8b82
lib/codeql/rust/elements/TryExpr.qll cb452f53292a1396139f64a35f05bb11501f6b363f8affc9f2d5f1945ad4a647 d60ad731bfe256d0f0b688bdc31708759a3d990c11dee4f1d85ccc0d9e07bec9 lib/codeql/rust/elements/TryExpr.qll cb452f53292a1396139f64a35f05bb11501f6b363f8affc9f2d5f1945ad4a647 d60ad731bfe256d0f0b688bdc31708759a3d990c11dee4f1d85ccc0d9e07bec9
lib/codeql/rust/elements/TupleExpr.qll 561486554f0c397bc37c87894c56507771174bfb25f19b3bf258a94f67573e56 d523246820853ff0a7c6b5f9dbe73d42513cadd6d6b76ea7e64147140ac93c15 lib/codeql/rust/elements/TupleExpr.qll 1b1be270198f9d3db1c28c4caaa4a7fe9b5ae14651f1a10e2891a7d78d6ad18b 4f585aa684dfbff753e342903ddd60ee4d7c374b8bddeb645784d10903c90ae0
lib/codeql/rust/elements/TupleField.qll e20a991f7f1322cc7c05b2a8946d5017edb119812efa3e44daa94a5dff2d0c7b 8c25c9577fef8b5b9a4b285ceb7cfffcd8d89448035b1967cd7fda1503adfe13 lib/codeql/rust/elements/TupleField.qll e20a991f7f1322cc7c05b2a8946d5017edb119812efa3e44daa94a5dff2d0c7b 8c25c9577fef8b5b9a4b285ceb7cfffcd8d89448035b1967cd7fda1503adfe13
lib/codeql/rust/elements/TupleFieldList.qll b67cd2dec918d09e582467e5db7a38c8fa18350af591b43a1b450cd2026dbb67 22fdd1e77c16e3be4627ee7a45985b94785492d36056eeeff2c94b43450b48c8 lib/codeql/rust/elements/TupleFieldList.qll b67cd2dec918d09e582467e5db7a38c8fa18350af591b43a1b450cd2026dbb67 22fdd1e77c16e3be4627ee7a45985b94785492d36056eeeff2c94b43450b48c8
lib/codeql/rust/elements/TuplePat.qll 028cdea43868b0fdd2fc4c31ff25b6bbb40813e8aaccf72186051a280db7632e 38c56187971671e6a9dd0c6ccccb2ee4470aa82852110c6b89884496eb4abc64 lib/codeql/rust/elements/TuplePat.qll 028cdea43868b0fdd2fc4c31ff25b6bbb40813e8aaccf72186051a280db7632e 38c56187971671e6a9dd0c6ccccb2ee4470aa82852110c6b89884496eb4abc64
@@ -407,7 +407,7 @@ lib/codeql/rust/elements/internal/TraitConstructor.qll 1f790e63c32f1a22ae1b039ca
lib/codeql/rust/elements/internal/TryExprConstructor.qll 98e3077ebc4d76f687488b344f532b698512af215b66f0a74b5cea8ed180836c b95603c10c262911eeffdf4ccba14849e8443916b360e287963d5f2582d8e434 lib/codeql/rust/elements/internal/TryExprConstructor.qll 98e3077ebc4d76f687488b344f532b698512af215b66f0a74b5cea8ed180836c b95603c10c262911eeffdf4ccba14849e8443916b360e287963d5f2582d8e434
lib/codeql/rust/elements/internal/TryExprImpl.qll cacf43a49ba518be3f94e4a355f5889861edc41f77601eff27e0ed774eca6651 5f4a6a346ec457d5de89b32419e8b4c2deddc55e2d61dbb59842d7f34aa11c44 lib/codeql/rust/elements/internal/TryExprImpl.qll cacf43a49ba518be3f94e4a355f5889861edc41f77601eff27e0ed774eca6651 5f4a6a346ec457d5de89b32419e8b4c2deddc55e2d61dbb59842d7f34aa11c44
lib/codeql/rust/elements/internal/TupleExprConstructor.qll 71c38786723225d3d90399b8a085b2b2664c62256654db9e1288fadd56745b9d 639ad70b49ebadc027127fbdc9de14e5180169a4285908233bc38ccac6f14110 lib/codeql/rust/elements/internal/TupleExprConstructor.qll 71c38786723225d3d90399b8a085b2b2664c62256654db9e1288fadd56745b9d 639ad70b49ebadc027127fbdc9de14e5180169a4285908233bc38ccac6f14110
lib/codeql/rust/elements/internal/TupleExprImpl.qll 23a0e4367fbcfcec3e2cf4a429f329a222b399c6729dd60f7ea42550273a6132 615f3b4897fdcbfddcf5c58e6edd64bf6e395923af89cc4e2a336099168bb6ad lib/codeql/rust/elements/internal/TupleExprImpl.qll daabbc7dd36c615cdd8d3b59e06f4992a302b26554115711f733508836887abe 4c43a26e5f8b68d9d032bb5cd0af88cf9ac9b4b4e40af47dc85dd931ce9db6f8
lib/codeql/rust/elements/internal/TupleFieldConstructor.qll 89d3cf2540235044ed5a89706cfbdebc5cdf9180fd5b6d3376c79a1b2c0430c0 16861fe089aac8e42a5a90d81dd48d5015391d0a06c78ca02bd876d65378699f lib/codeql/rust/elements/internal/TupleFieldConstructor.qll 89d3cf2540235044ed5a89706cfbdebc5cdf9180fd5b6d3376c79a1b2c0430c0 16861fe089aac8e42a5a90d81dd48d5015391d0a06c78ca02bd876d65378699f
lib/codeql/rust/elements/internal/TupleFieldListConstructor.qll 4335ba2061b6e4968db9ec05c0b4d3e6a564db89a2df69e036f317672a7900b1 0b8dded875dbf696cf588e8c21acc27332a2ff66ced7bfabdfc1ad621991f888 lib/codeql/rust/elements/internal/TupleFieldListConstructor.qll 4335ba2061b6e4968db9ec05c0b4d3e6a564db89a2df69e036f317672a7900b1 0b8dded875dbf696cf588e8c21acc27332a2ff66ced7bfabdfc1ad621991f888
lib/codeql/rust/elements/internal/TupleFieldListImpl.qll 74869e92a3cbdd7895adaaa418d29d5e97387daf46c17315f219ad967af15d76 5815e4b37db958663df1f6fedc9667a11b261c9c2133e3f983a3aedc452c01fc lib/codeql/rust/elements/internal/TupleFieldListImpl.qll 74869e92a3cbdd7895adaaa418d29d5e97387daf46c17315f219ad967af15d76 5815e4b37db958663df1f6fedc9667a11b261c9c2133e3f983a3aedc452c01fc
@@ -587,7 +587,11 @@ lib/codeql/rust/elements/internal/generated/PtrTypeRepr.qll 8d0ea4f6c7f8203340bf
lib/codeql/rust/elements/internal/generated/PureSynthConstructors.qll e5b8e69519012bbaae29dcb82d53f7f7ecce368c0358ec27ef6180b228a0057f e5b8e69519012bbaae29dcb82d53f7f7ecce368c0358ec27ef6180b228a0057f lib/codeql/rust/elements/internal/generated/PureSynthConstructors.qll e5b8e69519012bbaae29dcb82d53f7f7ecce368c0358ec27ef6180b228a0057f e5b8e69519012bbaae29dcb82d53f7f7ecce368c0358ec27ef6180b228a0057f
lib/codeql/rust/elements/internal/generated/RangeExpr.qll 23cca03bf43535f33b22a38894f70d669787be4e4f5b8fe5c8f7b964d30e9027 18624cef6c6b679eeace2a98737e472432e0ead354cca02192b4d45330f047c9 lib/codeql/rust/elements/internal/generated/RangeExpr.qll 23cca03bf43535f33b22a38894f70d669787be4e4f5b8fe5c8f7b964d30e9027 18624cef6c6b679eeace2a98737e472432e0ead354cca02192b4d45330f047c9
lib/codeql/rust/elements/internal/generated/RangePat.qll 80826a6a6868a803aa2372e31c52a03e1811a3f1f2abdb469f91ca0bfdd9ecb6 34ee1e208c1690cba505dff2c588837c0cd91e185e2a87d1fe673191962276a9 lib/codeql/rust/elements/internal/generated/RangePat.qll 80826a6a6868a803aa2372e31c52a03e1811a3f1f2abdb469f91ca0bfdd9ecb6 34ee1e208c1690cba505dff2c588837c0cd91e185e2a87d1fe673191962276a9
<<<<<<< HEAD
lib/codeql/rust/elements/internal/generated/Raw.qll 53fc373ce72ac66e58c68f27e90f627f190590d226602f55b38827422aa1c78a 958aaf7f788fe126de27610203a87cf9fdd8a02f2d2e2dd77e69a7b8fef5db55 lib/codeql/rust/elements/internal/generated/Raw.qll 53fc373ce72ac66e58c68f27e90f627f190590d226602f55b38827422aa1c78a 958aaf7f788fe126de27610203a87cf9fdd8a02f2d2e2dd77e69a7b8fef5db55
=======
lib/codeql/rust/elements/internal/generated/Raw.qll b32f6737ca918cf003f294cc809546e3e89fa9f91666b20aab8acaa6fb986094 aeecf005da2fcfcc6e143c7970866f476f3b146632ed6bb36ccb5db19570c11b
>>>>>>> main
lib/codeql/rust/elements/internal/generated/RefExpr.qll 7d995884e3dc1c25fc719f5d7253179344d63650e217e9ff6530285fe7a57f64 f2c3c12551deea4964b66553fb9b6423ee16fec53bd63db4796191aa60dc6c66 lib/codeql/rust/elements/internal/generated/RefExpr.qll 7d995884e3dc1c25fc719f5d7253179344d63650e217e9ff6530285fe7a57f64 f2c3c12551deea4964b66553fb9b6423ee16fec53bd63db4796191aa60dc6c66
lib/codeql/rust/elements/internal/generated/RefPat.qll 456ede39837463ee22a630ec7ab6c8630d3664a8ea206fcc6e4f199e92fa564c 5622062765f32930465ba6b170e986706f159f6070f48adee3c20e24e8df4e05 lib/codeql/rust/elements/internal/generated/RefPat.qll 456ede39837463ee22a630ec7ab6c8630d3664a8ea206fcc6e4f199e92fa564c 5622062765f32930465ba6b170e986706f159f6070f48adee3c20e24e8df4e05
lib/codeql/rust/elements/internal/generated/RefTypeRepr.qll 5b0663a6d234572fb3e467e276d019415caa95ef006438cc59b7af4e1783161e 0e27c8a8f0e323c0e4d6db01fca821bf07c0864d293cdf96fa891b10820c1e4b lib/codeql/rust/elements/internal/generated/RefTypeRepr.qll 5b0663a6d234572fb3e467e276d019415caa95ef006438cc59b7af4e1783161e 0e27c8a8f0e323c0e4d6db01fca821bf07c0864d293cdf96fa891b10820c1e4b
@@ -604,7 +608,7 @@ lib/codeql/rust/elements/internal/generated/Static.qll 1a6c87d3c5602e3d02268ebe2
lib/codeql/rust/elements/internal/generated/Stmt.qll 8473ff532dd5cc9d7decaddcd174b94d610f6ca0aec8e473cc051dad9f3db917 6ef7d2b5237c2dbdcacbf7d8b39109d4dc100229f2b28b5c9e3e4fbf673ba72b lib/codeql/rust/elements/internal/generated/Stmt.qll 8473ff532dd5cc9d7decaddcd174b94d610f6ca0aec8e473cc051dad9f3db917 6ef7d2b5237c2dbdcacbf7d8b39109d4dc100229f2b28b5c9e3e4fbf673ba72b
lib/codeql/rust/elements/internal/generated/StmtList.qll 816aebf8f56e179f5f0ba03e80d257ee85459ea757392356a0af6dbd0cd9ef5e 6aa51cdcdc8d93427555fa93f0e84afdfbbd4ffc8b8d378ae4a22b5b6f94f48b lib/codeql/rust/elements/internal/generated/StmtList.qll 816aebf8f56e179f5f0ba03e80d257ee85459ea757392356a0af6dbd0cd9ef5e 6aa51cdcdc8d93427555fa93f0e84afdfbbd4ffc8b8d378ae4a22b5b6f94f48b
lib/codeql/rust/elements/internal/generated/Struct.qll 999da1b46e40d6e03fd2338fea02429462877c329c5d1338618cbd886a81567e daa7ff7bd32c554462e0a1502d8319cb5e734e056d0564e06596e416e2b88e9d lib/codeql/rust/elements/internal/generated/Struct.qll 999da1b46e40d6e03fd2338fea02429462877c329c5d1338618cbd886a81567e daa7ff7bd32c554462e0a1502d8319cb5e734e056d0564e06596e416e2b88e9d
lib/codeql/rust/elements/internal/generated/StructExpr.qll c6d861eaa0123b103fd9ffd2485423419ef9b7e0b4af9ed2a2090d8ec534f65d 50da99ee44771e1239ed8919f711991dd3ec98589fbe49b49b68c88074a07d74 lib/codeql/rust/elements/internal/generated/StructExpr.qll e77702890561102af38f52d836729e82569c964f8d4c7e680b27992c1ff0f141 23dc51f68107ab0e5c9dd88a6bcc85bb66e8e0f4064cb4d416f50f2ba5db698c
lib/codeql/rust/elements/internal/generated/StructExprField.qll 6bdc52ed325fd014495410c619536079b8c404e2247bd2435aa7685dd56c3833 501a30650cf813176ff325a1553da6030f78d14be3f84fea6d38032f4262c6b0 lib/codeql/rust/elements/internal/generated/StructExprField.qll 6bdc52ed325fd014495410c619536079b8c404e2247bd2435aa7685dd56c3833 501a30650cf813176ff325a1553da6030f78d14be3f84fea6d38032f4262c6b0
lib/codeql/rust/elements/internal/generated/StructExprFieldList.qll 298d33442d1054922d2f97133a436ee559f1f35b7708523284d1f7eee7ebf443 7febe38a79fadf3dcb53fb8f8caf4c2780f5df55a1f8336269c7b674d53c6272 lib/codeql/rust/elements/internal/generated/StructExprFieldList.qll 298d33442d1054922d2f97133a436ee559f1f35b7708523284d1f7eee7ebf443 7febe38a79fadf3dcb53fb8f8caf4c2780f5df55a1f8336269c7b674d53c6272
lib/codeql/rust/elements/internal/generated/StructField.qll 0ccd678b64b82fdab7ffe9eb74f0d393b22da4459fe72248828896b5204c009c 0faf5a517eccc43141a48809ed35b864341a35764de2dba7442daa899ff4ff69 lib/codeql/rust/elements/internal/generated/StructField.qll 0ccd678b64b82fdab7ffe9eb74f0d393b22da4459fe72248828896b5204c009c 0faf5a517eccc43141a48809ed35b864341a35764de2dba7442daa899ff4ff69
@@ -619,7 +623,7 @@ lib/codeql/rust/elements/internal/generated/TokenTree.qll 1a3c4f5f30659738641abd
lib/codeql/rust/elements/internal/generated/Trait.qll 8fa41b50fa0f68333534f2b66bb4ec8e103ff09ac8fa5c2cc64bc04beafec205 ce1c9aa6d0e2f05d28aab8e1165c3b9fb8e24681ade0cf6a9df2e8617abeae7e lib/codeql/rust/elements/internal/generated/Trait.qll 8fa41b50fa0f68333534f2b66bb4ec8e103ff09ac8fa5c2cc64bc04beafec205 ce1c9aa6d0e2f05d28aab8e1165c3b9fb8e24681ade0cf6a9df2e8617abeae7e
lib/codeql/rust/elements/internal/generated/TraitAlias.qll 40a296cf89eceaf02a32db90acb42bdc90df10e717bae3ab95bc09d842360a5b af85cf1f8fa46a8b04b763cdcacc6643b83c074c58c1344e485157d2ceb26306 lib/codeql/rust/elements/internal/generated/TraitAlias.qll 40a296cf89eceaf02a32db90acb42bdc90df10e717bae3ab95bc09d842360a5b af85cf1f8fa46a8b04b763cdcacc6643b83c074c58c1344e485157d2ceb26306
lib/codeql/rust/elements/internal/generated/TryExpr.qll 73052d7d309427a30019ad962ee332d22e7e48b9cc98ee60261ca2df2f433f93 d9dd70bf69eaa22475acd78bea504341e3574742a51ad9118566f39038a02d85 lib/codeql/rust/elements/internal/generated/TryExpr.qll 73052d7d309427a30019ad962ee332d22e7e48b9cc98ee60261ca2df2f433f93 d9dd70bf69eaa22475acd78bea504341e3574742a51ad9118566f39038a02d85
lib/codeql/rust/elements/internal/generated/TupleExpr.qll 75186da7c077287b9a86fc9194221ab565d458c08a5f80b763e73be5b646b29f 0250d75c43e2e6f56cdc8a0c00cc42b3d459ea8d48172d236c8cdf0fe96dfed2 lib/codeql/rust/elements/internal/generated/TupleExpr.qll 98f10bc72d09f98e3be87f41b1a3cbf037f4a7e3d3560dfa6d5759905a8177a5 6a9eb5568c518876b2912371e2b7b774cf5245097c5a0206eda35b749995f00b
lib/codeql/rust/elements/internal/generated/TupleField.qll d546b4e0c1a0b243c2bf88b371377cf9a396ca497cd5e78915e0e552910b6093 c0a754d15e0de590ee15139d8d366e4d7e4d33882c943e6ea8fa5fa8dce790e3 lib/codeql/rust/elements/internal/generated/TupleField.qll d546b4e0c1a0b243c2bf88b371377cf9a396ca497cd5e78915e0e552910b6093 c0a754d15e0de590ee15139d8d366e4d7e4d33882c943e6ea8fa5fa8dce790e3
lib/codeql/rust/elements/internal/generated/TupleFieldList.qll fb76d1a395326361859177c05e90e5bbb22d37518758752e9d89906006fb683e f31508b120c36f569cc7dcae06c9e55cf875abfb2fbe54a64ec12d8b3d2db108 lib/codeql/rust/elements/internal/generated/TupleFieldList.qll fb76d1a395326361859177c05e90e5bbb22d37518758752e9d89906006fb683e f31508b120c36f569cc7dcae06c9e55cf875abfb2fbe54a64ec12d8b3d2db108
lib/codeql/rust/elements/internal/generated/TuplePat.qll 4e13b509e1c9dd1581a9dc50d38e0a6e36abc1254ea9c732b5b3e6503335afeb 298028df9eb84e106e625ed09d6b20038ad47bfc2faf634a0ffea50b17b5805d lib/codeql/rust/elements/internal/generated/TuplePat.qll 4e13b509e1c9dd1581a9dc50d38e0a6e36abc1254ea9c732b5b3e6503335afeb 298028df9eb84e106e625ed09d6b20038ad47bfc2faf634a0ffea50b17b5805d

View File

@@ -1 +0,0 @@
| src/directory_module/not_loaded.rs:1:1:1:1 | semantic analyzer unavailable (not included as a module) | Extraction warning in src/directory_module/not_loaded.rs with message semantic analyzer unavailable (not included as a module) | 1 |

View File

@@ -1,9 +1,9 @@
| Extraction errors | 0 | | Extraction errors | 0 |
| Extraction warnings | 1 | | Extraction warnings | 0 |
| Files extracted - total | 5 | | Files extracted - total | 5 |
| Files extracted - with errors | 1 | | Files extracted - with errors | 0 |
| Files extracted - without errors | 4 | | Files extracted - without errors | 5 |
| Files extracted - without errors % | 80 | | Files extracted - without errors % | 100 |
| Inconsistencies - AST | 0 | | Inconsistencies - AST | 0 |
| Inconsistencies - CFG | 0 | | Inconsistencies - CFG | 0 |
| Inconsistencies - Path resolution | 0 | | Inconsistencies - Path resolution | 0 |

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Attribute macros are now taken into account when identifying macro-expanded code. This affects the queries `rust/unused-variable` and `rust/unused-value`, which exclude results in macro-expanded code.

View File

@@ -2944,8 +2944,8 @@ module MakeCfgNodes<LocationSig Loc, InputSig<Loc> Input> {
* ```rust * ```rust
* let first = Foo { a: 1, b: 2 }; * let first = Foo { a: 1, b: 2 };
* let second = Foo { a: 2, ..first }; * let second = Foo { a: 2, ..first };
* Foo { a: 1, b: 2 }[2] = 10; * let n = Foo { a: 1, b: 2 }.b;
* Foo { .. } = second; * Foo { a: m, .. } = second;
* ``` * ```
*/ */
final class StructExprCfgNode extends CfgNodeFinal, ExprCfgNode { final class StructExprCfgNode extends CfgNodeFinal, ExprCfgNode {
@@ -3063,8 +3063,9 @@ module MakeCfgNodes<LocationSig Loc, InputSig<Loc> Input> {
/** /**
* A tuple expression. For example: * A tuple expression. For example:
* ```rust * ```rust
* (1, "one"); * let tuple = (1, "one");
* (2, "two")[0] = 3; * let n = (2, "two").0;
* let (a, b) = tuple;
* ``` * ```
*/ */
final class TupleExprCfgNode extends CfgNodeFinal, ExprCfgNode { final class TupleExprCfgNode extends CfgNodeFinal, ExprCfgNode {

View File

@@ -13,8 +13,8 @@ import codeql.rust.elements.StructExprFieldList
* ```rust * ```rust
* let first = Foo { a: 1, b: 2 }; * let first = Foo { a: 1, b: 2 };
* let second = Foo { a: 2, ..first }; * let second = Foo { a: 2, ..first };
* Foo { a: 1, b: 2 }[2] = 10; * let n = Foo { a: 1, b: 2 }.b;
* Foo { .. } = second; * Foo { a: m, .. } = second;
* ``` * ```
*/ */
final class StructExpr = Impl::StructExpr; final class StructExpr = Impl::StructExpr;

View File

@@ -10,8 +10,9 @@ import codeql.rust.elements.Expr
/** /**
* A tuple expression. For example: * A tuple expression. For example:
* ```rust * ```rust
* (1, "one"); * let tuple = (1, "one");
* (2, "two")[0] = 3; * let n = (2, "two").0;
* let (a, b) = tuple;
* ``` * ```
*/ */
final class TupleExpr = Impl::TupleExpr; final class TupleExpr = Impl::TupleExpr;

View File

@@ -19,6 +19,8 @@ module Impl {
or or
n = root.(Adt).getDeriveMacroExpansion(_) n = root.(Adt).getDeriveMacroExpansion(_)
or or
n = root.(Item).getAttributeMacroExpansion()
or
isInMacroExpansion(root, n.getParentNode()) isInMacroExpansion(root, n.getParentNode())
} }

View File

@@ -20,8 +20,8 @@ module Impl {
* ```rust * ```rust
* let first = Foo { a: 1, b: 2 }; * let first = Foo { a: 1, b: 2 };
* let second = Foo { a: 2, ..first }; * let second = Foo { a: 2, ..first };
* Foo { a: 1, b: 2 }[2] = 10; * let n = Foo { a: 1, b: 2 }.b;
* Foo { .. } = second; * Foo { a: m, .. } = second;
* ``` * ```
*/ */
class StructExpr extends Generated::StructExpr { class StructExpr extends Generated::StructExpr {

View File

@@ -15,8 +15,9 @@ module Impl {
/** /**
* A tuple expression. For example: * A tuple expression. For example:
* ```rust * ```rust
* (1, "one"); * let tuple = (1, "one");
* (2, "two")[0] = 3; * let n = (2, "two").0;
* let (a, b) = tuple;
* ``` * ```
*/ */
class TupleExpr extends Generated::TupleExpr { } class TupleExpr extends Generated::TupleExpr { }

View File

@@ -3346,8 +3346,9 @@ module Raw {
* INTERNAL: Do not use. * INTERNAL: Do not use.
* A tuple expression. For example: * A tuple expression. For example:
* ```rust * ```rust
* (1, "one"); * let tuple = (1, "one");
* (2, "two")[0] = 3; * let n = (2, "two").0;
* let (a, b) = tuple;
* ``` * ```
*/ */
class TupleExpr extends @tuple_expr, Expr { class TupleExpr extends @tuple_expr, Expr {
@@ -4054,6 +4055,63 @@ module Raw {
/** /**
* INTERNAL: Do not use. * INTERNAL: Do not use.
<<<<<<< HEAD
=======
* A path pattern. For example:
* ```rust
* match x {
* Foo::Bar => "ok",
* _ => "fail",
* }
* ```
*/
class PathPat extends @path_pat, Pat, PathAstNode {
override string toString() { result = "PathPat" }
}
/**
* INTERNAL: Do not use.
* A struct expression. For example:
* ```rust
* let first = Foo { a: 1, b: 2 };
* let second = Foo { a: 2, ..first };
* let n = Foo { a: 1, b: 2 }.b;
* Foo { a: m, .. } = second;
* ```
*/
class StructExpr extends @struct_expr, Expr, PathAstNode {
override string toString() { result = "StructExpr" }
/**
* Gets the struct expression field list of this struct expression, if it exists.
*/
StructExprFieldList getStructExprFieldList() {
struct_expr_struct_expr_field_lists(this, result)
}
}
/**
* INTERNAL: Do not use.
* A struct pattern. For example:
* ```rust
* match x {
* Foo { a: 1, b: 2 } => "ok",
* Foo { .. } => "fail",
* }
* ```
*/
class StructPat extends @struct_pat, Pat, PathAstNode {
override string toString() { result = "StructPat" }
/**
* Gets the struct pattern field list of this struct pattern, if it exists.
*/
StructPatFieldList getStructPatFieldList() { struct_pat_struct_pat_field_lists(this, result) }
}
/**
* INTERNAL: Do not use.
>>>>>>> main
* A Trait. For example: * A Trait. For example:
* ``` * ```
* trait Frobinizable { * trait Frobinizable {

View File

@@ -20,8 +20,8 @@ module Generated {
* ```rust * ```rust
* let first = Foo { a: 1, b: 2 }; * let first = Foo { a: 1, b: 2 };
* let second = Foo { a: 2, ..first }; * let second = Foo { a: 2, ..first };
* Foo { a: 1, b: 2 }[2] = 10; * let n = Foo { a: 1, b: 2 }.b;
* Foo { .. } = second; * Foo { a: m, .. } = second;
* ``` * ```
* INTERNAL: Do not reference the `Generated::StructExpr` class directly. * INTERNAL: Do not reference the `Generated::StructExpr` class directly.
* Use the subclass `StructExpr`, where the following predicates are available. * Use the subclass `StructExpr`, where the following predicates are available.

View File

@@ -18,8 +18,9 @@ module Generated {
/** /**
* A tuple expression. For example: * A tuple expression. For example:
* ```rust * ```rust
* (1, "one"); * let tuple = (1, "one");
* (2, "two")[0] = 3; * let n = (2, "two").0;
* let (a, b) = tuple;
* ``` * ```
* INTERNAL: Do not reference the `Generated::TupleExpr` class directly. * INTERNAL: Do not reference the `Generated::TupleExpr` class directly.
* Use the subclass `TupleExpr`, where the following predicates are available. * Use the subclass `TupleExpr`, where the following predicates are available.

View File

@@ -82,14 +82,23 @@ abstract class Type extends TType {
pragma[nomagic] pragma[nomagic]
abstract TupleField getTupleField(int i); abstract TupleField getTupleField(int i);
/** Gets the `i`th type parameter of this type, if any. */ /**
abstract TypeParameter getTypeParameter(int i); * Gets the `i`th positional type parameter of this type, if any.
*
* This excludes synthetic type parameters, such as associated types in traits.
*/
abstract TypeParameter getPositionalTypeParameter(int i);
/** Gets the default type for the `i`th type parameter, if any. */ /** Gets the default type for the `i`th type parameter, if any. */
TypeMention getTypeParameterDefault(int i) { none() } TypeMention getTypeParameterDefault(int i) { none() }
/** Gets a type parameter of this type. */ /**
final TypeParameter getATypeParameter() { result = this.getTypeParameter(_) } * Gets a type parameter of this type.
*
* This includes both positional type parameters and synthetic type parameters,
* such as associated types in traits.
*/
TypeParameter getATypeParameter() { result = this.getPositionalTypeParameter(_) }
/** Gets a textual representation of this type. */ /** Gets a textual representation of this type. */
abstract string toString(); abstract string toString();
@@ -108,7 +117,9 @@ class TupleType extends Type, TTuple {
override TupleField getTupleField(int i) { none() } override TupleField getTupleField(int i) { none() }
override TypeParameter getTypeParameter(int i) { result = TTupleTypeParameter(arity, i) } override TypeParameter getPositionalTypeParameter(int i) {
result = TTupleTypeParameter(arity, i)
}
/** Gets the arity of this tuple type. */ /** Gets the arity of this tuple type. */
int getArity() { result = arity } int getArity() { result = arity }
@@ -141,7 +152,7 @@ class StructType extends StructOrEnumType, TStruct {
override TupleField getTupleField(int i) { result = struct.getTupleField(i) } override TupleField getTupleField(int i) { result = struct.getTupleField(i) }
override TypeParameter getTypeParameter(int i) { override TypeParameter getPositionalTypeParameter(int i) {
result = TTypeParamTypeParameter(struct.getGenericParamList().getTypeParam(i)) result = TTypeParamTypeParameter(struct.getGenericParamList().getTypeParam(i))
} }
@@ -166,7 +177,7 @@ class EnumType extends StructOrEnumType, TEnum {
override TupleField getTupleField(int i) { none() } override TupleField getTupleField(int i) { none() }
override TypeParameter getTypeParameter(int i) { override TypeParameter getPositionalTypeParameter(int i) {
result = TTypeParamTypeParameter(enum.getGenericParamList().getTypeParam(i)) result = TTypeParamTypeParameter(enum.getGenericParamList().getTypeParam(i))
} }
@@ -192,10 +203,18 @@ class TraitType extends Type, TTrait {
override TupleField getTupleField(int i) { none() } override TupleField getTupleField(int i) { none() }
override TypeParameter getTypeParameter(int i) { override TypeParameter getPositionalTypeParameter(int i) {
result = TTypeParamTypeParameter(trait.getGenericParamList().getTypeParam(i)) result = TTypeParamTypeParameter(trait.getGenericParamList().getTypeParam(i))
} }
override TypeParameter getATypeParameter() {
result = super.getATypeParameter()
or
result.(AssociatedTypeTypeParameter).getTrait() = trait
or
result.(SelfTypeParameter).getTrait() = trait
}
override TypeMention getTypeParameterDefault(int i) { override TypeMention getTypeParameterDefault(int i) {
result = trait.getGenericParamList().getTypeParam(i).getDefaultType() result = trait.getGenericParamList().getTypeParam(i).getDefaultType()
} }
@@ -218,7 +237,7 @@ class ArrayType extends Type, TArrayType {
override TupleField getTupleField(int i) { none() } override TupleField getTupleField(int i) { none() }
override TypeParameter getTypeParameter(int i) { override TypeParameter getPositionalTypeParameter(int i) {
result = TArrayTypeParameter() and result = TArrayTypeParameter() and
i = 0 i = 0
} }
@@ -241,7 +260,7 @@ class RefType extends Type, TRefType {
override TupleField getTupleField(int i) { none() } override TupleField getTupleField(int i) { none() }
override TypeParameter getTypeParameter(int i) { override TypeParameter getPositionalTypeParameter(int i) {
result = TRefTypeParameter() and result = TRefTypeParameter() and
i = 0 i = 0
} }
@@ -274,7 +293,7 @@ class ImplTraitType extends Type, TImplTraitType {
override TupleField getTupleField(int i) { none() } override TupleField getTupleField(int i) { none() }
override TypeParameter getTypeParameter(int i) { override TypeParameter getPositionalTypeParameter(int i) {
exists(TypeParam tp | exists(TypeParam tp |
implTraitTypeParam(impl, i, tp) and implTraitTypeParam(impl, i, tp) and
result = TImplTraitTypeParameter(impl, tp) result = TImplTraitTypeParameter(impl, tp)
@@ -295,10 +314,19 @@ class DynTraitType extends Type, TDynTraitType {
override TupleField getTupleField(int i) { none() } override TupleField getTupleField(int i) { none() }
override DynTraitTypeParameter getTypeParameter(int i) { override DynTraitTypeParameter getPositionalTypeParameter(int i) {
result = TDynTraitTypeParameter(trait.getGenericParamList().getTypeParam(i)) result = TDynTraitTypeParameter(trait.getGenericParamList().getTypeParam(i))
} }
override TypeParameter getATypeParameter() {
result = super.getATypeParameter()
or
exists(AstNode n |
dynTraitTypeParameter(trait, n) and
result = TDynTraitTypeParameter(n)
)
}
Trait getTrait() { result = trait } Trait getTrait() { result = trait }
override string toString() { result = "dyn " + trait.getName().toString() } override string toString() { result = "dyn " + trait.getName().toString() }
@@ -336,7 +364,7 @@ class SliceType extends Type, TSliceType {
override TupleField getTupleField(int i) { none() } override TupleField getTupleField(int i) { none() }
override TypeParameter getTypeParameter(int i) { override TypeParameter getPositionalTypeParameter(int i) {
result = TSliceTypeParameter() and result = TSliceTypeParameter() and
i = 0 i = 0
} }
@@ -352,7 +380,7 @@ abstract class TypeParameter extends Type {
override TupleField getTupleField(int i) { none() } override TupleField getTupleField(int i) { none() }
override TypeParameter getTypeParameter(int i) { none() } override TypeParameter getPositionalTypeParameter(int i) { none() }
} }
private class RawTypeParameter = @type_param or @trait or @type_alias or @impl_trait_type_repr; private class RawTypeParameter = @type_param or @trait or @type_alias or @impl_trait_type_repr;
@@ -548,7 +576,7 @@ class ImplTraitTypeTypeParameter extends ImplTraitType, TypeParameter {
override TupleField getTupleField(int i) { none() } override TupleField getTupleField(int i) { none() }
override TypeParameter getTypeParameter(int i) { none() } override TypeParameter getPositionalTypeParameter(int i) { none() }
} }
/** /**

View File

@@ -374,6 +374,20 @@ private module CertainTypeInference {
or or
result = inferLiteralType(n, path, true) result = inferLiteralType(n, path, true)
or or
result = inferRefNodeType(n) and
path.isEmpty()
or
result = inferTupleRootType(n) and
path.isEmpty()
or
result = inferAsyncBlockExprRootType(n) and
path.isEmpty()
or
result = inferArrayExprType(n) and
path.isEmpty()
or
result = inferCastExprType(n, path)
or
infersCertainTypeAt(n, path, result.getATypeParameter()) infersCertainTypeAt(n, path, result.getATypeParameter())
} }
@@ -405,7 +419,7 @@ private module CertainTypeInference {
inferCertainType(n, path) != t inferCertainType(n, path) != t
or or
// If we infer that `n` has _some_ type at `T1.T2....Tn`, and we also // If we infer that `n` has _some_ type at `T1.T2....Tn`, and we also
// know that `n` certainly has type `certainType` at `T1.T2...Ti`, `i <=0 < n`, // know that `n` certainly has type `certainType` at `T1.T2...Ti`, `0 <= i < n`,
// then it must be the case that `T(i+1)` is a type parameter of `certainType`, // then it must be the case that `T(i+1)` is a type parameter of `certainType`,
// otherwise there is a conflict. // otherwise there is a conflict.
// //
@@ -2366,30 +2380,18 @@ private module Cached {
or or
result = inferStructExprType(n, path) result = inferStructExprType(n, path)
or or
result = inferTupleRootType(n) and
path.isEmpty()
or
result = inferPathExprType(n, path) result = inferPathExprType(n, path)
or or
result = inferCallExprBaseType(n, path) result = inferCallExprBaseType(n, path)
or or
result = inferFieldExprType(n, path) result = inferFieldExprType(n, path)
or or
result = inferRefNodeType(n) and
path.isEmpty()
or
result = inferTryExprType(n, path) result = inferTryExprType(n, path)
or or
result = inferLiteralType(n, path, false) result = inferLiteralType(n, path, false)
or or
result = inferAsyncBlockExprRootType(n) and
path.isEmpty()
or
result = inferAwaitExprType(n, path) result = inferAwaitExprType(n, path)
or or
result = inferArrayExprType(n) and
path.isEmpty()
or
result = inferRangeExprType(n) and result = inferRangeExprType(n) and
path.isEmpty() path.isEmpty()
or or
@@ -2401,8 +2403,6 @@ private module Cached {
or or
result = inferClosureExprType(n, path) result = inferClosureExprType(n, path)
or or
result = inferCastExprType(n, path)
or
result = inferStructPatType(n, path) result = inferStructPatType(n, path)
or or
result = inferTupleStructPatType(n, path) result = inferTupleStructPatType(n, path)

View File

@@ -182,7 +182,7 @@ class NonAliasPathTypeMention extends PathTypeMention {
private TypeMention getTypeMentionForTypeParameter(TypeParameter tp) { private TypeMention getTypeMentionForTypeParameter(TypeParameter tp) {
exists(int i | exists(int i |
result = this.getPositionalTypeArgument(pragma[only_bind_into](i)) and result = this.getPositionalTypeArgument(pragma[only_bind_into](i)) and
tp = this.resolveRootType().getTypeParameter(pragma[only_bind_into](i)) tp = this.resolveRootType().getPositionalTypeParameter(pragma[only_bind_into](i))
) )
or or
exists(TypeAlias alias | exists(TypeAlias alias |

View File

@@ -116,7 +116,7 @@ SourceFile/gen_source_file.rs c0469cc8f0ecce3dd2e77963216d7e8808046014533359a44c
Static/gen_static.rs 21314018ea184c1ddcb594d67bab97ae18ceaf663d9f120f39ff755d389dde7a 21314018ea184c1ddcb594d67bab97ae18ceaf663d9f120f39ff755d389dde7a Static/gen_static.rs 21314018ea184c1ddcb594d67bab97ae18ceaf663d9f120f39ff755d389dde7a 21314018ea184c1ddcb594d67bab97ae18ceaf663d9f120f39ff755d389dde7a
StmtList/gen_stmt_list.rs adbd82045a50e2051434ce3cdd524c9f2c6ad9f3dd02b4766fb107e2e99212db adbd82045a50e2051434ce3cdd524c9f2c6ad9f3dd02b4766fb107e2e99212db StmtList/gen_stmt_list.rs adbd82045a50e2051434ce3cdd524c9f2c6ad9f3dd02b4766fb107e2e99212db adbd82045a50e2051434ce3cdd524c9f2c6ad9f3dd02b4766fb107e2e99212db
Struct/gen_struct.rs 5e181e90075f716c04c75e4ef0334abe3d5f419cd9ccfadfe595c09fab33566b 5e181e90075f716c04c75e4ef0334abe3d5f419cd9ccfadfe595c09fab33566b Struct/gen_struct.rs 5e181e90075f716c04c75e4ef0334abe3d5f419cd9ccfadfe595c09fab33566b 5e181e90075f716c04c75e4ef0334abe3d5f419cd9ccfadfe595c09fab33566b
StructExpr/gen_struct_expr.rs 8dd9a578625a88623c725b8afdfd8b636e1c3c991fe96c55b24d4b283d2212fb 8dd9a578625a88623c725b8afdfd8b636e1c3c991fe96c55b24d4b283d2212fb StructExpr/gen_struct_expr.rs e7824008b0b73d02f6243fd8a18e0ef93c63bfe775a878fc2679c3870fc342fd e7824008b0b73d02f6243fd8a18e0ef93c63bfe775a878fc2679c3870fc342fd
StructExprField/gen_struct_expr_field.rs 4ccca8e8ad462b4873f5604f0afdd1836027b8d39e36fbe7d6624ef3e744a084 4ccca8e8ad462b4873f5604f0afdd1836027b8d39e36fbe7d6624ef3e744a084 StructExprField/gen_struct_expr_field.rs 4ccca8e8ad462b4873f5604f0afdd1836027b8d39e36fbe7d6624ef3e744a084 4ccca8e8ad462b4873f5604f0afdd1836027b8d39e36fbe7d6624ef3e744a084
StructExprFieldList/gen_struct_expr_field_list.rs bc17e356690cfb1cd51f7dbe5ac88c0b9188c9bf94b9e3cc82581120190f33dc bc17e356690cfb1cd51f7dbe5ac88c0b9188c9bf94b9e3cc82581120190f33dc StructExprFieldList/gen_struct_expr_field_list.rs bc17e356690cfb1cd51f7dbe5ac88c0b9188c9bf94b9e3cc82581120190f33dc bc17e356690cfb1cd51f7dbe5ac88c0b9188c9bf94b9e3cc82581120190f33dc
StructField/gen_struct_field.rs 0884e458732ab74b4c7debee4fbef014f847815be5a6ddeba467844d33607c6e 0884e458732ab74b4c7debee4fbef014f847815be5a6ddeba467844d33607c6e StructField/gen_struct_field.rs 0884e458732ab74b4c7debee4fbef014f847815be5a6ddeba467844d33607c6e 0884e458732ab74b4c7debee4fbef014f847815be5a6ddeba467844d33607c6e
@@ -128,7 +128,7 @@ TokenTree/gen_token_tree.rs 3fdc9a36a1870bb2bedf66c8fe37d368f4ac18488e7118b86e39
Trait/gen_trait.rs bac694993e224f9c6dd86cfb28c54846ae1b3bae45a1e58d3149c884184487ea bac694993e224f9c6dd86cfb28c54846ae1b3bae45a1e58d3149c884184487ea Trait/gen_trait.rs bac694993e224f9c6dd86cfb28c54846ae1b3bae45a1e58d3149c884184487ea bac694993e224f9c6dd86cfb28c54846ae1b3bae45a1e58d3149c884184487ea
TraitAlias/gen_trait_alias.rs 425d78a7cb87db7737ceaf713c9a62e0411537374d1bc58c5b1fb80cc25732c9 425d78a7cb87db7737ceaf713c9a62e0411537374d1bc58c5b1fb80cc25732c9 TraitAlias/gen_trait_alias.rs 425d78a7cb87db7737ceaf713c9a62e0411537374d1bc58c5b1fb80cc25732c9 425d78a7cb87db7737ceaf713c9a62e0411537374d1bc58c5b1fb80cc25732c9
TryExpr/gen_try_expr.rs f60198181a423661f4ed1bf6f98d475f40ada190b7b5fc6af97aa5e45ca29a1e f60198181a423661f4ed1bf6f98d475f40ada190b7b5fc6af97aa5e45ca29a1e TryExpr/gen_try_expr.rs f60198181a423661f4ed1bf6f98d475f40ada190b7b5fc6af97aa5e45ca29a1e f60198181a423661f4ed1bf6f98d475f40ada190b7b5fc6af97aa5e45ca29a1e
TupleExpr/gen_tuple_expr.rs 8ecd1b6ecc58a0319eed434a423cc6f41bdf1901b1950e6e79735d7f7b2f8374 8ecd1b6ecc58a0319eed434a423cc6f41bdf1901b1950e6e79735d7f7b2f8374 TupleExpr/gen_tuple_expr.rs 27e56846b3f08c37c8a345169c2a532b2023d231d46a5bdf586bbc6d8fb36a01 27e56846b3f08c37c8a345169c2a532b2023d231d46a5bdf586bbc6d8fb36a01
TupleField/gen_tuple_field.rs 5d6b4f356af895541f975cc1fd90116fd047fe914c2049d47f61e4a43a8c2af4 5d6b4f356af895541f975cc1fd90116fd047fe914c2049d47f61e4a43a8c2af4 TupleField/gen_tuple_field.rs 5d6b4f356af895541f975cc1fd90116fd047fe914c2049d47f61e4a43a8c2af4 5d6b4f356af895541f975cc1fd90116fd047fe914c2049d47f61e4a43a8c2af4
TupleFieldList/gen_tuple_field_list.rs 42f0af8c391fb9e33fe09b791e0e719cadf5143b58764f8a5d38f8d9054daca7 42f0af8c391fb9e33fe09b791e0e719cadf5143b58764f8a5d38f8d9054daca7 TupleFieldList/gen_tuple_field_list.rs 42f0af8c391fb9e33fe09b791e0e719cadf5143b58764f8a5d38f8d9054daca7 42f0af8c391fb9e33fe09b791e0e719cadf5143b58764f8a5d38f8d9054daca7
TuplePat/gen_tuple_pat.rs b1b0c9c5ff1b787f380644691c77807655a4f6441fc7431c90ecf78c54c26148 b1b0c9c5ff1b787f380644691c77807655a4f6441fc7431c90ecf78c54c26148 TuplePat/gen_tuple_pat.rs b1b0c9c5ff1b787f380644691c77807655a4f6441fc7431c90ecf78c54c26148 b1b0c9c5ff1b787f380644691c77807655a4f6441fc7431c90ecf78c54c26148

View File

@@ -1,15 +1,15 @@
instances instances
| gen_struct_expr.rs:5:17:5:34 | Foo {...} | | gen_struct_expr.rs:5:17:5:34 | Foo {...} |
| gen_struct_expr.rs:6:18:6:38 | Foo {...} | | gen_struct_expr.rs:6:18:6:38 | Foo {...} |
| gen_struct_expr.rs:7:5:7:22 | Foo {...} | | gen_struct_expr.rs:7:13:7:30 | Foo {...} |
| gen_struct_expr.rs:8:5:8:14 | Foo {...} | | gen_struct_expr.rs:8:5:8:20 | Foo {...} |
getPath getPath
| gen_struct_expr.rs:5:17:5:34 | Foo {...} | gen_struct_expr.rs:5:17:5:19 | Foo | | gen_struct_expr.rs:5:17:5:34 | Foo {...} | gen_struct_expr.rs:5:17:5:19 | Foo |
| gen_struct_expr.rs:6:18:6:38 | Foo {...} | gen_struct_expr.rs:6:18:6:20 | Foo | | gen_struct_expr.rs:6:18:6:38 | Foo {...} | gen_struct_expr.rs:6:18:6:20 | Foo |
| gen_struct_expr.rs:7:5:7:22 | Foo {...} | gen_struct_expr.rs:7:5:7:7 | Foo | | gen_struct_expr.rs:7:13:7:30 | Foo {...} | gen_struct_expr.rs:7:13:7:15 | Foo |
| gen_struct_expr.rs:8:5:8:14 | Foo {...} | gen_struct_expr.rs:8:5:8:7 | Foo | | gen_struct_expr.rs:8:5:8:20 | Foo {...} | gen_struct_expr.rs:8:5:8:7 | Foo |
getStructExprFieldList getStructExprFieldList
| gen_struct_expr.rs:5:17:5:34 | Foo {...} | gen_struct_expr.rs:5:21:5:34 | StructExprFieldList | | gen_struct_expr.rs:5:17:5:34 | Foo {...} | gen_struct_expr.rs:5:21:5:34 | StructExprFieldList |
| gen_struct_expr.rs:6:18:6:38 | Foo {...} | gen_struct_expr.rs:6:22:6:38 | StructExprFieldList | | gen_struct_expr.rs:6:18:6:38 | Foo {...} | gen_struct_expr.rs:6:22:6:38 | StructExprFieldList |
| gen_struct_expr.rs:7:5:7:22 | Foo {...} | gen_struct_expr.rs:7:9:7:22 | StructExprFieldList | | gen_struct_expr.rs:7:13:7:30 | Foo {...} | gen_struct_expr.rs:7:17:7:30 | StructExprFieldList |
| gen_struct_expr.rs:8:5:8:14 | Foo {...} | gen_struct_expr.rs:8:9:8:14 | StructExprFieldList | | gen_struct_expr.rs:8:5:8:20 | Foo {...} | gen_struct_expr.rs:8:9:8:20 | StructExprFieldList |

Some files were not shown because too many files have changed in this diff Show More