Using splint for static code analysis on windowms with MPLAB how to avoid system file parse errors - mplab

I'm using MPLAB X (3.26) with a PIC32 on windows (XC32 v1.40 compiler). I'm trying to use splint to do static code analysis on someones code as part of a review. I've got most of the compiler defines and search paths sorted, but are a bit stumped when it comes to avoiding the parse errors in the PIC32 std include files.
The command I am using to run splint is
splint ^
-D"__32MX370F512L__" ^
-D"__PIC32_FEATURE_SET__"=370 ^
-D"__LANGUAGE_C__" ^
+I"C:/Program Files (x86)/Microchip/xc32/v1.40/pic32mx/include/" ^
main.c
The output then gives
< Location unknown >: Field name reused:
Code cannot be parsed. For help on parse errors, see splint -help
parseerrors. (Use -syntax to inhibit warning)
< Location unknown >: Previous use of
< Location unknown >: Previous use of
.... approx 100 times then...
C:\Program Files (x86)\Microchip\xc32\v1.40\pic32mx\include\\stddef.h(4,18):
Datatype ptrdiff_t declared with inconsistent type: long int
A function, variable or constant is redefined with a different type. (Use
-incondefs to inhibit warning)
load file standard.lcd: Specification of ptrdiff_t: arbitrary integral type
C:\Program Files (x86)\Microchip\xc32\v1.40\pic32mx\include\\stddef.h(5,27):
Datatype size_t declared with inconsistent type: unsigned long int
load file standard.lcd: Specification of size_t:
arbitrary unsigned integral type
C:\Program Files (x86)\Microchip\xc32\v1.40\pic32mx\include\\stddef.h(6,13):
Datatype wchar_t declared with inconsistent type: int
load file standard.lcd: Specification of wchar_t: arbitrary integral type
C:\Program Files (x86)\Microchip\xc32\v1.40\pic32mx\include\\stdarg.h(75,36):
No type before declaration name (implicit int type): __builtin_va_list :
int
A variable declaration has no explicit type. The type is implicitly int.
(Use -imptype to inhibit warning)
C:\Program Files (x86)\Microchip\xc32\v1.40\pic32mx\include\\stdarg.h(75,36):
Parse Error: Suspect missing struct or union keyword: __builtin_va_list :
int. (For help on parse errors, see splint -help parseerrors.)
*** Cannot continue.
The last one causes things to stop. I've tried things like -skip-iso-headers with no luck. It seems it is seeing issues with its standard.lcd file and the xc32 std files
Can anyone tell me
What the < Location unknown >: Field name reused: means or possibly is referring to?
A way to resolve the parse error due to the std header files?
So far only way to solve the header file issue is to define the types, e.g.
-D"__builtin_va_list"=int ^

