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

sclang: protect keysValuesArrayDo primitive #2799

Merged

Conversation

telephon
Copy link
Member

This can happen in corner cases. Fixes #852.

This can happen in corner cases. Fixes supercollider#852.
@telephon
Copy link
Member Author

It fails with a double error message:

ERROR: primitive failed: keysValuesArrayDo first argument should be an array.
ERROR: Primitive '_ObjectString' failed.
Failed.
RECEIVER:
Instance of Event {    (0x11a59da68, gc=74, fmt=00, flg=00, set=03)

But maybe someone can give me hints of how to improve it!

@@ -1758,6 +1758,18 @@ HOT void Interpret(VMGlobals *g)
PyrSlot * vars = g->frame->vars;
int m = slotRawInt(&vars[3]);
PyrObject * obj = slotRawObject(&vars[1]);

if (IsNil(&vars[1])) {
error("primitive failed: keysValuesArrayDo first argument should be an array.\n");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this error message please match the others in this file? See above line 1666:

error("Integer-forBy : endval or stepval not an Integer.\n");

and below line 1967:

error("Number-forSeries : first, second or last not an Integer or Float.\n");

@@ -1758,6 +1758,18 @@ HOT void Interpret(VMGlobals *g)
PyrSlot * vars = g->frame->vars;
int m = slotRawInt(&vars[3]);
PyrObject * obj = slotRawObject(&vars[1]);

if (IsNil(&vars[1])) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this check happen before lines 1759-1760?

@mossheim
Copy link
Contributor

mossheim commented Mar 19, 2017

That double error message matches what happens when hitting similar cases in PyrInterpreter3:

3.forBy("string"); 
// ERROR: Integer-forBy : endval or stepval not an Integer.
// ERROR: Primitive '_ObjectCompileString' failed.

3.forSeries("garbage");
// ERROR: Number-forSeries : first, second or last not an Integer or Float.
// ERROR: Primitive '_ObjectCompileString' failed.

I think it's fine for the purposes of this PR. Thanks for this!

@mossheim
Copy link
Contributor

There's an inconsistency between the check (IsNil) and the error message (should be an array). One of those needs to be modified—I'd go for more robust type-checking at this point, but since the crash only happens when the input is nil, amending the error message wouldn't be bad either.

@mossheim mossheim added comp: sclang sclang C++ implementation (primitives, etc.). for changes to class lib use "comp: class library" waiting for testing and removed waiting for testing labels Mar 19, 2017
@telephon
Copy link
Member Author

the check could be more elaborate, but given that this is an internal method, checking against nil is ok, I think. Alternatively, one can check how it's done in the array primitives - it is a little more complicated there.

@telephon
Copy link
Member Author

I still find it weird that the second error message is ERROR: Primitive '_ObjectString' failed.. But, well.

@nhthn
Copy link
Contributor

nhthn commented Mar 19, 2017

Can we get a unit test please?

@mossheim
Copy link
Contributor

@telephon Can you give the code you used to produce that error message? I find it interesting that mine refers to the primitive _ObjectCompileString.

The code looks pretty good; I am OK to merge once there's a unit test. :)

@telephon
Copy link
Member Author

().keysValuesArrayDo()

I'll do a test next week.

@telephon
Copy link
Member Author

this code: e = (); e.array = nil; e.keysValuesDo({}); causes the interpreter go in an infinite print loop, repeating:

Instance of PrimitiveFailedError {    (0x11a441f88, gc=88, fmt=00, flg=00, set=03)
  instance variables [5]
    what : "Failed."
    protectedBacktrace : nil
    path : nil
    receiver : instance of Event (0x16bbc6fa8, size=5, set=3)
    failedPrimitiveName : Symbol '_ObjectString'
}
ERROR: Dictionary-keysValuesArrayDo: first argument should not be nil.
ERROR: throw during error handling!

@telephon
Copy link
Member Author

telephon commented Mar 21, 2017

I'm not sure if I'm doing the right thing to the stack here:

if (IsNil(&vars[1])) {
	error("Dictionary-keysValuesArrayDo: first argument should not be nil.\n");
	
	slotCopy(++sp, &g->receiver);
	numArgsPushed = 1;
	selector = gSpecialSelectors[opmPrimitiveFailed];
	slot = sp;
	
	goto class_lookup;
}

Setting numArgsPushed = 0 fixes some issues (wrong error message and
looped error handling).
@telephon
Copy link
Member Author

Ok, setting numArgsPushed = 0 fixes it. Please have a look if that is correct.

@telephon
Copy link
Member Author

(can be merged IMHO)

@mossheim
Copy link
Contributor

I was wary of this one mainly because of the uncertain copy-pasting into the main interpreter loop, but I guess since the others seem to be similarly weird with posting _ObjectCompileString / _ObjectString it's probably OK. One thing I noticed just now is that the unit tests test an Event object and not a Dictionary. I'm going to change that and then merge. Thanks!

@mossheim
Copy link
Contributor

Thanks! Eventually we should get to the bottom of why _ObjectString is the named primitive in the error message/call stack.

@mossheim mossheim merged commit 2d7b3b7 into supercollider:master May 27, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
comp: sclang sclang C++ implementation (primitives, etc.). for changes to class lib use "comp: class library"
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants