SymbolRef and SVal confusion

hey

I am having a bit of a hard time understanding the connection between SVals and SymbolRefs, could someone enlighten me? As I understand it, SVals are transient, and SymbolRefs are not, which makes them handy for tracking state. However, some SVals don’t have SymbolRefs. What is the recommended way of identifying an SVal with no SymbolRef at a later stage in a checker execution? All the examples I have looked at just bail when there is no SymbolRef.

I find that the following code has a SymbolRef for the SVal in the branch condition:

int main(int argc, char *argv)
{
UILabel *l = [[UILabel alloc] init];

BOOL available = [l respondsToSelector:@selector(adjustsLetterSpacingToFitWidth)];
if (available)
l.adjustsLetterSpacingToFitWidth = YES;

[l release];

return 0;
}

But the following code does not:

int main(int argc, char *argv)
{
UILabel *l = [[UILabel alloc] init];

BOOL available = [l respondsToSelector:@selector(adjustsLetterSpacingToFitWidth)];
BOOL unavailable = !available;

if (available)
l.adjustsLetterSpacingToFitWidth = YES;

[l release];

return 0;
}

Any condition that is a binary or unary operator seems to have an SVal with no SymbolRef. I would love to know why.

thanks.

Hi Richard,

SVals are value objects. They should just be viewed as a union of different abstract values that an expression can evaluate to. They are “nameless” values. SVals can wrap SymbolRefs, but they also can wrap other values such as constants, addresses of goto labels, etc. When the analyzer evaluates an expression, it computes an SVal. Another way to look at SVals is that they “box” more interesting values that have different meanings.

SymbolRefs are “named” symbolic values. They represent the name of a value along a path. For example, in your code snippet ‘argc’ has an initial value that has a symbol. Along a path the analyzer can reason about properties of that value, e.g., constraints such as the value of argc being greater than 0, etc. Constraints cannot be associated with SVals, as they are value types that are just used to box more persistent named values like symbols.

If an SVal has no SymbolRef, it means one of two things:

(1) The value isn’t symbolic. There are many cases where this can be. Roughly SVals are divided into locations and non-locations, with those breaking up further into other sets of values:

