I'm porting C++ app from Solaris to Linux and I'm stuck with the following error. The code is:
template <class MapSuperClass> class FWPointerMap : public MapSuperClass
{
public:
FWPointerMap()
{
_wipe = false;
}
FWPointerMap(const MapSuperClass* mMap)
{
MapSuperClass::const_iterator it = mMap->begin(); // line 50
while(it != mMap->end())
{
insert(MapSuperClass::value_type((*it).first, (*it).second));
it++;
}
_wipe = false;
}
And I get the following error:
../../framework/fwcore/hdr/FWPointerMap: In constructor FWPointerMap<MapSuperClass>::FWPointerMap(const MapSuperClass*):
../../framework/fwcore/hdr/FWPointerMap:50: error: expected ; before it
../../framework/fwcore/hdr/FWPointerMap:52: error: it was not declared in this scope
I think you just need to add 'typename' to tell the compiler that MapSuperClass::const_iterator is a type:
typename MapSuperClass::const_iterator it = mMap->begin(); // line 50
Because MaySuperClass is a class template parameter, the assumption is that the const_iterator member is a field. Using typename informs the compiler that it is in fact a type.
More information: http://en.wikipedia.org/wiki/Typename#A_method_for_indicating_that_a_dependent_name_is_a_type
Related
I have followed the ideas I saw on the internet:
UpdateColumnIndexVector(m_vColumnIndexesToExclude, WriteColumnIndexesToExclude);
That calls:
void CCreateReportDlg::UpdateColumnIndexVector(ColumnIndexVector &rvData, std::function<void()> WriteToRegistry)
{
bool bModified = true;
// Code simplified
if (bModified)
{
WriteToRegistry();
}
}
The function being passed in:
void CCreateReportDlg::WriteColumnIndexesToExclude()
{
ByteVector vData(m_vColumnIndexesToExclude.begin(), m_vColumnIndexesToExclude.end()); // int to BYTE
const CString strSection = theApp.GetActiveScheduleSection(_T("Options"));
theApp.WriteProfileVector(strSection, _T("AssignStatesEx"), vData);
}
When I compile:
error C3867: CCreateReportDlg::WriteColumnIndexesToExclude: non-standard syntax; use & to create a pointer to member
Yet, if I change this line to:
UpdateColumnIndexVector(m_vColumnIndexesToExclude, &WriteColumnIndexesToExclude);
That does not compile either:
error C2276: &: illegal operation on bound member function expression
error C2660: CCreateReportDlg::UpdateColumnIndexVector: function does not take 1 arguments
WriteColumnIndexesToExclude is a private member of the dialog class.
What am I doing wrong?
PS. My project is MFC C++ Dialog.
I'd like to match on all the ways a particular argument to a function can be null. Right now I'm using
hasArgument(
3,
anyOf(
cxxNullPtrLiteralExpr()
,integerLiteral() // Technically this would alert on a constant pointer; but that's madness
)
)
However this doesn't match the following code:
void* nullObj = nullptr;
function(nullptr, false, false, nullObj);
Is it possible/easy to track this and match it? Right now I have a very simpler matcher but I guess this type of analysis requires considerably more logic?
High-level answer
You can't just "match" an expression whose value is NULL. AST matching can only inspect the syntax of the argument, so if the argument is not a literal, you don't know if it might be NULL.
Instead, you need to use a flow-sensitive checker that queries the Clang SA constraint engine. The constraint engine tracks values as they flow through the program.
The core of such a checker looks like this:
bool NullArgChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
ProgramStateRef state = C.getState();
auto SVal = C.getSVal(CE->getArg(0)).getAs<DefinedOrUnknownSVal>();
if (SVal) {
ConditionTruthVal Nullness = state->isNull(*SVal);
if (Nullness.isConstrainedTrue()) {
Given a call expression CE, we get its first argument, then query the CheckerContext for the symbolic value SVal associated with the first argument. We then ask if that value is known to be NULL.
Complete example
Here is a complete example checker that reports a warning every time it sees a value known to be NULL being passed as the first argument of any function.
NullArgChecker.cpp:
// NullArgChecker.cpp
// https://stackoverflow.com/questions/57665383/how-can-i-match-a-pointer-to-a-null-object
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
using namespace clang;
using namespace ento;
namespace {
class NullArgChecker : public Checker< eval::Call > {
mutable std::unique_ptr<BuiltinBug> BT_nullarg;
public:
NullArgChecker() {}
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
};
} // end anonymous namespace
bool NullArgChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
ProgramStateRef state = C.getState();
auto SVal = C.getSVal(CE->getArg(0)).getAs<DefinedOrUnknownSVal>();
if (SVal) {
// This is the core of this example checker: we query the constraint
// engine to see if the symbolic value associated with the first
// argument is known to be NULL along the current path.
ConditionTruthVal Nullness = state->isNull(*SVal);
if (Nullness.isConstrainedTrue()) {
// Create a warning for this condition.
ExplodedNode *N = C.generateErrorNode();
if (N) {
if (!BT_nullarg) {
BT_nullarg.reset(new BuiltinBug(
this, "Null Argument", "The first argument is NULL."));
}
C.emitReport(llvm::make_unique<BugReport>(
*BT_nullarg, BT_nullarg->getDescription(), N));
}
}
}
return false;
}
void ento::registerNullArgChecker(CheckerManager &mgr) {
mgr.registerChecker<NullArgChecker>();
}
bool ento::shouldRegisterNullArgChecker(const LangOptions &LO) {
return true;
}
Changes to other files to hook this in:
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
## -148,6 +148,10 ## def NonnullGlobalConstantsChecker: Checker<"NonnilStringCon
stants">,
let ParentPackage = CoreAlpha in {
+def NullArgChecker : Checker<"NullArg">,
+ HelpText<"Check for passing a NULL argument">,
+ Documentation<NotDocumented>;
+
def BoolAssignmentChecker : Checker<"BoolAssignment">,
HelpText<"Warn about assigning non-{0,1} values to Boolean variables">,
Documentation<HasAlphaDocumentation>;
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
## -62,6 +62,7 ## add_clang_library(clangStaticAnalyzerCheckers
NonNullParamChecker.cpp
NonnullGlobalConstantsChecker.cpp
NullabilityChecker.cpp
+ NullArgChecker.cpp
NumberObjectConversionChecker.cpp
ObjCAtSyncChecker.cpp
ObjCAutoreleaseWriteChecker.cpp
Example input to test it on:
// nullargpp.cpp
// Testing NullArg checker with C++.
#include <stddef.h> // NULL
void somefunc(int*);
void nullarg1()
{
somefunc(NULL); // reported
somefunc(0); // reported
somefunc(nullptr); // reported
}
void nullarg2()
{
int *p = 0;
somefunc(p); // reported
}
void nullarg3(int *p)
{
if (p) {
somefunc(p); // not reported
}
else {
somefunc(p); // reported
}
}
void not_nullarg(int *p)
{
somefunc(p); // not reported
}
Example run:
$ g++ -std=c++11 -E -o nullargpp.ii nullargpp.cpp
$ ~/bld/llvm-project/build/bin/clang -cc1 -analyze -analyzer-checker=alpha.core.NullArg nullargpp.ii
nullargpp.cpp:10:3: warning: The first argument is NULL
somefunc(
^~~~~~~~~
nullargpp.cpp:11:3: warning: The first argument is NULL
somefunc(0);
^~~~~~~~~~~
nullargpp.cpp:12:3: warning: The first argument is NULL
somefunc(nullptr);
^~~~~~~~~~~~~~~~~
nullargpp.cpp:18:3: warning: The first argument is NULL
somefunc(p);
^~~~~~~~~~~
nullargpp.cpp:27:5: warning: The first argument is NULL
somefunc(p);
^~~~~~~~~~~
5 warnings generated.
For maximum specificity, the above changes were made to llvm-project commit 05efe0fdc4 (March 2019), running on Linux, but should work with any Clang v9.
Code
BOOL CGrAllObjects::ReorderObj(CGrObject* pGrFind,int ixObjNewIx)
{
int nSubCode,nLyrCode=pGrFind->GetLayerCode(nSubCode);
CGrObject* pGrObject;
CGrObjectArray*
pGrObjectArray=GetObjArrayFromCode(nLyrCode,nSubCode);
if(!pGrObjectArray) return FALSE;
for(int ixObj=pGrObjectArray->GetSize()-1; ixObj>=0; ixObj--)
{ pGrObject=pGrObjectArray->GetAt(ixObj);
if(pGrObject==pGrFind) break;
}
if(ixObj<0) return FALSE;
if(ixObj!=ixObjNewIx)
{ pGrObjectArray->RemoveAt(ixObj);
pGrObjectArray->InsertAt(ixObjNewIx,pGrFind);
}
return TRUE;
}
Error: 1>c:\xxx\xxx\xxxx\xxxx\xxxx\xxxxx\xxxx.cpp(359) : error C2065:
'ixObj' : undeclared identifier
for(int ixObj ... the variable "ixObj" is only defined in the scope of the for loop and is not known outside.
Define the integer before the loop, and remove the decalration from 'for':
int ixObj;
for(ixObj=...
The following code compiles to Javascript and runs OK, http://try.haxe.org/#8C940
abstract Comparable(Dynamic) from Float from String {
#:op(a<b) static function lt(a, b):Bool;
}
class Test {
public static function min<T:Comparable>(t:T, t2:T):T {
return (t:Comparable) < (t2:Comparable) ? t : t2;
}
static function main() {
var a = min(1.1,2.2); //ok
$type(a); //Float
trace(a); //1.1
var b = min(1,2); //ok
$type(b); //Int
trace(b); //1
var c = min("a","b"); //ok
$type(c); //String
trace(c); //a
//following will produce compilation error, correctly
//min(0, "a");
}
}
But when compiled for neko, it gives the following error:
Main.hx:7: characters 12-13 : Unexpected :
Main.hx:7: characters 12-13 : Unexpected :
Uncaught exception - load.c(181) : Module not found : main.n
The error in question is line:
return (t:Comparable) < (t2:Comparable) ? t : t2;
Any ideas why the language featuer works in one target but not the other? And how can I fix the issue for neko?
Thanks.
i guess you have a compiler version conflict, can you try the latest development builds:
http://hxbuilds.s3-website-us-east-1.amazonaws.com/builds/haxe/
(you can find the link here: http://haxe.org/manual/haxe3#git-builds -- edit: this page does not exist any more, but the build page is available via http://build.haxe.org)
I'm trying to recompile older code in latest Visual Studio (2008) and code that worked previously now fails to compile. One of the problems is due to overloaded operators for my class. below there is simplified class to demonstrate the problem. If I remove casting operators for int and char* then it works fine. So one of the ways to fix my issue is to replace them with procedures to_char and to_int and use them instead but it will require a lot of changes in the code (that class is heavily used). There must be some better, smarter way to fix it. any help is greatly appreciated :-)
class test
{
public:
test();
test(char* s2);
test(int num);
test(test &source);
~test();
operator char*();
operator int();
};
test::test() {
}
test::test(char* s2) {
}
test::test(int num) {
}
test::test(test &source) {
}
test::operator char*() {
}
test::operator int() {
}
test test_proc() {
test aa;
return aa;
}
int test_proc2(test aa)
{
return 0;
}
int main()
{
test_proc2(test_proc());
}
//test.cpp(60) : error C2664: 'test_proc2' : cannot convert parameter 1 from 'test' to 'test'
// Cannot copy construct class 'test' due to ambiguous copy constructors or no available copy constructor
Try changing
test(test &source);
to
test(const test &source);
The issue is that the test_proc call returns a temporary test object, which can be passed to a function that accepts a const reference, but not a plain reference.