[LuaJIT ffi] Misleading error message?

classic Classic list List threaded Threaded
20 messages Options
Reply | Threaded
Open this post in threaded view
|

[LuaJIT ffi] Misleading error message?

Thomas Lauer-3
During my experiments with ffi I've run into this.

The following code, run under Windows, produces an error message for
line 4 which IMHO is misleading at best but more probably spurious?

ffi=require('ffi')
ffi.cdef('void DebugBreak(void);')  -- Any function will do
if ffi.C.DebugBreak then print(ffi.C.DebugBreak) end  -- OK
if ffi.C.DebugBreak~=nil then print(ffi.C.DebugBreak) end

luajit.exe: f:\testffi.lua:4: attempt to compare 'void ()' with 'void *'

--
cheers  thomasl

Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

Mike Pall-29
Thomas Lauer wrote:
> The following code, run under Windows, produces an error message for
> line 4 which IMHO is misleading at best but more probably spurious?
>
> ffi=require('ffi')
> ffi.cdef('void DebugBreak(void);')  -- Any function will do
> if ffi.C.DebugBreak then print(ffi.C.DebugBreak) end  -- OK
> if ffi.C.DebugBreak~=nil then print(ffi.C.DebugBreak) end
>
> luajit.exe: f:\testffi.lua:4: attempt to compare 'void ()' with 'void *'

Well, the error message is correct. You're comparing a function
with nil (which is treated like a pointer to void here).

But it's debatable whether comparing a function with a pointer
should be disallowed. In C, functions and function pointers are
almost universally exchangeable, so I guess this should be
allowed here. I've changed the semantics in git HEAD.

[But note that neither of two conditionals in your code can ever
be true. Only nil and false are treated as not-true conditions.
And GetProcAddress() returns NULL on error, so there cannot be a
dynamically resolved function with a NULL address.]

--Mike

Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

Xavier Wang

Hi mike,

Is that difficult to make unresolved function name become nil?
ffi.C.foobar --> nil

在 2011-7-23 晚上10:45,"Mike Pall" <[hidden email]>写道:
> Thomas Lauer wrote:
>> The following code, run under Windows, produces an error message for
>> line 4 which IMHO is misleading at best but more probably spurious?
>>
>> ffi=require('ffi')
>> ffi.cdef('void DebugBreak(void);') -- Any function will do
>> if ffi.C.DebugBreak then print(ffi.C.DebugBreak) end -- OK
>> if ffi.C.DebugBreak~=nil then print(ffi.C.DebugBreak) end
>>
>> luajit.exe: f:\testffi.lua:4: attempt to compare 'void ()' with 'void *'
>
> Well, the error message is correct. You're comparing a function
> with nil (which is treated like a pointer to void here).
>
> But it's debatable whether comparing a function with a pointer
> should be disallowed. In C, functions and function pointers are
> almost universally exchangeable, so I guess this should be
> allowed here. I've changed the semantics in git HEAD.
>
> [But note that neither of two conditionals in your code can ever
> be true. Only nil and false are treated as not-true conditions.
> And GetProcAddress() returns NULL on error, so there cannot be a
> dynamically resolved function with a NULL address.]
>
> --Mike
>
Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

Mike Pall-29
Xavier Wang wrote:
> Is that difficult to make unresolved function name become nil?
> ffi.C.foobar --> nil

That's not difficult. But there would be no way you could get the
error message then (a table lookup can only return one result).
And you'd have to litter your code with asserts. It makes more
sense to error out here. For a C program you'll get an error when
the static or dynamic linker fails to resolve a symbol, too.

--Mike

Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

Xavier Wang


在 2011-7-23 晚上11:03,"Mike Pall" <[hidden email]>写道:
>
> Xavier Wang wrote:
> > Is that difficult to make unresolved function name become nil?
> > ffi.C.foobar --> nil
>
> That's not difficult. But there would be no way you could get the
> error message then (a table lookup can only return one result).
> And you'd have to litter your code with asserts. It makes more
> sense to error out here. For a C program you'll get an error when
> the static or dynamic linker fails to resolve a symbol, too.
>

I see, maybe providing another function to lookup symbols is better ?

