How do i analyse a complex project like open62541? - frama-c

I am a student and currently trying to analyse the reference implementation for the OPC Ua protocol in C with cppcheck and frama-c. My goal is not to do very dedicated testing but more some general/basic tests to see if there are some obvious issues with the code.
The project can be found here
I am running a VM with Ubuntu 19.10 and Frama-C version 20.0 (Calcium).
The steps i performed are as follows:
git clone https://github.com/open62541/open62541.git
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 /path/to/source
frama-c -json-compilation-database /path/to/compile_commands.json
Until now everything works as expected and there are no Errors.
However now i am having trouble understanding how to continue.
Do i need to do my analysis on all files seperately or is it possible to throw in the whole project like with cppcheck?
How would i approach this in general? Do i need to to analyse all files step by step?
For example i tried:
frama-c -json-compilation-database /path/to/compilation_commands.json -val /path/to/open62541/src/
which returns:
[kernel] Parsing src (with preprocessing)
gcc: warning: /path/to/open62541/src/: linker input file unused because linking not done
[kernel] User Error: cannot find entry point `main'.
Please use option `-main' for specifying a valid entry point.
[kernel] Frama-C aborted: invalid user input.
So apperantly frama-c requires an entry point, however i do not know which entry point i need to specify.
Any help regarding this is much appreciated.
I apologize for my lack of understanding. This is my first project of this kind and i am a little bit overwhelmed by frama-c and the complexity of the open62541 project.

Do i need to do my analysis on all files separately or is it possible to throw in the whole project like with cppcheck?
Frama-C can actually analyze the entire project in one go provided multiple files do not define the same symbols. See http://blog.frama-c.com/index.php?post/2018/01/25/Analysis-scripts%3A-helping-automate-case-studies, paragraph "Setting sources and testing parsing":
The list of source files to be given to Frama-C can be obtained from the compile_commands.json file. However, it is often the case that the software under analysis contains several binaries, each requiring a different set of sources. The JSON compilation database does not map the sources used to produce each binary, so it is not always possible to entirely automate the process.
The key point in your case is that the compilation_commands.json instructs Frama-C on how to parse each file, but you must still supply the files you want to see parsed yourself. With your current command-line, Frama-C tries to interpret /path/to/open62541/src/ as a file (and fails), and has no other file to parse. This is why you get the error User Error: cannot find entry point 'main'.
Thus, you must specify the files you want to parse on the command-line. This can be done in two ways:
manually, by extracting the files referenced in compilation_commands.json
automatically, using the frama-c-script helpers, described at http://blog.frama-c.com/index.php?post/2019/01/16/Setting-up-an-analysis-with-the-help-of-frama-c-script
I used the first approach, but I suggest you use the second, as frama-c-script is very helpful to start a first analysis.
Once you have done this listing step, you will encounter at least three more problems:
Frama-C will choke on # include <sys/param.h>, because this file is not present in the standard C library bundled with Frama-C. Either remove this include in the source files, or add an empty sys/param.h somewhere
some .c files refer to generated headers that are not present in the git repo of open62541. So you will need to compile the repo to get those headers before launching Frama-C.
Frama-C will also choke on the definition of the macro UA_STATIC_ASSERT in architecture_definitions.h. I did not investigate whether one of the definitions was accepted, and I simply defined it to the empty macro.
After all this, you should be good to go.

Related

How do i set up 'make install' to check the md5 of the installed libs/bins and only installed if changed?

