Skip to content

Avoidance of KV-Exceptions #66

@Objective-Cloud

Description

@Objective-Cloud

First of all: Great work on GRMustache. We have integrated GRMustache deeply into our open source framework for web development at Objective-Cloud. We are using it in production and for our own "applications" that are running in the cloud. However there is one problem which causes a lot of problems: The NSUndefinedKey-exceptions that come up.

In general, a thrown exception (even if it is caught), is not nice. This is especially true for something that is running in the cloud (all the time). Every thrown exception causes memory leaks. This could be used by an attacker: She could constantly request the rendering of a template that is known to cause lots of exceptions (internally). In the end of the day the app will use more and more memory.

There is a workaround: The compiler (more precise: the ARC-subsystem) can be told to generate exception-safe code. The downside is that the code generated by ARC becomes a lot bigger.

The other workaround is, as documented, to call

[GRMustache preventNSUndefinedKeyExceptionAttack];

The documentation says, this should be for debugging only and I understand why: It is swizzeling valueForUndefinedKey: which is a hack in and of itself in my opinion.

Another workaround is (and that is what we have done for our own applications) is to use mustache in a way so that no undefined key exception is thrown: So we don't really use the context stack-feature. This works but sometimes it is "hard" to do certain things because the context stack is such an integral feature of mustache.

I have thought about a proper solution for this problem. I would like to describe my solution and make hereby a request for comments. If you think that my solution is okay then I would go ahead and implement it.

The solution:

The main problem is, that you call -valueForKey: and you don't really know if the key is defined for the object in question. You are not to blame for that since this is/was the only viable solution up until a few months ago. In my opinion GRMustache is the perfect use-case for keyed-subscripting.

Here is how it should work in my opinion:

  1. Before GRMustache is calling -valueForKey on an object it should check to see if the following is true: [object respondsToSelector:@selector(objectForKeyedSubscript:)]. In other words: Do not call -valueForKey: if the object supports keyed-subscripting.
    1. (object does not support keyed-subscripting): Call -valueForKey: and we are done (backwards compatibility)
    2. (object supports keyed-subscripting): Call objectForKeyedSubscript:.
  2. (objectForKeyedSubscript: was called)
    1 returned something non-nil: Use the return value as the resulting value and render it.
    2 returned nil: Go up in the stack and repeat the whole procedure.

Rationale:

objectForKeyedSubscript: is often implemented in a way that does simply return nil if the key was not found. A developer can add GRMustache support to his custom class by simply implemented keyed-subscripting which is trivial in most circumstances.

What do you think?

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions