-
Notifications
You must be signed in to change notification settings - Fork 197
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
reasonClassSizeGTE_D is buggy #209
Comments
I was able to reproduce this, thanks. |
Adding consistency checks at each step during initial reasoning finds a slightly different problem:
So we decide that the object is exactly 0x18 bytes long and 0x1c bytes long. Yep, that sounds like a contradiction to me ;) |
Some additional logging:
|
|
I think I know what is happening. The function 0x591820 is allocating either a CEngineSurface or a CEngineCompressedSurface. Both of these inherit from CEngineSurfaceBase, whose constructor is 0x591bf0. So, this seems to be a counter-example for reasonClassSizeGTE_D. If a function allocates two classes that have a common base, but the classes have a different allocation size, it will cause GTE_D to fail. But we already have a clause to deal with this: https://github.com/cmu-sei/pharos/blob/master/share/prolog/oorules/rules.pl#L3222
@sei-ccohen What do you think? |
@Trass3r As a workaround, you could try to remove one of or both of the thisPtrAllocation facts I posted above. |
@sei-eschwartz doesn't seem to make a difference? |
You are right, there appears to be at least one other problem when those are commented out. I'll play with it some more today. |
Here is the error I get when I comment those out: insanityClassSizeInvalid failed: Class=0x66ed14 LTESize=0x70 GTESize=0xb0 0x66ed14 is apparently the vftable for the CGadget class. This is what IDA has to say about 0x66ed14:
0x52b810 is CGadget::CGadget. It looks like 0x52a0d0 constructs a CButton, which inherits from CGadget. So same problem. |
@Trass3r For now you may just want to disable the problematic rules:
This does get past initial reasoning at least. It's still running for me. |
And it hit another sanity problem :(
0x5b88c0 is definitely not a constructor |
Yeah the |
Neat, we knew about ICF but not exactly what it was called. @sei-ccohen https://docs.microsoft.com/en-us/cpp/build/reference/opt-optimizations?view=msvc-170 |
0x5b88c0 and 0x5d91e0 are both kind of weird. 0x5d91e0 more so. It calls delete on the pointer at offset 8. So it's not a regular deleting destructor. Anyway, let me summarize:
But we also conclude:
Why can't 0x5b88c0 be a real destructor? Trying to figure that out. |
Because pharos' static analysis decided it can't be |
I am running again here, but it would help @Trass3r if you have the facts log file and could look for the message that says:
|
Hmm. I just ran and I do have a |
I was able to run through with my .facts file and applying the patch I posted above. |
Don't have it in front of me right now but should still be the same as in #139 (comment) @sei-eschwartz ah actually 3 by now: |
That indeed made a difference. I get:
Looking at function 0x5fedd0, it seems that an object is constructed at stack offset 0x20, destructed, and then constructed and destructed again. Specifically:
When this happens on the heap, we can use a call to new or delete to say that these are two different object lifetimes. But on the stack we can't do that of course. So right now the rationale is that 0x5b88c0 cannot be a destructor because 0x5b8770 is called after it on the same object. I wonder if we could change the logic to only look at the last two calls. If we think that 0x5b8770 might be a destructor, then it makes sense to only look at the last call of the destructor and see if any other method is invoked on that. The question is what side effects would that have? |
With those changes I was able to do a complete run. Note that the problem in ClassSizeGTE_D is still not fixed. |
Getting back to the GTE_D problem. We track a constructor call to offset 0 of a newly allocated object, and we basically want to know whether the constructor is for the newly allocated object. The example we saw is that class C inherits from class B. Class C's constructor is inlined, but class B's is not. We can tell from manual examination because the inlined constructor has a VFTable installation, which is a sign that there are two constructors. So one observation is that if we see a call to a constructor at offset 0, and that constructor has a vftable installed at offset 0, then if a derived constructor was inlined we would also see a vftable installed at offset 0. If we see a call to a constructor with a vftable write, and the calling context does not have a vftable write, then I think the constructor is the outermost constructor. (Is this true for embedded objects?) Alternatively, if we know that a class has no ancestors or descendants, the constructor call must be on the class itself, right? No... not quite because it could be on an embedded class at offset 0. |
|
Not sure if this is still related to the original problem but it still doesn't run through:
|
Hopefully it is unrelated, I'll check it out. It could be #227. That binary reminded me of yours in a few ways.
Sent from my T-Mobile 5G Device
Get Outlook for Android<https://aka.ms/AAb9ysg>
…________________________________
From: Trass3r ***@***.***>
Sent: Saturday, July 9, 2022 5:42:13 PM
To: cmu-sei/pharos ***@***.***>
Cc: Edward J Schwartz ***@***.***>; Mention ***@***.***>
Subject: Re: [cmu-sei/pharos] reasonClassSizeGTE_D is buggy (Issue #209)
Not sure if this is still related to the original problem but it still doesn't run through:
Contradictory information about constructor: factConstructor(0x5de050) but reasonNOTConstructor(0x5de050)
Constraint checks failed, retracting guess!
failed.
Consistency checks failed.
Contradictory information about constructor: factConstructor(0x600400) but reasonNOTConstructor(0x600400)
Constraint checks failed, retracting guess!
tryBinarySearch completely failed on [0x5de050] and will now backtrack to fix an upstream problem.
Refusing to backtrack into reasoningLoop to fix an upstream problem because backtrackForUpstream/0 is not set.
This likely indicates that there is a problem with the OO rules.
Please report this failure to the Pharos developers!
[150] prolog_stack:get_prolog_backtrace(100,[frame(150,clause(<clause>(0x5ce281eb4d00),6),_5626440)|_5626428],[goal_term_depth(100)]) at /usr/local/lib/swipl/library/prolog_stack.pl:137
[149] throw_with_backtrace(error(system_error(upstreamProblem))) at /usr/local/share/pharos/prolog/oorules/util.pl:185
[26] solve_internal at /usr/local/share/pharos/prolog/oorules/setup.pl:681
[25] catch(user:solve_internal,_5626664,user:((_5626732=error(resource_error(private_table_space),_5626746)->complain_table_space(ooscript);_5626796=error(resource_error(stack),_5626810)->complain_stack_size(ooscript);true),throw(_5626842))) at /usr/local/lib/swipl/boot/init.pl:562
[24] solve(ooscript) at /usr/local/share/pharos/prolog/oorules/setup.pl:617
—
Reply to this email directly, view it on GitHub<#209 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AL6ZAVG4PVAE6DZKE6YIWWLVTHW3LANCNFSM5NXCSE2Q>.
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
I might see what is going wrong...
So we decide that this vftable belongs to the current constructor based on the vftable write. Here is the vftable write: .text:005DD7C0 call ??2@YAPAXI@Z ; operator new(uint) In other words, we install this vftable into a new heap-allocated object, not the "this" object this constructor is constructing. I think this is a side-effect of a change we made recently that exported possibleVFTableFacts for non-this objects. The solution is to validate that the vftable write is in "this" object. I am trying this now. |
Hopefully it's unrelated but I'll check it out. It might be related to
#227.
…On Sat, Jul 9, 2022, 5:42 PM Trass3r - ***@***.*** ***@***.***> wrote:
Not sure if this is still related to the original problem but it still
doesn't run through:
Contradictory information about constructor: factConstructor(0x5de050) but reasonNOTConstructor(0x5de050)
Constraint checks failed, retracting guess!
failed.
Consistency checks failed.
Contradictory information about constructor: factConstructor(0x600400) but reasonNOTConstructor(0x600400)
Constraint checks failed, retracting guess!
tryBinarySearch completely failed on [0x5de050] and will now backtrack to fix an upstream problem.
Refusing to backtrack into reasoningLoop to fix an upstream problem because backtrackForUpstream/0 is not set.
This likely indicates that there is a problem with the OO rules.
Please report this failure to the Pharos developers!
[150] prolog_stack:get_prolog_backtrace(100,[frame(150,clause(<clause>(0x5ce281eb4d00),6),_5626440)|_5626428],[goal_term_depth(100)]) at /usr/local/lib/swipl/library/prolog_stack.pl:137
[149] throw_with_backtrace(error(system_error(upstreamProblem))) at /usr/local/share/pharos/prolog/oorules/util.pl:185
[26] solve_internal at /usr/local/share/pharos/prolog/oorules/setup.pl:681
[25] catch(user:solve_internal,_5626664,user:((_5626732=error(resource_error(private_table_space),_5626746)->complain_table_space(ooscript);_5626796=error(resource_error(stack),_5626810)->complain_stack_size(ooscript);true),throw(_5626842))) at /usr/local/lib/swipl/boot/init.pl:562
[24] solve(ooscript) at /usr/local/share/pharos/prolog/oorules/setup.pl:617
—
Reply to this email directly, view it on GitHub
<#209 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAHYKZLIZTZLWPNNVAXBFKLVTHW3LANCNFSM5NXCSE2Q>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
Facts
Even when using the
purecall(0x634d60).
hack from #139. Still the same testbed.The text was updated successfully, but these errors were encountered: