Hi, Test gcc.dg/analyzer/pr94362-1.c actually has an additional null_deref > warning in C++, which is not affected by exceptions > or optimizations. I will keep updated on that one. Note that no warnings > are emitted for this test in C. > > analyzer/pr94362-1.c: In function ‘const EVP_PKEY_ASN1_METHOD* > EVP_PKEY_asn1_find_str(ENGINE**, const char*, int)’: > analyzer/pr94362-1.c:55:16: warning: dereference of NULL ‘ameth’ [CWE-476] > [-Wanalyzer-null-dereference] > analyzer/pr94362-1.c:39:29: note: (1) entry to ‘EVP_PKEY_asn1_find_str’ > analyzer/pr94362-1.c:42:31: note: (2) ‘ameth’ is NULL > analyzer/pr94362-1.c:53:43: note: (3) following ‘true’ branch... > analyzer/pr94362-1.c:54:31: note: (4) ...to here > analyzer/pr94362-1.c:54:31: note: (5) calling ‘EVP_PKEY_asn1_get0’ from > ‘EVP_PKEY_asn1_find_str’ > analyzer/pr94362-1.c:29:29: note: (6) entry to ‘EVP_PKEY_asn1_get0’ > analyzer/pr94362-1.c:32:53: note: (7) ‘0’ is NULL > analyzer/pr94362-1.c:54:31: note: (8) returning to > ‘EVP_PKEY_asn1_find_str’ from ‘EVP_PKEY_asn1_get0’ > analyzer/pr94362-1.c:54:31: note: (9) ‘ameth’ is NULL > analyzer/pr94362-1.c:55:16: note: (10) dereference of NULL ‘ameth’ > > > Cheers, > Benjamin. > > As promised a quick update on that front. I've managed to pinpoint the difference between the C and C++. Compiling with -fno-exceptions -O0 the two IPA's seen by the analyzer are nearly identical, if not for one difference.
const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(ENGINE **pe, const char *str, int len) { int i; const EVP_PKEY_ASN1_METHOD *ameth = (const EVP_PKEY_ASN1_METHOD *) ((void *)0); ... for (i = EVP_PKEY_asn1_get_count(); i-- > 0;) { ameth = EVP_PKEY_asn1_get0(i); /* At this point, i >= 0 */ if (ameth->pkey_flags & 0x1) continue; return ameth; } ... } IPA when compiled by as C: <bb 6> : i_23 = EVP_PKEY_asn1_get_count (); goto <bb 10>; [INV] <bb 7> : ameth_27 = EVP_PKEY_asn1_get0 (i_24); _2 = ameth_27->pkey_flags; _3 = _2 & 1; if (_3 != 0) goto <bb 8>; [INV] else goto <bb 9>; [INV] <bb 8> : // predicted unlikely by continue predictor. goto <bb 10>; [INV] <bb 9> : _28 = ameth_27; goto <bb 12>; [INV] <bb 10> : # i_5 = PHI <i_23(6), i_24(8)> i.4_4 = i_5; i_24 = i.4_4 + -1; if (i.4_4 > 0) goto <bb 7>; [INV] else goto <bb 11>; [INV] ... and as C++ <bb 6> : i_23 = EVP_PKEY_asn1_get_count (); goto <bb 10>; [INV] <bb 7> : ameth_28 = EVP_PKEY_asn1_get0 (i_24); _2 = ameth_28->pkey_flags; _3 = _2 & 1; if (_3 != 0) goto <bb 8>; [INV] else goto <bb 9>; [INV] <bb 8> : // predicted unlikely by continue predictor. goto <bb 10>; [INV] <bb 9> : _29 = ameth_28; goto <bb 12>; [INV] <bb 10> : # i_5 = PHI <i_23(6), i_24(8)> i.5_4 = i_5; i_24 = i.5_4 + -1; retval.4_25 = i.5_4 > 0; /* Difference here. C++ stores the comparison's result before using it */ if (retval.4_25 != 0) goto <bb 7>; [INV] else goto <bb 11>; [INV] This slight difference causes i_24 to not be part of an equivalence class in C++, although it is part of one in C. Therefore when calling ameth_28 = EVP_PKEY_asn1_get0 (i_24);, i_24 won't appear as constrained in C++, although we know it to be positive. Info is lost. Further down the line, because of this missing ec constraint_manager::eval_condition will evaluate to UNKNOWN, and the pending diagnostic path won't be refused but accepted as feasible in C++. constraints and equivalence classes in C: ec2: {(CONJURED(_8 = sk_EVP_PKEY_ASN1_METHOD_num (app_methos.1_2);, _8)+(int)1)} ec3: {(int)0 == [m_constant]'0'} /* int since constraining 'int i_24' */ ec4: {CONJURED(_8 = sk_EVP_PKEY_ASN1_METHOD_num (app_methos.1_2);, _8)} /* This is the ec of i_24 */ ec5: {(int)-1 == [m_constant]'-1'} constraints: 1: ec5 < ec4 2: ec3 < ec2 ... vs C++'s: ec2: {((CONJURED(_8 = sk_EVP_PKEY_ASN1_METHOD_num (app_methos.1_2);, _8)+(int)1)>(int)0)} ec3: {(bool)0 == [m_constant]'0'} /* bool instead of int cuz constraining 'bool retval.4_25' */ constraints: 1: ec2 != ec3 As you can see, i_24 equivalence class does not appear in C++. I'm considering if in a condition lhs or rhs is a logical binop svalue, we should unwrap one level, so that the condition's constraint is actually applied on the inner svalue. Cheers, Benjamin.