Skip to content
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

context of bad reference object is not present when FaultError is thrown #39

Open
ahrens opened this issue Jan 28, 2020 · 0 comments
Open

Comments

@ahrens
Copy link

ahrens commented Jan 28, 2020

Context

When the value of a reference-type object is determined, we generate a FaultError if the object is stored at an address which is not mapped. This happens when calling .read_() on it, which happens implicitly in most cases (e.g. printing, doing math). This may happen via a significantly different code path than when the reference-type object was instantiated.

Example problem

For example, one class may call some_int = pointer_to_struct_obj.some_member, to "dereference" an integer-type member. However, since a reference-type object is created, drgn does not read from the target address space at this time. The pointer_to_struct_obj's value is determined, (i.e. points to memory address 0x1234), but some_int's value is not known, (e.g. we only know that it is at memory address 0x1235). Therefore, some_int, an reference-type object to an integer, may be stored at an invalid memory address (i.e. one that is not mapped by the target kernel, dump, or process).

The class mentioned above may pass this "integer" (actually a reference object to an integer at target memory address 0x1235) to a different, unrelated class, which then uses the "integer", by doing math with it, printing it, etc. All of these implicitly call some_int.read_(), which attempts to read from the referenced address in the target. If the address is not mapped, a FaultError will be thrown. At best, this FaultError can identify that we tried to read an object of type X (e.g. long long int) from address Y (e.g. 0x1235). However, from the programmer's point of view, the problem was that pointer_to_struct_obj was a bad pointer, and we dereferenced it by doing pointer_to_struct_obj.some_member. Unfortunately, this information is not available at the time the FaultError is generated (specifically, the type and value of pointer_to_struct_obj, and the name of the member being accessed some_member).

An even more confusing example involves reference pointers. When doing some_int = pointer_to_struct_obj.some_member, it may be that pointer_to_struct_obj is a reference object, i.e. we do not know the value of the pointer, only where it is stored. We need to determine its value now, so we attempt to read from the target, generating a FaultError if it is not mapped. This is confusing because the problem is not that the struct we are trying to dereference is at a bad address, but rather that the pointer to the struct is stored at a bad address.

Proposed Solution

I propose that we change the semantics of drgn.Object.member_() such that if the memory address referenced by the newly-created reference object is not mapped by the target, we generate a FaultError at this time. The FaultError should include the type of the struct and name, type and address of the member that's being accessed.

This should probably also be extended to the creation of reference objects in general. In the more general case, we may not be able to include much additional information in the FaultError, but at least the exception will be thrown when the reference object is created, rather than by the likely unrelated code that uses the reference object.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant