I'm working on my stb_image wrapper right now. It's almost ready for release. But to be a good little developer I want to test it on the three major platforms (Linux, OS X, and Windows) before saying it's v1.0.
I developed it on Linux and it passes all of the unit tests. But when I tried to have it run on OS X (sierra), I got this error:
[Suite] Unit Tests for stb_image wrapper
Traceback (most recent call last)
tests.nim(56) tests
stb_image.nim(86) load
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
The line in question can be found here: https://gitlab.com/define-private-public/stb_image-Nim/blob/bd4fc301069b068d7657b838ecf369be0573683a/stb_image.nim#L86
I did a little investigating. The wrapped function stbi_load() is setting the width, height, and components variables like it should, but nothing is being passed into data upon the function's return. I got the same error when I tried to do this:
echo data[]
I really have no idea what is wrong.
It seems like that the original sbti_load() function from the library just returns NULL instead of actual pointer. You may can check it using the repr proc:
echo data.repr
As far as I can see, the sbti_load() function receives a file name so may be the issue is in the test suite, in the test file names declarations. You can also investigate the problem by inspecting produced C files in the nimcache directory.It shouldn't be an issue with the test suite. I added this line right after the let data = stbi_load(... call
echo x
echo y
echo channels_in_file
echo data.repr
And it gave me this output:
2
2
4
Traceback (most recent call last)
tests.nim(56) tests
stb_image.nim(86) load
repr.nim(308) reprAny
repr.nim(252) reprAux
repr.nim(234) reprRef
repr.nim(271) reprAux
SIG
SEGV: Illegal storage access. (Attempt to read from nil?)
I find this very odd because the return parameters are fine, but the actual returned value is not.
This behaviour is very odd indeed. The pointer received from the function is not nil, but it is not valid though. Is it possible situation if the stbi_load function would return the actual cuchar(s) instead of the pointer? You might also want to check the numeric representation of the returned pointer using the following code:
echo cast[pointer](data).repr
It should not fail even when the pointer is invalid.Alright, I tried that and it does echo out a pointer address (e.g. 0xFFff08b7e).
Where this is getting kind of weird for me is that I have this raytracer that I'm working on that uses stb_image.h as well and it able to load an image on OS X without throwing a seg fault. The code for the mini-wrapper is here: https://gitlab.com/define-private-public/PeterShirley-RayTracing-Nim/blob/7130281eee79c76be8e0c6ecb6dc36c99ab5aa52/book2/stb_image.nim
The only major difference is that the wrapper in the ray tracer doesn't have the header file embedded directly in a .nim file, though that shouldn't matter.
I am really perplexed by this.
First four cuchars of data may be looking like a regular pointer address. Have you performed a comparsion between first bytes of data(actual data, not a pointer) from the working test and bytes in this invalid pointer? It is not very likely but the data might be dereferenced somehow in the generated code.
As long as Nim directly translates to C before compilation, it would be useful to compare the generated C code from nimcache directory in both of the working mini-wrapper and the failing test to collect more clues.
Well, I got the unit tests run without any segfaults (on OS X).
On a whim, I decided to change the import stb_image_header line (in stb_image.nim) to use the include statement instead; it worked. Is this a bug I should report?
I don't think that it is a bug. The import keyword is designed to be used with Nim symbols, not with directly emitted C code. It might be just a side effect that your code with import worked.
Probably, it will be a better solution to use the header pragma instead of including whole header into the Nim source.
I put the source of the header in it's own .nim file so my users wouldn't have to add a --cincludes: option at the compilation step.
I do find it odd that import had different behavior on Linux vs. OS X in regards to this, and it effected a return value.