namespace nonloc {

enum Kind { ConcreteIntKind, SymbolValKind,
LocAsIntegerKind, CompoundValKind, LazyCompoundValKind };

and

namespace loc {

enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind };

This is from SVals.h.

If a value isn’t symbolic, usually that means there is no symbolic information to track. For example, if the value was an integer, such as 42, it would be a ConcreteInt, and the checker doesn’t usually need to track any state with the number 42. That’s why the checkers bail out early.

(2) The other reason an SVal has no Symbol, but it really should be a symbolic value, is when the analyzer cannot reason about something (yet). An example is floating point numbers. In such cases, the SVal will evaluate to UnknownVal. This represents a case that is outside the realm of the analyzer’s reasoning capabilities.

Now to your question about binary and unary operators. It is possible that the analyzer is constant folding the operations when the symbolic value is known to be constrained. In such cases, the analyzer may eagerly “concretize” a symbolic value and split the path. For example, suppose we have:

BOOL b = x > 10;

In this case, ‘b’ will not be symbolic value. What happens when the analyzer evaluates ‘x > 10’ is that it eagerly asserts both (a) x > 10 and (b) x <= 10 and splits the path with either (a) being true or (b) being true. Along those two paths, the value of ‘b’ will either be 1 or 0 respectively. If you do a dump of the SVal (using the .dump() method) you will likely see the value 1 or 0 get printed out. This value isn’t symbolic, it is concrete.

I hope this helps clear things up a bit. If it is still unclear, please do not hesitate to ask for more clarification.

Cheers,
Ted

Hello Ted,

This is a great explanation!

Could you put it somewhere in clang/docs/analyzer?

Dmitri

This is partially described in “Representing Values” section of http://clang-analyzer.llvm.org/checker_dev_manual.html

We could extend it with the missing info (looks like UnknownVal is missing).

Anna.

Thank you Ted, this was very helpful. You are right about the SVal folding, they are already concrete values in the example I sent.

ta//

The check you probably want is evalAssume. As you’ve seen, evalBranchCondition checks when there’s a branch in the control flow graph, but not when the analyzer decides to split states.

However, you have to be careful with evalAssume: the SVal being assumed can affect the condition on your symbol even if it doesn’t directly wrap that symbol:

BOOL a = …;
BOOL b = …;
if (a == b) { … }

So you’ll probably end up having to ask the constraint checker if anything changed with regards to your symbols. You could make this cheaper by iterating over the symbols in the SVal first and seeing if they match your set of unresolved calls to -respondsToSelector: and friends.

Jordan

Hey Jordan

I am currently using a combination of both. First I check for an availability checking call in checkBranchCondition, if it is already a concrete int then the global state is set. If it is not, then the Symbol (or Memregion in the case of a FunctionDecl) is set in the state, which is later checked in evalAssume when the assumption has been made.

This works well, except for FunctionDecls. I am currently having a problem with state not being set when returning from evalAssume. I have looked through the code, and the problem seems to be the assumeAux function in SimpleConstraintManager. When the Cond is a MemoryRegionKind with no SubRegion, the switch falls through to the GotoLabelKind, which will always return NULL for false assumptions. If that is the case, then when doing something like this, the false case is never tested, as the branch condition is always true:

if (UIAccessibilityIsGuidedAccessEnabled != NULL) {
doIOS6Stuff();
} else {

// this will not trigger a warning
doIOS6Stuff();

}

Also, this has the knock on effect of not setting any state for the true assumption when not already a concrete int, because of the following code in the ConstraintManager:

ProgramStateRef StFalse = assume(State, Cond, false);
// StFalse will always be NULL here for FunctionDecl Conds
if (!StFalse) {
// We are careful to return the original state, /not/ StTrue,
// because we want to avoid having callers generate a new node
// in the ExplodedGraph.
return ProgramStatePair(State, (ProgramStateRef)NULL);
}

So when the function has not already been folded, no global state can be set, eg:

if (UIAccessibilityIsGuidedAccessEnabled) {

// this will erroneously trigger a warning as no global state was set

doIOS6Stuff();
}

Could you advise as to the best solution to this problem?

thanks,
richard

I was worried you were going to ask about this. :slight_smile:

The problem is that functions are represented by FunctionTextRegions. As you noticed, our design is that only SymbolicRegions can represent NULL—all other regions are known to have an address. However, this is not true for weak symbols (functions or otherwise). In order to get this right, we probably need to enhance the analyzer to treat weak extern symbols like references, and then automatically dereference them upon use.

It would be nice to have AST support here. After all, CodeGen is doing the same thing. I’m not sure if that’s feasible / generally useful, though.

Another possibility would be to have SValBuilder::getFunctionPointer and StoreManager::getLValueVar automatically bind a symbolic value rather than a regular value if the Decl being referenced is weak. In order to do this properly for functions, though, we might need a new symbol kind, since we want to maintain the reference to the FunctionDecl. We’d also want to make sure the same symbol is used every time, since the presence of a weak-linked symbol shouldn’t change during a program. You could probably do this by passing no context information when conjuring the symbol, but then using the Decl as the symbol tag…

Anyway, we haven’t designed this yet. If you’re willing to work on it, that would be great. My thought is that you should get the -respondsToSelector: case working first, then come back and deal with this (hopefully submitting a patch as well).

Jordan

I don’t think the “references” analogy is quite right. Functions are already modeled in the AST using function pointers, and they are dereferenced during a function call. We could possibly model weak-linked functions using SymbolicRegions, that are then later constrained to alias a specific FunctionTextRegion. Aliasing is something we need to handle better anyway, and I think this would nicely fit into that model.

I had a quick attempt at this, by creating a SymbolExtent of a weak function decl code region and creating a SymbolicRegion with that. This actually fixes the checker I was writing, which is nice. I am not sure if I understand fully the implications of doing this however. Where does the SymbolicRegion need to be constrained back to a FunctionTextRegion?

Index: Core/SValBuilder.cpp

SymbolExtent isn’t really meant for this; it’s supposed to represent the metadata of how large an allocation is in memory. Doing this is basically like changing “return func” to “return sizeof(*func)”, except that functions don’t really have valid sizes anyway. You really can’t put an extent symbol (type size_t) into a loc::MemRegionVal (some kind of pointer-ish thing).

In practice, this lets you do the null test, but won’t actually let the analyzer call the function, which is no good.

I don’t have any other immediate insights to offer. We just don’t have values that can represent either null or a specific function at this time. You might be able to fake it for now by adding a pre-visit check for CastExprs of type CK_FunctionToPointerDecay, and eagerly splitting the path whenever someone references a weak function.

Jordan

Hey Jordan,

I realise SymbolExtent is the wrong symbol class to use, it was just a quick hack to see how much more work was involved in getting the analyser to assume false on function decls. Not very much it turned out. I guess a new SymExpr subclass is needed.

The bit I am not clear on is where the analyser calls a function, where I would need to add code to handle this new symbol type. Apologies if this is a stupid question, I had a dig through ExprEngine, but did not find what I was looking for. Is it VisitCast?

Ta.

VisitCast handles the “decay” in the AST from a raw function name to a function pointer; all C function calls are actually calls to function pointers according to the standard. But the actual code that figures out the function to call is in CallEventManager::getSimpleCall, which…huh, doesn’t actually look at the callee’s SVal if it’s known at compile time. Which means only calls through weak function pointers would lose out. I would actually be okay with this since these are (a) rare, and (b) probably not calls we do much special processing for anyway.

If you want to try hacking this in, I’d suggest using a conjured symbol with no Expr and no block count (so it’s the same all across the program) and the appropriate pointer-to-function type:

QualType Ty = Ctx.getPointerType(FD->getType());
SVB.conjureSymbol(/Stmt=/0, /LCtx=/0, Ty, /VisitCount=/0, /Tag=/FD);

And then come up with a bunch of test cases and make sure that if you, say, define “malloc” as weak that we still treat it like “malloc”. If everything works, send it back and I’ll commit it to SVN.

Thanks for working on this!
Jordan

Hey Jordan,

How about something like the attached diff? I have included a test case that just stole some of the other tests on C functions and redeclares them as weak and runs the tests again. I did also try making all function pointers weak and running the test cases, which also passes. A couple of test cases needed modifying to return the underlying FunctionTextRegion instead of the SymbolicRegion for weak function pointers, which seems a bit messy, don’t know if you have any ideas about a nicer solution to this. Maybe getAsRegion() should always return the FunctionTextRegion if it is wrapping a SymbolWeakFunction?

Richard.

WeakFuncs.diff (9.95 KB)

weak-functions.c (5.99 KB)

Hi, Richard. Sorry for the delay in responding.

Hm. I’m not sure why we need a new symbol type specifically for functions, but I could understand the use for generic weak-linked symbols (unfortunate overloading there). After all, in this case “&foo” may be null:

extern int foo attribute((availability(macosx, 10.4)));

I’m not sure how we want to represent this in the analyzer, though. We wouldn’t want all MemRegions to have associated symbols.

…actually, I can think of reasons why we would, at least for all top-level MemRegions. But that’s quite a redesign; it’s probably not something we’re going to do right now.

In any case, this seems oddly intrusive, with far more places needing to know about SymbolWeakFunction than seems strictly necessary. Having to choose one of two regions available in a single SVal seems very strange, and I’m worried that we won’t really be getting this right all the time.

I’m sorry I’m not able to think through a solid design with you right now; I’ve got a number of other projects going on. I haven’t thought through the ramifications of this yet, but what if you inverted this design and instead gave weak FunctionTextRegions associated metadata symbols with function pointer type? That way it’d be much easier to figure out where FunctionTextRegions need to opt-in to SymbolicRegion-like behavior, and at worst we’d handle these functions the same way we did before. …Again, I haven’t really thought it all the way through, but what do you think?)

