I also added a missing const to a BugReporter API.
There are some TODOs for potential future updates if we want richer notes during reporting.
Differential D70725
[analyzer] Add path notes to FuchsiaHandleCheck xazax.hun on Nov 26 2019, 9:22 AM. Authored by
Details I also added a missing const to a BugReporter API. There are some TODOs for potential future updates if we want richer notes during reporting.
Diff Detail
Event TimelineComment Actions Sooooo... note tags?
Comment Actions I was thinking about note tags, but since we iterate on the argument/parameter pairs and might change the state in each iteration we would need to add a new transition after each change. I was wondering if using note tags would worth the cost (both in performance due to the additional number of nodes and in code complexity due to making transitions more often). Comment Actions Sorry, my previous comment might not be clear. The point is, the same call might both acquire and release handles (there are such calls in Fuchsia), so we might end up adding more than one note for a call for which we would need to add more than one transitions. If you think it is still cleaner that way, I could do that as well :)
Comment Actions Hmm, would this be too functional?: std::vector<std::function> notes; for (arg : args) { if (isAcquired(param)) { State = State->set(arg, Acquired); notes.push_back([](Report) { if (Report.isInteresting(arg)) return "Handle acquired here"; }); } if (isReleased(param)) { State = State->set(arg, Released); notes.push_back([](Report) { if (Report.isInteresting(arg)) return "Handle released here"; }); } } C.addTransition(State, C.getNoteTag( // We might as well add a C.getNoteTag() overload // to do this automatically. [std::move(notes)](Report) { for (note : notes) note(); })); Or, well, yeah, chain the nodes together; you anyway have to do this occasionally due to clumsiness of the rest of the API. Comment Actions
Of course i mean something like this: std::string text = note(); if (!text.empty()) return text; (and return something like "" on the other return path in the inner lambdas). Comment Actions Just a small side note. If the state was same as the previous we do not end up creating a new ExplodedNode right? Is this also the case when we add a NoteTag?
Comment Actions It only happens for evaluation when you cannot evaluate something. Other than that Pre/PostCall working fine to add a node with the NoteTag. Comment Actions Yay, it actually works! I only have minor comments and ignorable hand-waving now. Tag pointers are part of the ProgramPoint's identity, which in turn are part of the ExplodedNode's identity. If you make a new note tag and transition into it for the first time, the new node is guaranteed to be fresh.
Comment Actions
Comment Actions This is what I suspected. I wonder if all the checks end up using NoteTags will the increased number of nodes ever be a concern? Maybe if the state is the same as the previous we should just not add the note tag? For example, my checker before the note tag would only generate new nodes if there was an actual change to the state. After this change it probably ends up adding new nodes with empty note tags all the time. This could be bad both for performance and debugging. What do you think? Comment Actions Mmm, right, i guess you should also skip adding the tag if the notes array is empty. There might be more complicated use-cases (especially in ExprEngine itself) where you may end up adding a tag even if the state doesn't change. For instance, when changing an Environment value from absent to UnknownVal, the state doesn't get actually updated. Or making range assumptions over UnknownVal. But i'd argue that we do indeed want the note tag in such cases because it is still worth annotating the ExplodedGraph with an explanation of what's happening. Eg., a note "Assuming a condition is false" makes sense even if the condition is an UnknownVal and no actual constraints are added. Another example: in a recent StreamChecker review we've been talking about a peculiar stream function that by design closes a file descriptor if it's open but does nothing if the descriptor is already closed. I believe this event deserves a note "The descriptor remains closed" (possibly prunable) even though there is no change in the state. This is something we couldn't do with our usual visitor-based approach which involves observing changes in the state (we technically could, via pattern-matching over the program point, but that'd directly duplicate a lot more of checker logic than usual). Comment Actions I see, that makes sense. I updated the code. I was hoping for a low hanging fruit to make this more user friendly :)
|
N = N->getFirstPred().