<p dir="ltr"><br>
On Oct 19, 2014 12:03 AM, "Pekka Paalanen" <<a href="mailto:ppaalanen@gmail.com">ppaalanen@gmail.com</a>> wrote:<br>
><br>
> On Sat, 18 Oct 2014 11:19:55 -0700<br>
> Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>> wrote:<br>
><br>
> > On Thu, Oct 16, 2014 at 11:16 PM, Pekka Paalanen <<a href="mailto:ppaalanen@gmail.com">ppaalanen@gmail.com</a>><br>
> > wrote:<br>
> ><br>
> > > On Thu, 16 Oct 2014 10:40:20 +0300<br>
> > > Pekka Paalanen <<a href="mailto:ppaalanen@gmail.com">ppaalanen@gmail.com</a>> wrote:<br>
> > ><br>
> > > > On Thu, 16 Oct 2014 09:46:39 +0300<br>
> > > > Pekka Paalanen <<a href="mailto:ppaalanen@gmail.com">ppaalanen@gmail.com</a>> wrote:<br>
> > > ><br>
> > > > > On Wed, 15 Oct 2014 22:44:25 +0400<br>
> > > > > Dmitry Cherkassov <<a href="mailto:dcherkassov@gmail.com">dcherkassov@gmail.com</a>> wrote:<br>
> > > > ><br>
> > > > > > Hi list!<br>
> > > > > ><br>
> > > > > > The definition of wl_display_interface symbol can come from<br>
> > > > > > libwayland-server.so or libwayland-client.so.<br>
> > > > > ><br>
> > > > > > There is a code in closed source EGL implementation that does<br>
> > > > > > interfaces comparison via pointers, yielding negative results when<br>
> > > > > > addresses are different (one address is saved by QtWayland, the other<br>
> > > > > > one is from &wl_display_interface in EGL source code).<br>
> > > > > ><br>
> > > > > > Is there a smarter way to compare wl_display_interface's?<br>
> > > > > ><br>
> > > > > > There is this function:<br>
> > > > > ><br>
> > > > > > wl_interface_equal(const struct wl_interface *a, const struct<br>
> > > wl_interface *b)<br>
> > > > > > {<br>
> > > > > >     return a == b || strcmp(a->name, b->name) == 0;<br>
> > > > > > }<br>
> > > > > ><br>
> > > > > > But as you can see it's not safe to use it alone because in case of<br>
> > > > > > bad pointer we will get undefined results.<br>
> > > > > ><br>
> > > > > > Currently struct wl_interface is the following:<br>
> > > > > >  struct wl_interface {<br>
> > > > > >      const char *name;<br>
> > > > > >      int version;<br>
> > > > > >      int method_count;<br>
> > > > > >      const struct wl_message *methods;<br>
> > > > > >      int event_count;<br>
> > > > > >      const struct wl_message *events;<br>
> > > > > >  };<br>
> > > > > ><br>
> > > > > > Since there is no magic field at the beginning it is not possible to<br>
> > > > > > see whether a pointer points to the valid wl_interface structure.<br>
> > > > > ><br>
> > > > > > So my question is: how can we compare wl_interfaces in more clever<br>
> > > and<br>
> > > > > > safer way?<br>
> > > > ><br>
> > > > > Hmm, why would you ever have a bad pointer?<br>
> > > > ><br>
> > > > > Bad pointers in general tend to cause crashes and stuff, so you<br>
> > > > > shouldn't be having a bad one in the first place.<br>
> > > > ><br>
> > > > > What is the background for your question/problem?<br>
> > > ><br>
> > > > Ok, I suppose this was discussed in IRC last night: the actual problem<br>
> > > > behind the question is how to detect whether the void pointer<br>
> > > > (EGLNativeDisplayType) given to eglCreateDisplay is actually a<br>
> > > > wl_display.<br>
> > > ><br>
> > > > That's tough.<br>
> > > ><br>
> > > > A couple of hacks come to mind.<br>
> > > ><br>
> > > > bool<br>
> > > > _eglNativePlatformDetectWayland(void *nativeDisplay)<br>
> > > > {<br>
> > > >       void *f;<br>
> > > ><br>
> > > >       if (!dereferencable(nativeDisplay))<br>
> > > >               return false;<br>
> > > ><br>
> > > >       f = *(void **)nativeDisplay;<br>
> > > ><br>
> > > > The first is to dlopen both libwayland-client and libwayland-server in<br>
> > > > turn with RTLD_NOLOAD | RTLD_LOCAL, and fetching the<br>
> > > > wl_display_interface symbol from each, comparing those to 'f'. If<br>
> > > > either matches, return true.<br>
> > ><br>
> > > While discussing in IRC, I realized half of this is nonsense.<br>
> > ><br>
> > > eglGetDisplay() can only get a wl_display created by libwayland-client,<br>
> > > and never one created by libwayland-server. Assuming the dynamic<br>
> > > linking is sane, the interface pointer in wl_display is *always* the<br>
> > > one from libwayland-client.so.<br>
> > ><br>
> > > Now we just need to make sure, that we compare 'f' to the interface<br>
> > > pointer from libwayland-client.so. That could probably be done with the<br>
> > > dlopen/dlsym trick, or...<br>
> > ><br>
> > > > Another would be to check if 'f' is dereferencable (and not equal to<br>
> > > > the default wl_display_interface), and check if (char *)f starts with<br>
> > > > "wl_d". If yes, do a full string comparison with "wl_display". It's<br>
> > > > not reliable, but maybe works enough.<br>
> > > ><br>
> > > > The proper solution is for apps to use EGL_KHR_platform_wayland to<br>
> > > > explicitly say the pointer is a wl_display. That of course doesn't work<br>
> > > > on old apps, so you might implement a workaround through environment<br>
> > > > like Mesa does: EGL_PLATFORM=wayland bypasses all autodetection and<br>
> > > > assumes it is a wl_display.<br>
> > > ><br>
> > > > In any case, EGL really should implement EGL_KHR_platform_wayland so we<br>
> > > > have a chance to get rid of the inherently unreliable autodetect. And we<br>
> > > > should start using that in our demo apps...<br>
> > > ><br>
> > > > If we consider autodetecting client wl_display pointers worth to solve<br>
> > > > properly, we should probably add a function for that in<br>
> > > > libwayland-client.so. However, implementing that portably might be<br>
> > > > difficult.<br>
> > ><br>
> > > ...adding a function int/bool wl_is_wl_display_pointer(void *p) into<br>
> > > libwayland-client.so. As that function would be built into<br>
> > > libwayland-client.so, it naturally uses the client.so version of<br>
> > > wl_display_interface symbol (unless dynamic linking miraculously<br>
> > > manages to mess that up?).<br>
> > ><br>
> > > 'p' would be the tentative 'struct wl_display *', so that the<br>
> > > implementation details of struct wl_display would be contained in<br>
> > > libwayland-client.so, and not leaked elsewhere like e.g. in Mesa.<br>
> > ><br>
> > > All this means we should be able to get away with just one pointer<br>
> > > comparison, after assuring that the first sizeof(void*) bytes pointed<br>
> > > to by the given unknown pointer (EGLNativeDisplayType) are<br>
> > > dereferencable without a segfault or other fatal error.<br>
> > ><br>
> > > So, a quick fix for EGL implementations right now would be to try the<br>
> > > dlopen hack, until they can start to depend on a new<br>
> > > libwayland-client.so providing wl_is_wl_display_pointer().<br>
> > ><br>
> > > I am unsure about the exact definition of wl_is_wl_display_pointer():<br>
> > > can it do the dereferencability check itself, or should we require the<br>
> > > caller to guarantee that dereferencing cannot crash. The latter would<br>
> > > leave the portability burden on the callers rather than libwayland.<br>
> > ><br>
> > > How's that sound?<br>
> > ><br>
> ><br>
> > That sounds fine.  I think we can count on the client passing in a valid<br>
> > pointer to something.  Chances are that whatever the client passes in will<br>
> > be a pointer to some sort of structure and so we can probably read 8 bytes<br>
> > without a problem.  If we really wanted to, we could do a quick alignment<br>
> > check to ensure that it's sizeof(void *)-aligned.<br>
><br>
> There are perfectly valid cases, where the value passed in to<br>
> eglGetDisplay is non-zero and not a valid pointer, see below.<br>
><br>
> The exact question is, do we expect the caller have already<br>
> done the referenceability test, or do we promise to do that<br>
> ourselves inside is_wl_display function?<br>
><br>
> For the reference, this is the check in Mesa:<br>
> /**<br>
>  * Perform validity checks on a generic pointer.<br>
>  */<br>
> static EGLBoolean<br>
> _eglPointerIsDereferencable(void *p)<br>
> {<br>
> #ifdef HAVE_MINCORE<br>
>    uintptr_t addr = (uintptr_t) p;<br>
>    unsigned char valid = 0;<br>
>    const long page_size = getpagesize();<br>
><br>
>    if (p == NULL)<br>
>       return EGL_FALSE;<br>
><br>
>    /* align addr to page_size */<br>
>    addr &= ~(page_size - 1);<br>
><br>
>    if (mincore((void *) addr, page_size, &valid) < 0) {<br>
>       _eglLog(_EGL_DEBUG, "mincore failed: %m");<br>
>       return EGL_FALSE;<br>
>    }<br>
><br>
>    return (valid & 0x01) == 0x01;<br>
> #else<br>
>    return p != NULL;<br>
> #endif<br>
> }<br>
><br>
> From<br>
> <a href="http://cgit.freedesktop.org/mesa/mesa/tree/src/egl/main/egldisplay.c?id=1fc124b80f228319ded06f80a51681c75dc0a4f3#n110">http://cgit.freedesktop.org/mesa/mesa/tree/src/egl/main/egldisplay.c?id=1fc124b80f228319ded06f80a51681c75dc0a4f3#n110</a><br>
><br>
> Bill seemed to think, that the only non-pointer value we need check<br>
> against is zero (NULL), but that is not the case.<br>
><br>
> The value passed as and cast into EGLNativeDisplayType could also<br>
> be an arbitrary integer (raspberry pi proprietary EGL), file<br>
> descriptor (Mesa DRM platform), or anything really. It's up to the<br>
> EGL platform to define what it is, and the EGL platform is what we<br>
> are desperately trying to autodetect when the application is not<br>
> using EGL_EXT_platform_base -based platform indication.<br>
><br>
> > I don't know that I care whether we do your wl_is_wl_display_pointer or<br>
> > Bill's "dynamic cast" version.  It doesn't much matter.<br>
><br>
> Yeah, doesn't matter, can do it either way, this is a special case<br>
> that will not happen again, is a fallback path, will only ever<br>
> be used inside libEGL implementations, etc.<br>
><br>
> > > Is it possible to have several instances of libwayland-client in a<br>
> > > process address space? Meaning we would have several different<br>
> > > client-side wl_display_interface pointers?<br>
> > ><br>
> ><br>
> > I don't think so.  At least not without some very bizarre hackery.  Also, I<br>
> > think it's reasonable to assume that either a) libEGL is reasonably<br>
> > normally linked against the same chunks of code that link to<br>
> > libwayland-client or b) The client really knows what they're doing and is<br>
> > prepared for the consequences.  Because really, if they're pulling those<br>
> > kinds of tricks they're asking for trouble.<br>
><br>
> I hope so too.<br>
><br>
> > > If yes, it's back to the string comparisons...<br>
> > ><br>
> ><br>
> > String comparisons are right out.  They'll cause a segfault the moment it's<br>
> > not a wl_display pointer.<br>
><br>
> No, it could work. For the EGLNativeDisplayType cast to void*:<br>
><br>
> 1. check it is not NULL<br>
> 2. check it is dereferencable for at least sizeof(void*) bytes<br>
> 3. extract a void *f from the memory pointed to by it<br>
> 4. check 'f' is dereferencable for N=sizeof("wl_display") bytes<br>
> 5. check the first N bytes at address 'f' against "wl_display"<br>
><br>
> Steps 1-3 have to be done in any case. Steps 4-5 are the string<br>
> comparison case. As we already checked that the bytes can be read,<br>
> the string comparison should be safe.<br>
><br>
> But yes, I'd rather not do that.<br>
><br>
> Still, something has to do the first dereferecability test in step<br>
> 2, and it is not really portable I believe, so the question is who<br>
> do we require to do that?<br>
><br>
> I think I'd be tempted to say that its the libEGL, since it's<br>
> probably fairly OS dependent anyway. That only works when we<br>
> don't need a dereferencability test for 'f', so no problem. That<br>
> would make is_wl_display(arg) to be as simple as<br>
>         return *(void**)arg == &wl_display_interface;</p>
<p dir="ltr">Fine with me.<br>
--Jason</p>
<p dir="ltr">><br>
> Thanks,<br>
> pq<br>
</p>