By the way, please make sure your code conforms to the LLVM coding conventions. In particular, we capitalize local variable names, indent with two spaces, attach & and * to the variable name rather than the type name, and keep all lines within 80 columns.

As for your test cases, I’d personally suggest not using clang_analyzer_eval as a weak function—its only purpose is to be interpreted by the analyzer. malloc() tests checkers evaluating calls. Two other things that might be worth borrowing are dispatch_once, which is implemented with a synthesized body, and some made up CoreFoundation function like CFCopyFoo, which the analyzer handles with a post-call callback to produce a leak warning.

Jordan

Hey Jordan,

I agree the solution was a bit messy, it seemed like there were too many places that had to know about testing what kind of SymbolicRegion they had. I prefer your idea of attaching a metadata symbol to the FunctionTextRegion for weak functions, this seems a lot cleaner to me. How about the attached diff? I also added some tests for dispatch_once and CFCopy… method.

Thoughts?

weak-function-symbols.diff (13.9 KB)

That’s not quite going to work – what if I explicitly spell out my comparison?

if (MyWeakFunction == NULL) {
}

In this case, SimpleConstraintManager won’t go through your new assumeLocSymbol.

…although actually, it won’t make it there at all, because SimpleSValBuilder::evalBinOpLL folds null comparisons against non-symbolic regions. That’s actually easy enough to fix, though, and if you do that this might actually work.

Oh, and metadata symbols also die unless some checker specifically requests to keep them alive. I’m wondering now if the current behavior of SymbolExtent (immutable, lasts as long as the base region, only as path-specific as their region) is, in fact, closer to the desired behavior here than metadata symbols (invalidatable, path-sensitive, only lasts as long as someone is interested). If this is the case, maybe SymbolExtent should be made more generic.

(Sorry for giving you a runaround here. I’m not sure what the right thing to do is…I just want to avoid “new symbols” being the solution to every problem, and at the same time make sure that the existing symbols have well-defined semantics.)

It’s still a bit of a hack, but it’s reaching the point where it’s strictly better than what we’re doing without introducing new holes in the analyzer logic. Thanks for working on this.

Finally…

  • Don’t forget test cases for the weak functions themselves! You need to verify (perhaps using clang_analyzer_eval) that a weak function starts out unknown, but can be constrained to null or non-null.
  • I think you can prune down the number of test cases lifted from other tests…you just need one to show that each function is still being treated specially and not as a generic opaque system function.
  • The initialization of FunctionTextRegion’s WeakSym can happen in the constructor initializers rather than the body.
  • Please be careful about the LLVM coding conventions. You got most of them, but there are still a few issues: comments should be full, capitalized sentences, lines should have no trailing whitespace (even blank lines), and types should have the * or & attached to the name.

Looking better…
Jordan

Hi Jordan,

That’s not quite going to work – what if I explicitly spell out my comparison?

if (MyWeakFunction == NULL) {
}

In this case, SimpleConstraintManager won’t go through your new assumeLocSymbol.

…although actually, it won’t make it there at all, because SimpleSValBuilder::evalBinOpLL folds null comparisons against non-symbolic regions. That’s actually easy enough to fix, though, and if you do that this might actually work.

I am not sure I follow you here. Why will this not work? On line 646 of SimpleSValBuilder we have:

if (SymbolRef lSym = lhs.getAsLocSymbol())
return MakeSymIntVal(lSym, op, rInt->getValue(), resultTy);

The metadata symbol will be returned here by getAsLocSymbol() and everything proceeds as expected. Testing this on the following trivial code shows a divide by zero warning for both branches of the IfStmt:

int myFunc() attribute((weak_import));
int main(int argc, char *argv)
{
if (myFunc == NULL) {
1 / 0;
} else {
1 / 0;
}
return 0;
}

Oh, and metadata symbols also die unless some checker specifically requests to keep them alive. I’m wondering now if the current behavior of SymbolExtent (immutable, lasts as long as the base region, only as path-specific as their region) is, in fact, closer to the desired behavior here than metadata symbols (invalidatable, path-sensitive, only lasts as long as someone is interested). If this is the case, maybe SymbolExtent should be made more generic.

(Sorry for giving you a runaround here. I’m not sure what the right thing to do is…I just want to avoid “new symbols” being the solution to every problem, and at the same time make sure that the existing symbols have well-defined semantics.)

OK, I was under the impression that a SymbolMetadata would stay alive as long as the MemRegion was, but I see that is incorrect in the docs. I would confess to not exactly being an expert on the Symbol class hierarchy, but it seems to me that SymbolExtent is not the right thing to use here. It has the properties we want, but as you mentioned before, it represents the size of a region. This seems an odd symbol to be using to represent a possible NULL pointer to a function. What about using a SymbolRegionValue here?

It’s still a bit of a hack, but it’s reaching the point where it’s strictly better than what we’re doing without introducing new holes in the analyzer logic. Thanks for working on this.

Finally…

  • Don’t forget test cases for the weak functions themselves! You need to verify (perhaps using clang_analyzer_eval) that a weak function starts out unknown, but can be constrained to null or non-null.
  • I think you can prune down the number of test cases lifted from other tests…you just need one to show that each function is still being treated specially and not as a generic opaque system function.

Yes, of course, silly omission.

  • The initialization of FunctionTextRegion’s WeakSym can happen in the constructor initializers rather than the body.

Ja, I wanted to do this, but it seemed like a bit of a chicken and egg thing. To create the symbol requires knowing the FunctionTextRegion in its constructor, so how does the FunctionTextRegion have the symbol in its constructor, without passing it the SymbolManager so it can create the symbol itself, which also seemed a bit odd. Or am I being stupid?

  • Please be careful about the LLVM coding conventions. You got most of them, but there are still a few issues: comments should be full, capitalized sentences, lines should have no trailing whitespace (even blank lines), and types should have the * or & attached to the name.