ffi.lookup("C", "foobar") -- nil, "no such symbol"

> --Mike
>

Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

Thomas Lauer-3
In reply to this post by Mike Pall-29
Mike Pall <[hidden email]> wrote:

> Thomas Lauer wrote:
> > The following code, run under Windows, produces an error message for
> > line 4 which IMHO is misleading at best but more probably spurious?
> >
> > ffi=require('ffi')
> > ffi.cdef('void DebugBreak(void);')  -- Any function will do
> > if ffi.C.DebugBreak then print(ffi.C.DebugBreak) end  -- OK
> > if ffi.C.DebugBreak~=nil then print(ffi.C.DebugBreak) end
> >
> > luajit.exe: f:\testffi.lua:4: attempt to compare 'void ()' with 'void *'
>
> Well, the error message is correct. You're comparing a function
> with nil (which is treated like a pointer to void here).

Technically you're right. Any competent C programmer will have an idea
what this messages means and where it comes from. However, I assume that
the ffi functions will be used also by people who've not done a lot of C
programming.

> [But note that neither of two conditionals in your code can ever
> be true. Only nil and false are treated as not-true conditions.

I am not sure that I follow. Here, ffi.C.DebugBreak evaluates as true.

The actual code that triggered this mail is somewhat more involved than
the simplified example I gave.

--
cheers  thomasl

Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

Mike Pall-29
In reply to this post by Xavier Wang
Xavier Wang wrote:
> I see, maybe providing another function to lookup symbols is better ?
>
> ffi.lookup("C", "foobar") -- nil, "no such symbol"

Easy enough to add this yourself:

  local function plookup(ns, sym) return ns[sym] end
  function ffi.lookup(ns, sym) return pcall(plookup, ns, sym) end

print(ffi.lookup(ffi.C, "foobar"))

--Mike

Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

Xavier Wang


在 2011-7-23 晚上11:15,"Mike Pall" <[hidden email]>写道:
>
> Xavier Wang wrote:
> > I see, maybe providing another function to lookup symbols is better ?
> >
> > ffi.lookup("C", "foobar") -- nil, "no such symbol"
>
> Easy enough to add this yourself:
>
>  local function plookup(ns, sym) return ns[sym] end
>  function ffi.lookup(ns, sym) return pcall(plookup, ns, sym) end
>
> print(ffi.lookup(ffi.C, "foobar"))
>
> --Mike
>

That's easy, thank you Mike :-)

Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

Mike Pall-29
In reply to this post by Thomas Lauer-3
Thomas Lauer wrote:
> Mike Pall <[hidden email]> wrote:
> > [But note that neither of two conditionals in your code can ever
> > be true. Only nil and false are treated as not-true conditions.
>
> I am not sure that I follow. Here, ffi.C.DebugBreak evaluates as true.

s/be true/be false/

--Mike

Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

Thomas Lauer-3
In reply to this post by Mike Pall-29
Mike Pall <[hidden email]> wrote:

> Thomas Lauer wrote:
> > The following code, run under Windows, produces an error message for
> > line 4 which IMHO is misleading at best but more probably spurious?
> >
> > ffi=require('ffi')
> > ffi.cdef('void DebugBreak(void);')  -- Any function will do
> > if ffi.C.DebugBreak then print(ffi.C.DebugBreak) end  -- OK
> > if ffi.C.DebugBreak~=nil then print(ffi.C.DebugBreak) end
> >
> > luajit.exe: f:\testffi.lua:4: attempt to compare 'void ()' with 'void *'
>
> Well, the error message is correct. You're comparing a function
> with nil (which is treated like a pointer to void here).
>
> But it's debatable whether comparing a function with a pointer
> should be disallowed. In C, functions and function pointers are
> almost universally exchangeable, so I guess this should be
> allowed here. I've changed the semantics in git HEAD.

Sorry to be a PITA with this but I have to revisit this topic. I still
get very similar error messages which, after thinking a bit about
things, I am convinced shouldn't be there.

The underlying problem is this. Somewhere buried in a module I have a
small function called handler which checks whether the value of an
incoming parameter ~= nil. See this snippet:

> function handler(m,n,v)
> m=getModulename(m)
> if m=='_G' then m=' in main program'
> else m=' in module '..m end
> if v~=nil then error('invalid assignment to '..n..m,3) -- Zonk!
> else error(n..' not declared'..m,3) end
> end

This function has no idea what type or value the incoming parameter v
might have. In standard Lua this ain't a problem as I can compare all
values, including userdata, with nil. So a line like this:

z=<any lua value> will trigger a call to

> error('invalid assignment to '..n..m,3)

Not so with ffi values, though. If I write, for instance, this:

z=ffi.typeof(<some ct>) the "v ~= nil" test itself crashes out with

> luajit.exe: f:\testffi.lua:46: attempt to compare 'enum 21' with 'void *'

So far, I've always assumed that Lua allows to compare any value with
nil without the comparison itself triggering an error.

Maybe I am mistaken in this assumption. Or maybe Lua does that but the
LuaJIT ffi doesn't. At any rate, I think being able to compare any value
against nil without having the comparison itself trigger an error to be
an important feature.

--
cheers  thomasl



Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

Mike Pall-29
Thomas Lauer wrote:
> At any rate, I think being able to compare any value against nil
> without having the comparison itself trigger an error to be an
> important feature.

The FFI data types are strictly typed and behave accordingly. In
fact, it's just a convenience that you can compare them with other
Lua object types at all. Otherwise all such comparisons would
return false.

That however implies implicit conversions, e.g. '1LL == 1' is
really '1LL == ffi.cast("int64_t", 1)'. As with all implicit
conversions one has to be very careful and very conservative (or
you end up with something like PHP). That's why 'nil' is turned
into 'ffi.cast("void *", 0)' and only compares to pointer-like
objects and nothing else.

If you really, really need to find out whether something is a nil
object without ever raising errors, then use 'type(v) == "nil"'.

--Mike

Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

Thomas Lauer-3
Mike Pall <[hidden email]> wrote:

> Thomas Lauer wrote:
> > At any rate, I think being able to compare any value against nil
> > without having the comparison itself trigger an error to be an
> > important feature.
>
> The FFI data types are strictly typed and behave accordingly. In
> fact, it's just a convenience that you can compare them with other
> Lua object types at all. Otherwise all such comparisons would
> return false.
>
> That however implies implicit conversions, e.g. '1LL == 1' is
> really '1LL == ffi.cast("int64_t", 1)'. As with all implicit
> conversions one has to be very careful and very conservative (or
> you end up with something like PHP). That's why 'nil' is turned
> into 'ffi.cast("void *", 0)' and only compares to pointer-like
> objects and nothing else.

Well, I still think that allowing to compare any value (including ffi
values) against the special case of nil would be a sensible thing to do.

I imagine you won't go there so perhaps a hint in the ffi docs (if and
when you find the time) might be a good idea.

> If you really, really need to find out whether something is a nil
> object without ever raising errors, then use 'type(v) == "nil"'.

That's what I've done as a workaround.

--
cheers  thomasl


Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

Justin Cormack
On Sat, 2011-07-30 at 16:04 +0100, Thomas Lauer wrote:

> Well, I still think that allowing to compare any value (including ffi
> values) against the special case of nil would be a sensible thing to do.
>
> I imagine you won't go there so perhaps a hint in the ffi docs (if and
> when you find the time) might be a good idea.
>
> > If you really, really need to find out whether something is a nil
> > object without ever raising errors, then use 'type(v) == "nil"'.
>
> That's what I've done as a workaround.
>

