I am writing a reference-counted linked list of characters data structure in C for practice. I want to try using Sal in it to annotate function parameters for this practice.
I have an input paremeter(named This), which I want to annotate to make it clear that the specified parameter's members must be mutable in order for the function to behave as expected.
The situation is analogous to the code below.
#include <Windows.h>
typedef struct Box {
ULONG val;
} Box;
ULONG Box_decrement(_In_ Box *This) {
return InterlockedDecrement(&(This->val));
}
int main(int argc, char **argv) {
Box b = {2};
Box_decrement(&b);
return (BYTE)b.val;
};
Is there an existing Sal annotation that can be used to annotate the This parameter of the Box_increment function to make it clear from the function signature that the function modifies one or more members of the Box that has been passed to it?
Something like _InternallyMutable_(but exist):
#include <Windows.h>
typedef struct Box {
ULONG val;
} Box;
ULONG Box_decrement(_InternallyMutable_ _In_ Box *This) {
return InterlockedDecrement(&(This->val));
}
int main(int argc, char **argv) {
Box b = {2};
Box_decrement(&b);
return (BYTE)b.val;
};
Best solution so far(unfortunately, there does not seem to be any equivelent in SAL to denote Internally_mutable, there is Unchanged which is the opposite):
#include <Windows.h>
#define _Internally_mutable_(expr) _At_(expr, _Out_range_(!=, _Old_(expr)))
typedef struct Box {
ULONG val;
} Box;
ULONG Box_decrement(_In_ _InternallyMutable_(This) Box *This) {
return InterlockedDecrement(&(This->val));
}
int main(int argc, char **argv) {
Box b = {2};
Box_decrement(&b);
return (BYTE)b.val;
};
Yes! You can. SAL is a wonderful DSL that lets you do basically anything you want if you're psychic enough to infer it from the little bits in the Windows SDK. I've even in the past been able to write super simple custom annotations to detect invalid
HANDLEusage with_Post_satisfies_and friends.This code seems to work:
...Running with all native rules in code analysis, I get a warning like this:
(there, substitute
valuewith your variable) For_Internally_mutable_, I can do it in the "above the function" style of SAL:...but not inline WITHOUT being repetitive, as you wanted. Not sure why right now -
_Curr_doesn't seem to be working? - I may need another layer of indirection or something. Here's what it looks like:How I figured this out:
sal.hdefines an_Unchanged_annotation (despite doing web dev for several years now and little C++, I remembered this when I saw your question in a google alert for SAL!):...if you look at this macro closely, you'll see that it just substitutes as:
...and further unrolling it, you'll see
_Post_equal_to_is:Do you see it? All it's doing is saying the
_Out_range_is equal to the expression you specify._Out_range_(and all the otherrangeSAL macros) appear to accept all of the standard C operators. That behavior is not documented, but years of reading through the Windows SDK headers shows me it's intentional! Here, all we need to do is use the not equals operator with the_Old_intrinsic, and the analyzer's solver should be able to figure it out!_Unchanged_itself is broken?To my great confusion,
_Unchanged_itself seems broken:...that produces NO warning. Without the
_Inout_, code analysis is convinced thatvalueis uninitialized on function entry. This makes no sense of course, and I'm calling this directly frommainin the same file. Twiddling with inlining or link time code generation doesn't seem to helpI've played a lot with it, and various combinations of
_Inout_, even_Post_satisfies_. I should file a bug, but I'm already distracted here, I'm supposed to be doing something else right now :)Link back here if anybody does file a bug. I don't even know what the MSVC/Compiler teams use for bug reporting these days.
Fun facts
5-6 years ago I tried to convince Microsoft to open source the SAL patents! It would have been great, I would have implemented them in Clang, so we'd all be able to use it across platforms! I might have even kicked off a career in static-analysis with it. But alas, they didn't want to do it in the end. Open sourcing them would have meant they might have to support it and/or any extensions the community might have introduced, and I kinda understand why they didn't want that. It's a shame, I love SAL, and so do many others!