Will do, thought I had caught everything this time…

Hi Jordan,

That’s not quite going to work – what if I explicitly spell out my comparison?

if (MyWeakFunction == NULL) {
}

In this case, SimpleConstraintManager won’t go through your new assumeLocSymbol.

…although actually, it won’t make it there at all, because SimpleSValBuilder::evalBinOpLL folds null comparisons against non-symbolic regions. That’s actually easy enough to fix, though, and if you do that this might actually work.

I am not sure I follow you here. Why will this not work? On line 646 of SimpleSValBuilder we have:

if (SymbolRef lSym = lhs.getAsLocSymbol())
return MakeSymIntVal(lSym, op, rInt->getValue(), resultTy);

The metadata symbol will be returned here by getAsLocSymbol() and everything proceeds as expected. Testing this on the following trivial code shows a divide by zero warning for both branches of the IfStmt:

int myFunc() attribute((weak_import));
int main(int argc, char *argv)
{
if (myFunc == NULL) {
1 / 0;
} else {
1 / 0;
}
return 0;
}

Oops! I missed your changed to SVals.cpp. (This is what I get for reviewing patches by sight only.)

I am a little concerned about getAsLocSymbol always returning the metadata symbol, but maybe it’s okay. I need to go trace through the ramifications of that. My idea was to only produce the metadata symbol when we are sure we are doing a comparison (or a cast to bool, I suppose), since right now there’s no way to go from the symbol back to the region (wrapping the symbol in a SymbolicRegion would be incorrect).

Oh, and metadata symbols also die unless some checker specifically requests to keep them alive. I’m wondering now if the current behavior of SymbolExtent (immutable, lasts as long as the base region, only as path-specific as their region) is, in fact, closer to the desired behavior here than metadata symbols (invalidatable, path-sensitive, only lasts as long as someone is interested). If this is the case, maybe SymbolExtent should be made more generic.

(Sorry for giving you a runaround here. I’m not sure what the right thing to do is…I just want to avoid “new symbols” being the solution to every problem, and at the same time make sure that the existing symbols have well-defined semantics.)

OK, I was under the impression that a SymbolMetadata would stay alive as long as the MemRegion was, but I see that is incorrect in the docs. I would confess to not exactly being an expert on the Symbol class hierarchy, but it seems to me that SymbolExtent is not the right thing to use here. It has the properties we want, but as you mentioned before, it represents the size of a region. This seems an odd symbol to be using to represent a possible NULL pointer to a function. What about using a SymbolRegionValue here?

Heh. A bit of history: I added both SymbolExtent and SymbolMetadata. Originally I had hoped they’d be able to use the same kind of symbol, but it turned out that extents being non-invalidatable and metadata being somewhat volatile made it hard to unify the two. If we changed the symbol hierarchy now, we’d rename SymbolExtent – it’d be something like SymbolRegionMetadata and SymbolRegionContentsMetadata, except those names are ugly.

The other symbols have single, well-defined purposes, and I’d rather not overload them:

  • SymbolRegionValue represents the contents of a MemRegion, i.e. the value of a parameter or global variable.

  • SymbolDerived represents the contents of a subregion of a SymbolicRegion, e.g. the third field in a struct passed by value.

  • SymbolConjured represents the value of an expression that the analyzer can’t evaluate (usually a call expression).

I/we sometimes cheat and reuse SymbolConjured because it’s so flexible, but mostly it’s good to stick to these uses. And…

  • SymbolExtent is (currently) a single-purpose symbol used to represent the size (in bytes) of a region whose size is not statically known (i.e. by the compiler).
  • SymbolMetadata is a general-purpose symbol used to represent invalidatable metadata associated with a particular region.

(I realize all of this should be added to / clarified in our docs.)

  • The initialization of FunctionTextRegion’s WeakSym can happen in the constructor initializers rather than the body.

Ja, I wanted to do this, but it seemed like a bit of a chicken and egg thing. To create the symbol requires knowing the FunctionTextRegion in its constructor, so how does the FunctionTextRegion have the symbol in its constructor, without passing it the SymbolManager so it can create the symbol itself, which also seemed a bit odd. Or am I being stupid?

Ha, I just meant the initialization to NULL. I didn’t think through whether it was possible to push the creation of the weak symbol into the constructor.

Jordan

Hey,

Hi Jordan,

That’s not quite going to work – what if I explicitly spell out my comparison?

