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

invalid memory access from uninitialized variable #4544

Closed
masukomi opened this issue Jun 11, 2017 · 3 comments
Closed

invalid memory access from uninitialized variable #4544

masukomi opened this issue Jun 11, 2017 · 3 comments

Comments

@masukomi
Copy link
Contributor

I'm not sure if this is a bug but it's definitely unexpected behavior

Expected Behavior:

uninitialized variables should not pass ! var.nil? or if var tests

Actual Behavior

exactly the opposite

Environment

macOS 10.12.4
Crystal 0.22.0 (2017-04-20) LLVM 4.0.0

Sample code

#tester.cr
log_version = uninitialized String

if ! log_version.nil?
  puts "it's not nill"
else
  puts "totally nil"
end
if log_version
  puts "log version is #{log_version}"
else
  puts "no log version"
end

compile that then run it

$ ./tester
it's not nill
Invalid memory access (signal 11) at address 0x7fff529c7000
[0x10d25e9ab] *CallStack::print_backtrace:Int32 +107
[0x10d24a38c] __crystal_sigfault_handler +60
[0x7fff9a43ab3a] _sigtramp +26

So, I can test if it's nil and it tells me it's not. I can test if it exists and it tells me it does, but if i try and do anything with it, it blows up.

In my code i had to change it to log_version = nil.as(String?) to get around this because it isn't clear how to test if a variable is uninitialized. It's probably in the doc's somewhere but I haven't found it, and i really don't think that the tests above should BOTH pass... I can see the argument against ! log_version.nil? passing, because it's not really nil. It's uninitialized but the fact that it passes the second test seems crazy. it's the most non-existent form of something. How can that be truthy?

@mverzilli
Copy link

uninitialized is a low-level, unsafe hack: https://crystal-lang.org/docs/syntax_and_semantics/declare_var.html

When you use it, you basically renounce most of the safety guarantees that Crystal provides, for the sake of performance or interoperability with C code.

Are you sure you really need to use declare an uninitialized var? What would be your use case?

@RX14
Copy link
Contributor

RX14 commented Jun 11, 2017

You can always model what you would have done with uninitialized with nil, and it'll be safer and cleaner code. The only use for uninitialized is for performance where you don't want to create a type union, but unless you really know what you're doing removing safety for a tiny increase in speed is unwise.

Unless you're binding C code then uninitialized is useful.

@RX14
Copy link
Contributor

RX14 commented Jun 11, 2017

For reference, there's no way to know if a variable is initialized or not because it will contain entirely random data. If it's a reference it will likely point to uninitialized memory (at least on 64bit), if it's a struct it will contain garbled data. There's no sane way to detect what is uninitialized.

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

4 participants