I've inherited a fairly large project that is built using autoconfigure/automake (the configure.ac/Makefile.am files have their own issues, but that's a separate question).
My problem is that a top level build + build install generates several static and dynamic libs as well as binaries. So far so good. The problem is that 'make install' will indiscriminately copy over every single one of those libs/bins. (This takes a while)
I'd like it to only copy over libs/bins that have changed - potentially by comparing the md5sum of the target and source files.
How can i hook this up in my configure.ac/Makefile.am?
The actual program to copy the files is install (usually /usr/bin/install); this is defined in the INSTALL Make-variable.
Your install implementation might support the -C flag:
-C, --compare
compare each pair of source and destination files,
and in some cases, do not modify the destination at all
you might have to
So you could try to provide a script that does what you want (compare the source file with the destination file, and only copy if needed), by overriding this variable.
You could also just injec tthe -C flag, to see if it gives you any speedup (I tend to agree with ldav1s' comment that it might not):
make install INSTALL="/usr/bin/install -C"
note, that install accepts quite a number of arguments, and if you are going to re-implement a compatible script, you might have to implement some sub-set thereof.

Why do which and Sys.which return different paths?

I tried to run a Python script from R with:
system('python script.py arg1 arg2')
And got an error:
ImportError: No module named pandas
This was a bit of a surprise since the script was working from the terminal as expected. Having encountered this type of issue before (with knitr, whence the engine.path chunk option), I know to check:
Sys.which('python')
# python
# "/usr/bin/python"
And compare it to the command line:
$ which python
# /Users/michael.chirico/anaconda2/bin/python
(i.e., the error arises because I have pandas installed for the anaconda distribution, though TBH I don't know why I have a different distribution)
Hence I can fix my issue by running:
system('/Users/michael.chirico/anaconda2/bin/python script.py arg1 arg2')
My question is two-fold:
How does R's system/Sys.which find a different python than my terminal?
How can I fix this besides writing out the full binary path each time?
I read ?Sys.which for some hints, but to no avail. In particular, ?Sys.which suggests Sys.which is using which:
This is an interface to the system command which
This is clearly (?) untrue; to be sure, I checked Sys.which('which') and which which to confirm both are pointing to /usr/bin/which (goaded on by this tidbit):
On a Unix-alike the full path to which (usually /usr/bin/which) is found when R is installed.
To the latter, on a whim I tried Sys.setenv(python = '/Users/michael.chirico/anaconda2/bin/python') to no avail.
As some of the comments hint, this is a problem that arises because the PATH environment variable is different for programs launched by Finder (or the Dock) than it is in the Terminal. There are ways to set the PATH for Dock-launched applications, but they aren't pretty. Here's a place to start looking if you want to go that route:
https://apple.stackexchange.com/questions/51677/how-to-set-path-for-finder-launched-applications
The other thing you can do, which is probably more straightforward, is tell R to set the PATH variable when it starts up, using Sys.setenv to add the path to your desired Python instance. You can do that for just one project, for your whole user account, or for the whole system, by placing the command in a .Rprofile file in the corresponding location. More information on how to do this here:
https://stat.ethz.ch/R-manual/R-devel/library/base/html/Startup.html

In GHC, is there a way I can check compilation without actually producing output?

Sometimes, I write code to a file solely for the purpose of checking whether it compiles -- with no interest in the generated binaries.
For example, if I am doing a learning exercise and want to produce some error or see if certain code compiles without error, I'd like to see the ordinary compile output printed to the terminal but without generating the *.hi or *.o files that occur by running ghc <myprogram>.hs.
I sometimes effectively do this using runhaskell, but that is not ideal -- it requires a main function, and actually runs the program whereas I am just looking for a compilation check.
Is there some way to suppress generation when running GHC, only displaying the ordinary compilation errors and warnings?
One of the answers to this question suggested the answer that I'm looking for: ghc option -fno-code.
I.e., compile but don't generate binaries with:
$ ghc -fno-code <myprogram>.hs
In the same spirit to the purpose of the question and in addition to the working answer by #mherzl, my answer below:
while true;do
inotifywait -e modify myprogram.hs
ghc -fno-code myprogram.hs
done
This only works on Linux systems having the inotifywait tool. It blocks an detects if the file is modified.

Compiling haskell module Network on win32/cygwin

I am trying to compile Network.HTTP (http://hackage.haskell.org/package/network) on win32/cygwin. However, it does fail with following message:
Setup.hs: Missing dependency on a foreign library:
* Missing (or bad) header file: HsNet.h
This problem can usually be solved by installing the system package that
provides this library (you may need the "-dev" version). If the library is
already installed but in a non-standard location then you can use the flags
--extra-include-dirs= and --extra-lib-dirs= to specify where it is.
If the header file does exist, it may contain errors that are caught by the C
compiler at the preprocessing stage. In this case you can re-run configure
with the verbosity flag -v3 to see the error messages.
Unfortuntely it does not give more clues. The HsNet.h includes sys/uio.h which, actually should not be included, and should be configurered correctly.
Don't use cygwin, instead follow Johan Tibells way
Installing MSYS
Install the latest Haskell Platform. Use the default settings.
Download version 1.0.11 of MSYS. You'll need the following files:
MSYS-1.0.11.exe
msysDTK-1.0.1.exe
msysCORE-1.0.11-bin.tar.gz
The files are all hosted on haskell.org as they're quite hard to find in the official MinGW/MSYS repo.
Run MSYS-1.0.11.exe followed by msysDTK-1.0.1.exe. The former asks you if you want to run a normalization step. You can skip that.
Unpack msysCORE-1.0.11-bin.tar.gz into C:\msys\1.0. Note that you can't do that using an MSYS shell, because you can't overwrite the files in use, so make a copy of C:\msys\1.0, unpack it there, and then rename the copy back to C:\msys\1.0.
Add C:\Program Files\Haskell Platform\VERSION\mingw\bin to your PATH. This is neccesary if you ever want to build packages that use a configure script, like network, as configure scripts need access to a C compiler.
These steps are what Tibell uses to compile the Network package for win and I have used this myself successfully several times on most of the haskell platform releases.
It is possible to build network on win32/cygwin. And the above steps, though useful (by Jonke) may not be necessary.
While doing the configuration step, specify
runghc Setup.hs configure --configure-option="--build=mingw32"
So that the library is configured for mingw32, else you will get link or "undefined references" if you try to link or use network library.
This combined with #Yogesh Sajanikar's answer made it work for me (on win64/cygwin):
Make sure the gcc on your path is NOT the Mingw/Cygwin one, but the
C:\ghc\ghc-6.12.1\mingw\bin\gcc.exe
(Run
export PATH="/cygdrive/.../ghc-7.8.2/mingw/bin:$PATH"
before running cabal install network in the Cygwin shell)

Mixing Qt and boost causes compilation error with "check" keyword

I am using Qt in a project and am now trying to include another project that uses boost.
I have added no_keywords to my config in the qt project file to avoid collision between the signal and slots functionality that is present in boost and Qt. But now I get a compilation error which seems to stem from double definition of a function called "check". Is there some way to avoid this?
An example is has_postfix_operator.hpp (line 141):
static ::boost::type_traits::yes_type check(has_operator); // this version is preferred when operator exists
Apparently there is a "check" defined in Qt.
I'm using Qt4.7 and boost 1.48. Running MacOSX 10.6.8
You should also look at /usr/include/AssertMacros.h, which defines a macro named "check" - that could be the cause of your problem.
To check this, add -d __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES=0 to your compiler flags.
If that works, that was your problem.
Here's a comment from that file:
Prior to Mac OS X 10.6 the macro names used in this file conflicted
with some user code, including libraries in boost and the proposed C++
standards efforts, and there was no way for a client of this header to
resolve this conflict. Because of this, most of the macros have been
changed so that they are prefixed with
__ and contain at least one capital letter, which should alleviate the current and future conflicts. However, to allow current sources to
continue to compile, compatibility macros are defined at the end with
the old names. A tops script at the end of this file will convert
all of the old macro names used in a directory to the new names.
Clients are recommended to migrate over to these new macros as they
update their sources because a future release of Mac OS X will remove
the old macro definitions ( without the double-underscore prefix ).
Clients who want to compile without the old macro definitions can
define the macro
__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES to 0 before this file is included.

Resources