if (MyWeakFunction == NULL) {
}

In this case, SimpleConstraintManager won’t go through your new assumeLocSymbol.

…although actually, it won’t make it there at all, because SimpleSValBuilder::evalBinOpLL folds null comparisons against non-symbolic regions. That’s actually easy enough to fix, though, and if you do that this might actually work.

I am not sure I follow you here. Why will this not work? On line 646 of SimpleSValBuilder we have:

if (SymbolRef lSym = lhs.getAsLocSymbol())
return MakeSymIntVal(lSym, op, rInt->getValue(), resultTy);

The metadata symbol will be returned here by getAsLocSymbol() and everything proceeds as expected. Testing this on the following trivial code shows a divide by zero warning for both branches of the IfStmt:

int myFunc() attribute((weak_import));
int main(int argc, char *argv)
{
if (myFunc == NULL) {
1 / 0;
} else {
1 / 0;
}
return 0;
}

Oops! I missed your changed to SVals.cpp. (This is what I get for reviewing patches by sight only.)

I am a little concerned about getAsLocSymbol always returning the metadata symbol, but maybe it’s okay. I need to go trace through the ramifications of that. My idea was to only produce the metadata symbol when we are sure we are doing a comparison (or a cast to bool, I suppose), since right now there’s no way to go from the symbol back to the region (wrapping the symbol in a SymbolicRegion would be incorrect).

Is it not possible to get the region back from the symbol using getRegion()?

Oh, and metadata symbols also die unless some checker specifically requests to keep them alive. I’m wondering now if the current behavior of SymbolExtent (immutable, lasts as long as the base region, only as path-specific as their region) is, in fact, closer to the desired behavior here than metadata symbols (invalidatable, path-sensitive, only lasts as long as someone is interested). If this is the case, maybe SymbolExtent should be made more generic.

(Sorry for giving you a runaround here. I’m not sure what the right thing to do is…I just want to avoid “new symbols” being the solution to every problem, and at the same time make sure that the existing symbols have well-defined semantics.)

OK, I was under the impression that a SymbolMetadata would stay alive as long as the MemRegion was, but I see that is incorrect in the docs. I would confess to not exactly being an expert on the Symbol class hierarchy, but it seems to me that SymbolExtent is not the right thing to use here. It has the properties we want, but as you mentioned before, it represents the size of a region. This seems an odd symbol to be using to represent a possible NULL pointer to a function. What about using a SymbolRegionValue here?

Heh. A bit of history: I added both SymbolExtent and SymbolMetadata. Originally I had hoped they’d be able to use the same kind of symbol, but it turned out that extents being non-invalidatable and metadata being somewhat volatile made it hard to unify the two. If we changed the symbol hierarchy now, we’d rename SymbolExtent – it’d be something like SymbolRegionMetadata and SymbolRegionContentsMetadata, except those names are ugly.

The other symbols have single, well-defined purposes, and I’d rather not overload them:

  • SymbolRegionValue represents the contents of a MemRegion, i.e. the value of a parameter or global variable.

  • SymbolDerived represents the contents of a subregion of a SymbolicRegion, e.g. the third field in a struct passed by value.

  • SymbolConjured represents the value of an expression that the analyzer can’t evaluate (usually a call expression).

I/we sometimes cheat and reuse SymbolConjured because it’s so flexible, but mostly it’s good to stick to these uses. And…

  • SymbolExtent is (currently) a single-purpose symbol used to represent the size (in bytes) of a region whose size is not statically known (i.e. by the compiler).
  • SymbolMetadata is a general-purpose symbol used to represent invalidatable metadata associated with a particular region.

(I realize all of this should be added to / clarified in our docs.)

SymbolExtent it is then, what do you think of the attached patch? I have changed the QualType of the symbol when it is wrapping a weak FunctionTextRegion to a function pointer type, is this sufficient?

  • The initialization of FunctionTextRegion’s WeakSym can happen in the constructor initializers rather than the body.

Ja, I wanted to do this, but it seemed like a bit of a chicken and egg thing. To create the symbol requires knowing the FunctionTextRegion in its constructor, so how does the FunctionTextRegion have the symbol in its constructor, without passing it the SymbolManager so it can create the symbol itself, which also seemed a bit odd. Or am I being stupid?

Ha, I just meant the initialization to NULL. I didn’t think through whether it was possible to push the creation of the weak symbol into the constructor.

Jordan

Then I was being stupid, no easy fix for that unfortunately :expressionless:

Richard

weak.diff (5.96 KB)