OmniSciDB  a5dc49c757
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GeosValidation.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2023 HEAVY.AI, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 
19 #if defined(ENABLE_GEOS) && !defined(_WIN32)
20 
21 #include <dlfcn.h>
22 #include <geos_c.h>
23 #include <mutex>
24 
25 #include "Logger/Logger.h"
26 
27 #ifndef GEOS_LIBRARY_FILENAME
28 #error Configuration should include GEOS library file name
29 #endif
30 
31 // this is externed in DBHandler.cpp and NativeCodegen.cpp
32 std::unique_ptr<std::string> g_libgeos_so_filename(
33  new std::string(GEOS_LIBRARY_FILENAME));
34 
35 namespace Geospatial {
36 
37 using PFN_GEOS_init_r = GEOSContextHandle_t (*)();
38 using PFN_GEOS_finish_r = void (*)(GEOSContextHandle_t);
39 using PFN_GEOSisValidDetail_r =
40  char (*)(GEOSContextHandle_t, const GEOSGeometry*, int, char**, GEOSGeometry**);
41 using PFN_GEOSGeomFromWKB_buf_r = GEOSGeometry* (*)(GEOSContextHandle_t,
42  const unsigned char*,
43  size_t);
44 using PFN_GEOSGeom_destroy_r = void (*)(GEOSContextHandle_t, GEOSGeometry*);
45 using PFN_GEOSFree_r = void (*)(GEOSContextHandle_t, void*);
46 
47 static bool geos_can_validate = true;
48 static void* geos_dso_handle = nullptr;
49 
50 static std::mutex geos_dso_mutex;
51 
52 static PFN_GEOS_init_r pfn_GEOS_init_r = nullptr;
53 static PFN_GEOS_finish_r pfn_GEOS_finish_r = nullptr;
54 static PFN_GEOSisValidDetail_r pfn_GEOSisValidDetail_r = nullptr;
55 static PFN_GEOSGeomFromWKB_buf_r pfn_GEOSGeomFromWKB_buf_r = nullptr;
56 static PFN_GEOSGeom_destroy_r pfn_GEOSGeom_destroy_r = nullptr;
57 static PFN_GEOSFree_r pfn_GEOSFree_r = nullptr;
58 
59 bool geos_init() {
60  // take lock
61  std::lock_guard<std::mutex> guard(geos_dso_mutex);
62 
63  // already failed
64  if (!geos_can_validate) {
65  return false;
66  }
67 
68  // already initialized
69  if (geos_dso_handle) {
70  return true;
71  }
72 
73  // validate filename
74  if (!g_libgeos_so_filename) {
75  LOG(WARNING)
76  << "GEOS dynamic library filename unspecified. Geometry validation unavailable.";
77  geos_can_validate = false;
78  return false;
79  }
80 
81  // attempt to load DSO
82  auto const* geos_dso_filename = g_libgeos_so_filename->c_str();
83  geos_dso_handle = dlopen(geos_dso_filename, RTLD_NOW | RTLD_LOCAL);
84  if (!geos_dso_handle) {
85  LOG(WARNING) << "Failed to dynamically load GEOS. Geometry validation unavailable.";
86  geos_can_validate = false;
87  return false;
88  }
89 
90  // fetch all required function pointers
91  pfn_GEOS_init_r = (PFN_GEOS_init_r)dlsym(geos_dso_handle, "GEOS_init_r");
92  pfn_GEOS_finish_r = (PFN_GEOS_finish_r)dlsym(geos_dso_handle, "GEOS_finish_r");
93  pfn_GEOSisValidDetail_r =
94  (PFN_GEOSisValidDetail_r)dlsym(geos_dso_handle, "GEOSisValidDetail_r");
95  pfn_GEOSGeomFromWKB_buf_r =
96  (PFN_GEOSGeomFromWKB_buf_r)dlsym(geos_dso_handle, "GEOSGeomFromWKB_buf_r");
97  pfn_GEOSGeom_destroy_r =
98  (PFN_GEOSGeom_destroy_r)dlsym(geos_dso_handle, "GEOSGeom_destroy_r");
99  pfn_GEOSFree_r = (PFN_GEOSFree_r)dlsym(geos_dso_handle, "GEOSFree_r");
100 
101  if (!pfn_GEOS_init_r || !pfn_GEOS_finish_r || !pfn_GEOSisValidDetail_r ||
102  !pfn_GEOSGeomFromWKB_buf_r || !pfn_GEOSGeom_destroy_r || !pfn_GEOSFree_r) {
103  LOG(WARNING) << "Failed to dynamically load required GEOS function pointers. Check "
104  "GEOS DSO version. Geometry validation unavailable.";
105  geos_can_validate = false;
106  return false;
107  }
108 
109  // done
110  return true;
111 }
112 
114  return geos_init();
115 }
116 
117 bool geos_validate_wkb(const unsigned char* wkb, const size_t wkb_size) {
118  // available?
119  if (!geos_init()) {
120  return true;
121  }
122  // validate
123  auto* context = pfn_GEOS_init_r();
124  CHECK(context);
125  auto* geom = pfn_GEOSGeomFromWKB_buf_r(context, wkb, wkb_size);
126  bool result = false;
127  if (geom) {
128  char* reason{};
129  GEOSGeometry* location{};
130  const int flags = 0;
131  result = pfn_GEOSisValidDetail_r(context, geom, flags, &reason, &location) != 0;
132  if (!result) {
133  LOG(WARNING) << "GEOS invalid reason: " << reason;
134  }
135  pfn_GEOSFree_r(context, reason);
136  pfn_GEOSGeom_destroy_r(context, location);
137  pfn_GEOSGeom_destroy_r(context, geom);
138  }
139  pfn_GEOS_finish_r(context);
140  return result;
141 }
142 
143 } // namespace Geospatial
144 
145 #else
146 
147 namespace Geospatial {
148 
150  return false;
151 }
152 
153 bool geos_validate_wkb(const unsigned char* /* wkb */, const size_t /* wkb_size */) {
154  return true;
155 }
156 
157 } // namespace Geospatial
158 
159 #endif
#define LOG(tag)
Definition: Logger.h:285
bool geos_validate_wkb(const unsigned char *, const size_t)
bool geos_validation_available()
#define CHECK(condition)
Definition: Logger.h:291