Usually you can just test with 'if not v then ...' rather than if v ==
nil then ...', so actually comparing to nil is rarely needed, unless
false is a sane value...

Justin



Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

Duncan Cross
On Sun, Jul 31, 2011 at 4:55 PM, Justin Cormack
<[hidden email]> wrote:

> On Sat, 2011-07-30 at 16:04 +0100, Thomas Lauer wrote:
>> Well, I still think that allowing to compare any value (including ffi
>> values) against the special case of nil would be a sensible thing to do.
>>
>> I imagine you won't go there so perhaps a hint in the ffi docs (if and
>> when you find the time) might be a good idea.
>>
>> > If you really, really need to find out whether something is a nil
>> > object without ever raising errors, then use 'type(v) == "nil"'.
>>
>> That's what I've done as a workaround.
>>
>
> Usually you can just test with 'if not v then ...' rather than if v ==
> nil then ...', so actually comparing to nil is rarely needed, unless
> false is a sane value...

Ah, but with LuaJIT FFI, null pointer values are considered equal to
nil, but are *not* logically false:

 > ffi = require 'ffi'
 > null = ffi.new('void*')
 > print(null == nil)
 true
 > print(not null)
 false

-Duncan

Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

Dirk Laurie
On Sun, Jul 31, 2011 at 06:43:23PM +0200, Duncan Cross wrote:

>
> Ah, but with LuaJIT FFI, null pointer values are considered equal to
> nil, but are *not* logically false:
>
>  > ffi = require 'ffi'
>  > null = ffi.new('void*')
>  > print(null == nil)
>  true
>  > print(not null)
>  false
>

All LuaJIT versions with FFI are still beta only, and the equality
of a null cdata with a Lua nil is therefore not yet cast in concrete
for all eternity.  May I respectfully suggest that this issue be
be high up on the list of things that should change.   Instead,
`ffi.null` as a predefined constant, different from `nil`, could be
a useful addition.

Dirk

Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

Mike Pall-29
Dirk Laurie wrote:
> All LuaJIT versions with FFI are still beta only, and the equality
> of a null cdata with a Lua nil is therefore not yet cast in concrete
> for all eternity.  May I respectfully suggest that this issue be
> be high up on the list of things that should change.

No way.

--Mike

Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

Henk Boom-2
In reply to this post by Mike Pall-29
On 30 July 2011 10:22, Mike Pall <[hidden email]> wrote:
> The FFI data types are strictly typed and behave accordingly. In
> fact, it's just a convenience that you can compare them with other
> Lua object types at all. Otherwise all such comparisons would
> return false.

This would match with the lua reference, which says

"Equality (==) first compares the type of its operands. If the types
are different, then the result is false."

Implicit coercions are definitely a convenience, but it means paying
the cost that use of the comparison operator can suddenly trigger
errors instead of returning false.

    henk

Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

James McKaskill-2
On Jul 31, 2011, at 13:58 , Henk Boom wrote:

> On 30 July 2011 10:22, Mike Pall <[hidden email]> wrote:
>> The FFI data types are strictly typed and behave accordingly. In
>> fact, it's just a convenience that you can compare them with other
>> Lua object types at all. Otherwise all such comparisons would
>> return false.
>
> This would match with the lua reference, which says
>
> "Equality (==) first compares the type of its operands. If the types
> are different, then the result is false."

This is why I ended up adding ffi.C.NULL for luaffi with the standard vm.

-- James


Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

Thomas Lauer-3
In reply to this post by Justin Cormack
Justin Cormack <[hidden email]> wrote:

> On Sat, 2011-07-30 at 16:04 +0100, Thomas Lauer wrote:
> > Well, I still think that allowing to compare any value (including ffi
> > values) against the special case of nil would be a sensible thing to do.
> >
> > I imagine you won't go there so perhaps a hint in the ffi docs (if and
> > when you find the time) might be a good idea.
> >
> > > If you really, really need to find out whether something is a nil
> > > object without ever raising errors, then use 'type(v) == "nil"'.
> >
> > That's what I've done as a workaround.
> >
>
> Usually you can just test with 'if not v then ...' rather than if v ==
> nil then ...', so actually comparing to nil is rarely needed, unless
> false is a sane value...

Sure, that's what I'd usually do... but in this specific case false is a
rare but quite feasible value for v. In fact, v could have *any*
possible type and value and I have no control over what this might be.

Anyway, I first did

> if type(v)~=='nil' then ...

but now I'm doing

> if v or v==false then ...

as this should generally be slightly faster.

--
cheers  thomasl

Reply | Threaded
Open this post in threaded view
|

Re: [LuaJIT ffi] Misleading error message?

Thomas Lauer-3
Thomas Lauer <[hidden email]> wrote:

> Anyway, I first did
>
> > if type(v)~=='nil' then ...
               ^
Err.. make that "type(v)~='nil'".

--
cheers  thomasl