I think your code (or some code that you #include) is using anonymous bitfields or/and structs. Anonymous structs and anonymous unions are provided by a GNU extension for versions of C earlier than C11. Since Splint doesn't know about C11 (I only found mentions of C99 in the manual, and google agrees) and only partial support for the GNU extensions (search for gnu-extensions), it has a hard time parsing them.
I had a similar problem with some code written for a PIC18f46k22, though I was using sdcc instead of XC8.
The issue was with pic18f46k22.h, which had anonymous structs (bitfields, specifically) inside a typedef union.
This code...
typedef union
{
struct
{
unsigned name0 : 1;
unsigned name1 : 1;
unsigned name2 : 1;
unsigned name3 : 1;
unsigned name4 : 1;
unsigned : 1;
unsigned : 1;
unsigned : 1;
};
struct
{
unsigned name : 6;
unsigned : 2;
};
} __NAMEbits_t;
...would produce these errors...
< Location unknown >: Field name reused:
Code cannot be parsed. For help on parse errors, see splint -help
parseerrors. (Use -syntax to inhibit warning)
< Location unknown >: Previous use of
...but this code wouldn't.
struct indv
{
unsigned name0 : 1;
unsigned name1 : 1;
unsigned name2 : 1;
unsigned name3 : 1;
unsigned name4 : 1;
unsigned : 1;
unsigned : 1;
unsigned : 1;
};
struct all
{
unsigned name : 6;
unsigned : 2;
};
typedef union
{
struct indv individualbits;
struct all allbits;
} __NAMEbits_t;

I am working with a different processor, compiler, and static analysis tool (PRQA / Helix QAC), but I think we are facing the same problem regarding the parse issue of the standard header files. It took me some time to figure out what is going on.
For one thing, I can say that your workaround is good enough and apparently you should not worry about it too much. I used a slightly different workaround described here:
Pycparser not working on preprocessed code
-D __builtin_va_list = struct __builtin_va_list {}
I guess another way would be to use stub standard headers instead of the real ones. My tool manual claims, for example, that there should be such header files supplied with the tool, although I haven't found/obtained them yet.

Related

error: storage class may not be specified here when using __align() in MDK ARM uVision v5 ARM Compiler 5

I am migrating a project from CubeIDE (GCC) to the most comprehensive software development solution for ArmĀ®-based microcontrollers uVision (ARM Compiler 5) and have a difficulty using __align keyword.
CubeIDE code which compiles fine in CubeIDE:
#include <stdalign.h>
typedef struct {
volatile alignas(uint32_t) uint16_t imageDark[320];
} test_results;
First issue is that uVision cannot locate <stdalign.h> which is part of standard library of the C programming language:
..\Src\device_tests.c(3): error: #5: cannot open source input file "stdalign.h": No such file or directory
So I removed <stdalign.h> and based on these KEIL documentation rewrote my code to
typedef struct {
volatile __align(__ALIGNOF__(uint32_t)) uint16_t imageDark[320];
} test_results;
Now I am receiving the following error:
..\Src\device_tests.c(46): error: #80: a storage class may not be specified here
volatile __align(__ALIGNOF__(uint32_t)) uint16_t imageDark[320];
..\Src\device_tests.c(46): error: #328: invalid storage class for a class member
volatile __align(__ALIGNOF__(uint32_t)) uint16_t imageDark[320];
Any help on how to make alignment work in uVision would be greatly appreciated.
I found out that the problem was that I was trying to align inside a struct. The above-mentioned syntax works for variables outside a struct. However to make it work inside struct I used the following syntax:
typedef struct {
volatile uint16_t imageDark[320] __attribute__((aligned (4)));
} test_results;

Clang Assertion failed: Ran out of source locations

I have a utility that uses Clang's LibTooling framework to parse the AST and perform static code analysis. I am using LLVM and Clang v10.0.
Recently I observed that the utility never finishes parsing the AST of a particular file. On debugging, I observed that the SourceManager.cpp calls an abort due to failed assertion. The exact place is here:
FileID SourceManager::createFileID(const ContentCache *File,
SourceLocation IncludePos,
SrcMgr::CharacteristicKind FileCharacter,
int LoadedID, unsigned LoadedOffset) {
...
...
assert(NextLocalOffset + FileSize + 1 > NextLocalOffset &&
NextLocalOffset + FileSize + 1 <= CurrentLoadedOffset &&
"Ran out of source locations!");
...
...
...
}
The values of the variables when the assertion fails are: NextLocalOffset=2147335549, FileSize=303516, CurrentLoadedOffset=2147483648 and (NextLocalOffset + FileSize)=2147639065.
The source file is automatically generated and is around 28,268,746 bytes (~27MB) and contains several include directives (~7000) for memory mapping different code blocks.
Is there a limit to the source files size Clang can process?

puts(NULL) - why doesn't WP+RTE complain?

Consider this small C file:
#include <stdio.h>
void f(void) {
puts(NULL);
}
I'm running the WP and RTE plugins of Frama-C like this:
frama-c-gui puts.c -wp -rte -wp-rte
I would expect this code to generate a proof obligation of valid_read_string(NULL); or similar, which would be obviously unprovable. However, to my surprise, no such thing happens. Is this a deficiency in the ACSL specification of the standard library?
Basically yes. You can see in the version of stdio.h that is bundled with Frama-C that the specification for puts is
/*# assigns *stream \from s[..]; */
extern int fputs(const char * restrict s,
FILE * restrict stream);
i.e. the bare minimum, an assigns clause (plus a from clause for Eva). Preconditions on s and stream. Adding a precondition on s would be easy; things are more complex for stream since you need a model for the various objects of type FILE.

What is the use of # symbol in c language

The symbol # was seen in one the program ,But i could not find why it is used .
The syntax is
const unsigned char Array_name[] #(INFO_Array+1) = {................};
The meaning of # operator can be different for the particular compiler in which the code is compiled.
For example, in IAR Embedded Workbench's C/C++ compiler the # operator can be used for placing global and static variables at absolute addresses.
If you are using IAR C/C++ compiler, the compiler will place Array_name in the address (INFO_Array+1).
# operator can also be used to place a variable or object in a particular section of the object file:
uint32_t CTRL_OFFSET_x86 # "MY_RAM_SECTION";
The above line will place CTRL_OFFSET_x86 in the object file section MY_RAM_SECTION.
#pragma location can also be used for this purpose.
To me, it looks like a compiler flag to disable interpreting the string "INFO_Array+1" as an expression. In C# for example, you can use the #-Operator to tell the compiler to use the following expression as String without trying to evaluate it.
A quick googling showed:
For example, this line will fail to compile:
int new = 1776; // 'new' is a keyword
However, this line compiles without error:
int #new = 1776;

How does CLR match the exported names during P/Invoke?

I work on a project that requires .Net interoperability with unmanaged code. I started to work with .Net a couple of weeks ago, though I have a lot of experience with C/C++, and I am surprised how CLR deals with P/Invoke. Here are the details. My colleague wrote this function
__declspec(dllexport) int __stdcall ReadIPWSensor(unsigned int deviceClassId, void *buffer) {...}
and I had to call it from C# module. I imported the function as
[DllImport("ipw", CallingConvention = CallingConvention.StdCall)]
extern static int ReadIPWSensor(uint deviceClassId, IntPtr buffer);
just to find out an exception (System.EntryPointNotFoundException, Unable to find an entry point named 'ReadIPWSensor' in DLL 'ipw'). I used DependencyWalker tool and found that the function was exported as ?ReadIPWSensor##YGHIPAX#Z (my colleague forgot to export it in the DEF file). Just for the quick test (the unmanaged DLL compiles very slowly) I changed my import definition to:
[DllImport("ipw", EntryPoint = "#22", CallingConvention = CallingConvention.StdCall)]
extern static int ReadIPWSensor(uint deviceClassId, IntPtr buffer);
as the ordinal was 22. The test passed successfully with the new import definition.
My first question is: What are the good practices when dealing the mangled function exports? Is it a good practice to use the export ordinals?
In my case I had access to the C++ source code and the DEF file so I added the export and changed back the import definition to
[DllImport("ipw", CallingConvention = CallingConvention.StdCall)]
extern static int ReadIPWSensor(uint deviceClassId, IntPtr buffer);
I knew there is another function we already use in our project and wanted to compare my code with the existing one. The function is defined as
extern "C" __declspec(dllexport) int __stdcall LoadIPWData(void
*buffer)
and is imported as
[DllImport("ipw", CallingConvention = CallingConvention.StdCall)]
extern static int LoadIPWData(IntPtr buffer);
To my surprise DependencyWalker tool shows that the function is exported as _LoadIPWData#4 (my coworker forgot to export it in the DEF file again). However with this function there is no System.EntryPointNotFoundException error. Obviously, the CLR somehow managed to resolve the right name. It seems there is some sort of fallback mechanism that allows CLR to find the right function. I can easily imagine the it sums the sizes of the parameters and is looking for "function_name#the_sum_of_all_parameter_sizes" though it seems quite simplistic.
My second question is: How does CLR match the exported function names during P/Invoke?
In this scenario I think CLR is so clever that it actually hides a bug - LoadIPWData function should be accessible by its name from other unmanaged modules. Maybe I am a bit of paranoid but I prefer to know how actually CLR works. Unfortunately all my google searches on that topic were fruitless.
The pinvoke marshaller has built-in knowledge of a few common DLL export naming schemes. It knows that __cdecl functions often have a leading underscore and that __stdcall in 32-bit mode is commonly decorated with a leading underscore and a trailing #x where x is the size in bytes of the arguments passed on the stack. It also knows that winapi functions are exported with a trailing extra A or W, a naming scheme to distinguish functions that accept strings and for which there's both an ansi and a Unicode version. The corresponding [DllImport] property is CharSet. It just tries them all until it finds a match.
It doesn't know anything about C++ compiler name decoration rules (aka mangling) so that's why you have to use extern "C" to suppress that by hand.

Resources