From 59f27010122064a8ea75dca0025df4e134673b61 Mon Sep 17 00:00:00 2001
From: Imanol Fernandez <mortimergoro@gmail.com>
Date: Thu, 30 Mar 2017 19:22:26 +0200
Subject: [PATCH 1/2] Fix eglGetProcAddress for core OpenGL entrypoints

---
 Cargo.toml                                 | 11 ++++++---
 src/lib.rs                                 |  4 +++-
 src/platform/with_egl/native_gl_context.rs | 26 ++++++++++++++++++++--
 3 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 1d92f4f0..48a82c26 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "offscreen_gl_context"
 license = "MIT / Apache-2.0"
-version = "0.8.4"
+version = "0.8.5"
 authors = ["Emilio Cobos Álvarez <emilio@crisal.io>", "The Servo Project Developers"]
 description = "Creation and manipulation of HW accelerated offscreen rendering contexts in multiple platforms. Originally intended for the Servo project's WebGL implementation."
 repository = "https://github.com/emilio/rust-offscreen-rendering-context"
@@ -14,7 +14,7 @@ gl_generator = "0.5"
 default = ["x11"]
 osmesa = ["osmesa-sys"]
 # NOTE: Just for testing use, there are no other changes
-test_egl_in_linux = []
+test_egl_in_linux = ["libloading", "lazy_static"]
 
 [dependencies]
 log  = "0.3"
@@ -22,6 +22,8 @@ gleam = "0.4"
 euclid = "0.11"
 serde = { version = "0.9", optional = true }
 osmesa-sys = { version = "0.1", optional = true }
+libloading = { version = "0.3", optional = true }
+lazy_static = { version = "0.2", optional = true }
 
 [target.x86_64-apple-darwin.dependencies]
 core-foundation = "0.3.0"
@@ -38,5 +40,8 @@ gdi32-sys = "0.2"
 user32-sys = "0.2"
 kernel32-sys = "0.2"
 
-[target.'cfg(any(target_os="macos", target_os="windows"))'.dependencies]
+[target.'cfg(any(target_os="macos", target_os="windows", target_os="android"))'.dependencies]
 lazy_static = "0.2"
+
+[target.'cfg(target_os = "android")'.dependencies]
+libloading = "0.3"
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index 3ec44227..b368cafa 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -23,9 +23,11 @@ extern crate kernel32;
 extern crate gdi32;
 #[cfg(target_os = "windows")]
 extern crate user32;
-#[cfg(any(target_os="macos", target_os="windows"))]
+#[cfg(any(target_os="macos", target_os="windows", target_os="android", feature="test_egl_in_linux"))]
 #[macro_use]
 extern crate lazy_static;
+#[cfg(any(target_os="android", feature="test_egl_in_linux"))]
+extern crate libloading;
 
 mod platform;
 pub use platform::{NativeGLContext, NativeGLContextMethods, NativeGLContextHandle};
diff --git a/src/platform/with_egl/native_gl_context.rs b/src/platform/with_egl/native_gl_context.rs
index 698ed5c9..9e85fdea 100644
--- a/src/platform/with_egl/native_gl_context.rs
+++ b/src/platform/with_egl/native_gl_context.rs
@@ -2,9 +2,20 @@ use euclid::Size2D;
 use platform::NativeGLContextMethods;
 use platform::with_egl::utils::{create_pixel_buffer_backed_offscreen_context};
 use std::ffi::CString;
+use std::ops::Deref;
 use egl;
 use egl::types::{EGLint, EGLBoolean, EGLDisplay, EGLSurface, EGLConfig, EGLContext};
+use libloading as lib;
 
+lazy_static! {
+    static ref GL_LIB: Option<lib::Library>  = {
+        if cfg!(target_os = "android") {
+            lib::Library::new("libGLESv2.so").ok()
+        } else {
+            lib::Library::new("libGL.so").ok()
+        }
+    };
+}
 pub struct NativeGLContextHandle(pub EGLDisplay, pub EGLSurface);
 unsafe impl Send for NativeGLContextHandle {}
 
@@ -69,10 +80,21 @@ impl Drop for NativeGLContext {
 impl NativeGLContextMethods for NativeGLContext {
     type Handle = NativeGLContextHandle;
 
+    // According to the EGL spec <= 1.4, eglGetProcAddress should only be used to
+    // retrieve extension functions. Some implementatios return NULL for core OpenGL functions.
+    // Other implementations may return non-NULL values even for invalid core or extension symbols.
+    // This is very dangerous, so we use dlsym function before calling eglGetProcAddress
+    // in order to avoid possible garbage pointers.
     fn get_proc_address(addr: &str) -> *const () {
         unsafe {
-            let addr = CString::new(addr.as_bytes()).unwrap().as_ptr();
-            egl::GetProcAddress(addr as *const _) as *const ()
+            if let Some(ref lib) = *GL_LIB {
+                let symbol: lib::Symbol<unsafe extern fn()> = lib.get(addr.as_bytes()).unwrap();
+                return *symbol.deref() as *const();
+            }
+
+            let addr = CString::new(addr.as_bytes());
+            let addr = addr.unwrap().as_ptr();
+            egl::GetProcAddress(addr) as *const ()
         }
     }
 

From a48fcdce5a8c4eb005a6260254f620c1f5646a60 Mon Sep 17 00:00:00 2001
From: Imanol Fernandez <mortimergoro@gmail.com>
Date: Fri, 31 Mar 2017 17:10:07 +0200
Subject: [PATCH 2/2] Avoid dlsym unwrap. Add more possible library names.

---
 src/platform/with_egl/native_gl_context.rs | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/src/platform/with_egl/native_gl_context.rs b/src/platform/with_egl/native_gl_context.rs
index 9e85fdea..26d17fc4 100644
--- a/src/platform/with_egl/native_gl_context.rs
+++ b/src/platform/with_egl/native_gl_context.rs
@@ -9,11 +9,14 @@ use libloading as lib;
 
 lazy_static! {
     static ref GL_LIB: Option<lib::Library>  = {
-        if cfg!(target_os = "android") {
-            lib::Library::new("libGLESv2.so").ok()
-        } else {
-            lib::Library::new("libGL.so").ok()
-        }
+       let names = ["libGLESv2.so", "libGL.so", "libGLESv3.so"];
+       for name in &names {
+           if let Ok(lib) = Library::new(name) 
+               return Some(lib)
+           }
+       }
+
+       None
     };
 }
 pub struct NativeGLContextHandle(pub EGLDisplay, pub EGLSurface);
@@ -88,8 +91,10 @@ impl NativeGLContextMethods for NativeGLContext {
     fn get_proc_address(addr: &str) -> *const () {
         unsafe {
             if let Some(ref lib) = *GL_LIB {
-                let symbol: lib::Symbol<unsafe extern fn()> = lib.get(addr.as_bytes()).unwrap();
-                return *symbol.deref() as *const();
+                let symbol: Result<lib::Symbol<unsafe extern fn()>, _> = lib.get(addr.as_bytes());
+                if let Ok(symbol) = symbol {
+                    return *symbol.deref() as *const ();
+                }
             }
 
             let addr = CString::new(addr.as_bytes());