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

class method returns one value, but is_a?(<this value>) contradicts. Can't debug #2376

Closed
waterlink opened this issue Mar 27, 2016 · 27 comments
Labels
kind:bug A bug in the code. Does not apply to documentation, specs, etc. status:needs-more-info topic:compiler

Comments

@waterlink
Copy link
Contributor

v = self.value
pp v.class
pp v.is_a?(String)
if v.class == String && !v.is_a?(String)
  raise "oops"
end

outputs:

v.class = String
v.is_a?(String) = false
Could not raise

I have no idea what v value is, since any way I try to introspect it, it fails with segmentation fault (11).

The library was working in 0.13.x correctly.

A method where error happens is here: https://github.com/waterlink/mocks.cr/blob/master/src/mocks/registry.cr#L34-L36

I have no idea how to debug or reduce the code size :( Any help is much appreciated..

@waterlink waterlink changed the title Very very strange problem class method returns one value, but is_a?(<this value>) contradicts. Can't debug Mar 27, 2016
@waterlink
Copy link
Contributor Author

Original value, where this String comes from (object.to_s), has the same property:

o = @original_object
pp o.class        # => Class
pp o.is_a?(Class) # => false

@waterlink
Copy link
Contributor Author

Seems to be somehow related to Hash and custom classes, that implement #== and #hash. Not sure yet how exactly.

@waterlink
Copy link
Contributor Author

Narrowed down even more:

# somewhere in CallStub#fetch
pp found
v = found[1]
pp v.class # => Mocks::Registry::ResultWrapper(Mocks::Registry::Result(Array(String)))
pp v.is_a?(Mocks::Registry::ResultWrapper(Mocks::Registry::Result(Array(String)))) # => false

And if I look at found inspection, I clearly see that the real type is Mocks::Registry::ResultWrapper(Mocks::Registry::Result(Mocks::Registry::NoArgs). I don't quite understand, how is it possible..

@waterlink
Copy link
Contributor Author

Apparently, if I actually do

pp v.is_a?(Mocks::Registry::ResultWrapper(Mocks::Registry::Result(Mocks::Registry::NoArgs))) # => true

Segmentation fault goes away (probably because type system finally figures out the type?).

@waterlink
Copy link
Contributor Author

Now next test fails, when the value is of type Mocks::Registry::ResultWrapper(Mocks::Registry::Result(Time)).

So there is some problem with type system now. Or at least it work differently from what it was before.

@waterlink
Copy link
Contributor Author

I can't even access its crystal_type_id, it simply segfaults on access..

@waterlink
Copy link
Contributor Author

The type there should definitely contain a union, like Time|NoArgs|Array(String)|.... But it is not

@waterlink
Copy link
Contributor Author

I was unable to minimize the code-to-reproduce and to pinpoint the problem.

Rather I have stopped confusing the type system and re-written the Registry implementation with proper generics, so that at any point of time, arguments type is known to the code and it is not a union, but specific type T. I have been able to shield the user from this change by using typeof({{arguments_tuple}}) in mock macro.

@jhass jhass added kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:compiler labels Mar 29, 2016
@asterite
Copy link
Member

@waterlink If you can point me to a revision or some code that exhibits the bug I can try to reduce it and fix it. Thanks!

@waterlink
Copy link
Contributor Author

@asterite Do you mean the revision of Crystal lang? i.e.: result of bisect?

@asterite
Copy link
Member

@waterlink I mean some code of yours that I can do crystal your_code.cr and shows the bug

@waterlink
Copy link
Contributor Author

@asterite Here you go: https://github.com/waterlink/mocks.cr/tree/7222b92155e9272c42a67c57ac851ecaad284d6d

git clone https://github.com/waterlink/mocks.cr -b 7222b92155e9272c42a67c57ac851ecaad284d6d && cd ./mocks.cr
crystal spec -v

@waterlink
Copy link
Contributor Author

Relevant file causing the failure is src/mocks/registry.cr, which does have some weird stuff going to workaround the fact, that we can't yet store Object in Hash (or use as any generic-type parameter).

@asterite
Copy link
Member

@waterlink Just checked out at that revision and ran crystal spec -v and they all pass. Should I look into something in particular?

@waterlink
Copy link
Contributor Author

I am getting this error on Crystal 0.14.2:

Spies
  fails when there was no call
  suceeds when there was a call
  fails when there was a call with different arguments
  works as stdlib spec expectation
  works with module mock
Application mock
  works
  works without class double
create module mock macro
  does not fail with Nil errors
  does not fail with Nil errors for stdlib class
Mocks::Registry::Method
  #received?(object_id, args)
    is false when there were no such call
    is true when there was such call
    is false when arguments are different
  #last_received_args(object_id)
    returns nil when there were no call
    returns arguments of last callInvalid memory access (signal 11) at address 0x4
[4767685] *CallStack::print_backtrace:Int32 +117
[4676712] __crystal_sigfault_handler +56
[5139848] sigfault_handler +40
[140039758357312] ???
[4760512] *String#hash<String>:Int32 +32
[5006045] *Mocks::Registry::ObjectId#hash<Mocks::Registry::ObjectId>:(Int32 | UInt64) +61
[5015968] *{Mocks::Registry::ObjectId, Mocks::Registry::ArgsInterface} +48
[5013320] *Mocks::Registry::StubKey#hash<Mocks::Registry::StubKey>:Int32 +40
[4879990] *Hash::StandardComparator::hash<Mocks::Registry::StubKey>:Int32 +6
[4998685] *Hash(Mocks::Registry::StubKey, Mocks::Registry::ResultInterface) +13
[4998883] *Hash(Mocks::Registry::StubKey, Mocks::Registry::ResultInterface) +67
[4994889] *Mocks::Registry::CallHash#add<Mocks::Registry::CallHash, Mocks::Registry::ObjectId, Array(String), Mocks::Registry::Result(Bool)>:Mocks::Registry::ResultWrapper(Mocks::Registry::Result(Bool)) +105
[7729760] ???

Are you trying to run it on 0.14.2 or HEAD?

@waterlink
Copy link
Contributor Author

When test is run in isolation I get almost the same failure:

$ crystal spec -v -e 'returns arguments of last call'
Mocks::Registry::Method
  #last_received_args(object_id)
    returns arguments of last callInvalid memory access (signal 11) at address 0x27dff
[4767685] *CallStack::print_backtrace:Int32 +117
[4676712] __crystal_sigfault_handler +56
[5139848] sigfault_handler +40
[140376344036160] ???
[5006176] *Mocks::Registry::ObjectId#==<Mocks::Registry::ObjectId, Mocks::Registry::ObjectId>:Bool +32
[5006414] *Mocks::Registry::ObjectId#==<Mocks::Registry::ObjectId, Mocks::Registry::ObjectId>:Bool +270
[5014186] *Mocks::Registry::StubKey#==<Mocks::Registry::StubKey, Mocks::Registry::StubKey>:Bool +858
[41809344] ???

@asterite
Copy link
Member

Linux?

@waterlink
Copy link
Contributor Author

Yes

@waterlink
Copy link
Contributor Author

Ubuntu 14.04.1 LTS

@waterlink
Copy link
Contributor Author

I will try inside of docker run crystallang/crystal:0.14.2 to see if it is just my specific setup problem (maybe some library weird version, or rather something like that).

@waterlink
Copy link
Contributor Author

Same problem inside of clean docker container.

@asterite
Copy link
Member

Strange. Just tried it on a vm (vagrant, the one in the repository, trusty64) and it works fine.

@waterlink
Copy link
Contributor Author

That is indeed strange. By the way, I have just tried to run it on crystallang/crystal:head - the same failure.

@waterlink
Copy link
Contributor Author

Any way it could be related to Linux Kernel version? To my knowledge, it is the only thing that is shared between docker container and host machine, for practical purposes?

@asterite
Copy link
Member

@waterlink Are you still having this issue?

@asterite
Copy link
Member

Closed in favor of #2665

@waterlink
Copy link
Contributor Author

@asterite I have made a clean rewrite, that completely avoided the issue. I am not sure if it is still there now, since old code won't work with new compiler, most probably.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind:bug A bug in the code. Does not apply to documentation, specs, etc. status:needs-more-info topic:compiler
Projects
None yet
Development

No branches or pull requests

3 participants