ruby-oci8 2.2.3 → 2.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -43,14 +43,24 @@
43
43
  #define PLTHOOK_INVALID_ARGUMENT 4
44
44
  #define PLTHOOK_OUT_OF_MEMORY 5
45
45
  #define PLTHOOK_INTERNAL_ERROR 6
46
+ #define PLTHOOK_NOT_IMPLEMENTED 7
46
47
 
47
48
  typedef struct plthook plthook_t;
48
49
 
50
+ #ifdef __cplusplus
51
+ extern "C" {
52
+ #endif
53
+
49
54
  int plthook_open(plthook_t **plthook_out, const char *filename);
55
+ int plthook_open_by_handle(plthook_t **plthook_out, void *handle);
50
56
  int plthook_open_by_address(plthook_t **plthook_out, void *address);
51
57
  int plthook_enum(plthook_t *plthook, unsigned int *pos, const char **name_out, void ***addr_out);
52
58
  int plthook_replace(plthook_t *plthook, const char *funcname, void *funcaddr, void **oldfunc);
53
59
  void plthook_close(plthook_t *plthook);
54
60
  const char *plthook_error(void);
55
61
 
62
+ #ifdef __cplusplus
63
+ }; /* extern "C" */
64
+ #endif
65
+
56
66
  #endif
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * ------------------------------------------------------
8
8
  *
9
- * Copyright 2013-2014 Kubo Takehiro <kubo@jiubao.org>
9
+ * Copyright 2013-2016 Kubo Takehiro <kubo@jiubao.org>
10
10
  *
11
11
  * Redistribution and use in source and binary forms, with or without modification, are
12
12
  * permitted provided that the following conditions are met:
@@ -33,6 +33,9 @@
33
33
  * or implied, of the authors.
34
34
  *
35
35
  */
36
+ #if defined(__sun) && defined(_XOPEN_SOURCE) && !defined(__EXTENSIONS__)
37
+ #define __EXTENSIONS__
38
+ #endif
36
39
  #define _GNU_SOURCE
37
40
  #include <stdio.h>
38
41
  #include <stdarg.h>
@@ -42,6 +45,7 @@
42
45
  #include <limits.h>
43
46
  #include <sys/types.h>
44
47
  #include <sys/stat.h>
48
+ #include <sys/mman.h>
45
49
  #include <fcntl.h>
46
50
  #include <errno.h>
47
51
  #include <dlfcn.h>
@@ -59,6 +63,7 @@
59
63
 
60
64
  #if defined __linux__
61
65
  #define ELF_OSABI ELFOSABI_SYSV
66
+ #define ELF_OSABI_ALT ELFOSABI_LINUX
62
67
  #elif defined __sun
63
68
  #define ELF_OSABI ELFOSABI_SOLARIS
64
69
  #elif defined __FreeBSD__
@@ -146,10 +151,18 @@ struct plthook {
146
151
  size_t dynstr_size;
147
152
  const Elf_Plt_Rel *plt;
148
153
  size_t plt_cnt;
154
+ #ifdef PT_GNU_RELRO
155
+ const char *relro_start;
156
+ const char *relro_end;
157
+ #endif
149
158
  };
150
159
 
151
160
  static char errmsg[512];
152
161
 
162
+ #ifdef PT_GNU_RELRO
163
+ static size_t page_size;
164
+ #endif
165
+
153
166
  static int plthook_open_executable(plthook_t **plthook_out);
154
167
  static int plthook_open_shared_library(plthook_t **plthook_out, const char *filename);
155
168
  static int plthook_open_real(plthook_t **plthook_out, const char *base, const char *filename);
@@ -167,6 +180,24 @@ int plthook_open(plthook_t **plthook_out, const char *filename)
167
180
  }
168
181
  }
169
182
 
183
+ int plthook_open_by_handle(plthook_t **plthook_out, void *hndl)
184
+ {
185
+ struct link_map *lmap = NULL;
186
+
187
+ if (hndl == NULL) {
188
+ set_errmsg("NULL handle");
189
+ return PLTHOOK_FILE_NOT_FOUND;
190
+ }
191
+ if (dlinfo(hndl, RTLD_DI_LINKMAP, &lmap) != 0) {
192
+ set_errmsg("dlinfo error");
193
+ return PLTHOOK_FILE_NOT_FOUND;
194
+ }
195
+ if (lmap->l_addr == 0 && *lmap->l_name == 0) {
196
+ return plthook_open_executable(plthook_out);
197
+ }
198
+ return plthook_open_real(plthook_out, (const char*)lmap->l_addr, lmap->l_name);
199
+ }
200
+
170
201
  int plthook_open_by_address(plthook_t **plthook_out, void *address)
171
202
  {
172
203
  Dl_info info;
@@ -229,7 +260,8 @@ static int plthook_open_executable(plthook_t **plthook_out)
229
260
  #elif defined __FreeBSD__
230
261
  return plthook_open_shared_library(plthook_out, NULL);
231
262
  #else
232
- #error unsupported OS
263
+ set_errmsg("Opening the main program is not supported on this platform.");
264
+ return PLTHOOK_NOT_IMPLEMENTED;
233
265
  #endif
234
266
  }
235
267
 
@@ -260,6 +292,9 @@ static int plthook_open_real(plthook_t **plthook_out, const char *base, const ch
260
292
  off_t offset;
261
293
  plthook_t *plthook;
262
294
  int rv;
295
+ #ifdef PT_GNU_RELRO
296
+ size_t idx;
297
+ #endif
263
298
 
264
299
  if (base == NULL) {
265
300
  set_errmsg("The base address is zero.");
@@ -330,6 +365,29 @@ static int plthook_open_real(plthook_t **plthook_out, const char *base, const ch
330
365
  rv = PLTHOOK_INVALID_FILE_FORMAT;
331
366
  goto error_exit;
332
367
  }
368
+ #ifdef PT_GNU_RELRO
369
+ if (page_size == 0) {
370
+ page_size = sysconf(_SC_PAGESIZE);
371
+ }
372
+ offset = ehdr->e_phoff;
373
+ if ((rv = lseek(fd, offset, SEEK_SET)) != offset) {
374
+ set_errmsg("failed to seek to the program header table.");
375
+ rv = PLTHOOK_INVALID_FILE_FORMAT;
376
+ goto error_exit;
377
+ }
378
+ for (idx = 0; idx < ehdr->e_phnum; idx++) {
379
+ Elf_Phdr phdr;
380
+ if (read(fd, &phdr, sizeof(phdr)) != sizeof(phdr)) {
381
+ set_errmsg("failed to read the program header table.");
382
+ rv = PLTHOOK_INVALID_FILE_FORMAT;
383
+ goto error_exit;
384
+ }
385
+ if (phdr.p_type == PT_GNU_RELRO) {
386
+ plthook->relro_start = plthook->base + phdr.p_vaddr;
387
+ plthook->relro_end = plthook->relro_start + phdr.p_memsz;
388
+ }
389
+ }
390
+ #endif
333
391
  close(fd);
334
392
  fd = -1;
335
393
 
@@ -428,10 +486,26 @@ int plthook_replace(plthook_t *plthook, const char *funcname, void *funcaddr, vo
428
486
  while ((rv = plthook_enum(plthook, &pos, &name, &addr)) == 0) {
429
487
  if (strncmp(name, funcname, funcnamelen) == 0) {
430
488
  if (name[funcnamelen] == '\0' || name[funcnamelen] == '@') {
489
+ #ifdef PT_GNU_RELRO
490
+ void *maddr = NULL;
491
+ if (plthook->relro_start <= (char*)addr && (char*)addr < plthook->relro_end) {
492
+ maddr = (void*)((size_t)addr & ~(page_size - 1));
493
+ if (mprotect(maddr, page_size, PROT_READ | PROT_WRITE) != 0) {
494
+ set_errmsg("Could not change the process memory protection at %p: %s",
495
+ maddr, strerror(errno));
496
+ return PLTHOOK_INTERNAL_ERROR;
497
+ }
498
+ }
499
+ #endif
431
500
  if (oldfunc) {
432
501
  *oldfunc = *addr;
433
502
  }
434
503
  *addr = funcaddr;
504
+ #ifdef PT_GNU_RELRO
505
+ if (maddr != NULL) {
506
+ mprotect(maddr, page_size, PROT_READ);
507
+ }
508
+ #endif
435
509
  return 0;
436
510
  }
437
511
  }
@@ -477,8 +551,15 @@ static int check_elf_header(const Elf_Ehdr *ehdr)
477
551
  return PLTHOOK_INVALID_FILE_FORMAT;
478
552
  }
479
553
  if (ehdr->e_ident[EI_OSABI] != ELF_OSABI) {
554
+ #ifdef ELF_OSABI_ALT
555
+ if (ehdr->e_ident[EI_OSABI] != ELF_OSABI_ALT) {
556
+ set_errmsg("invalid OS ABI: 0x%02x", ehdr->e_ident[EI_OSABI]);
557
+ return PLTHOOK_INVALID_FILE_FORMAT;
558
+ }
559
+ #else
480
560
  set_errmsg("invalid OS ABI: 0x%02x", ehdr->e_ident[EI_OSABI]);
481
561
  return PLTHOOK_INVALID_FILE_FORMAT;
562
+ #endif
482
563
  }
483
564
  if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
484
565
  set_errmsg("invalid file type: 0x%04x", ehdr->e_type);
@@ -142,6 +142,37 @@ int plthook_open(plthook_t **plthook_out, const char *filename)
142
142
  return plthook_open_real(plthook_out, _dyld_get_image_header(idx));
143
143
  }
144
144
 
145
+ int plthook_open_by_handle(plthook_t **plthook_out, void *hndl)
146
+ {
147
+ int flags[] = {
148
+ RTLD_LAZY | RTLD_NOLOAD,
149
+ RTLD_LAZY | RTLD_NOLOAD | RTLD_FIRST,
150
+ };
151
+ int flag_idx;
152
+ #define NUM_FLAGS (sizeof(flags) / sizeof(flags[0]))
153
+
154
+ if (hndl == NULL) {
155
+ set_errmsg("NULL handle");
156
+ return PLTHOOK_FILE_NOT_FOUND;
157
+ }
158
+ for (flag_idx = 0; flag_idx < NUM_FLAGS; flag_idx++) {
159
+ const char *image_name = NULL;
160
+ uint32_t idx = 0;
161
+
162
+ do {
163
+ void *handle = dlopen(image_name, flags[flag_idx]);
164
+ if (handle != NULL) {
165
+ dlclose(handle);
166
+ if (handle == hndl) {
167
+ return plthook_open_real(plthook_out, _dyld_get_image_header(idx));
168
+ }
169
+ }
170
+ } while ((image_name = _dyld_get_image_name(++idx)) != NULL);
171
+ }
172
+ set_errmsg("Cannot find the image correspond to handle %p", hndl);
173
+ return PLTHOOK_FILE_NOT_FOUND;
174
+ }
175
+
145
176
  int plthook_open_by_address(plthook_t **plthook_out, void *address)
146
177
  {
147
178
  Dl_info dlinfo;
@@ -93,6 +93,15 @@ int plthook_open(plthook_t **plthook_out, const char *filename)
93
93
  return plthook_open_real(plthook_out, hMod);
94
94
  }
95
95
 
96
+ int plthook_open_by_handle(plthook_t **plthook_out, void *hndl)
97
+ {
98
+ if (hndl == NULL) {
99
+ set_errmsg("NULL handle");
100
+ return PLTHOOK_FILE_NOT_FOUND;
101
+ }
102
+ return plthook_open_real(plthook_out, (HMODULE)hndl);
103
+ }
104
+
96
105
  int plthook_open_by_address(plthook_t **plthook_out, void *address)
97
106
  {
98
107
  HMODULE hMod;
@@ -288,7 +288,7 @@ static VALUE oci8_stmt_fetch(VALUE self, VALUE svc)
288
288
  *
289
289
  * Returns the definition of column specified by <i>pos</i>
290
290
  *
291
- * @param [Fixnum] pos Column position which starts from one
291
+ * @param [Integer] pos Column position which starts from one
292
292
  * @return [OCI8::Metadata::Base]
293
293
  *
294
294
  * @private
@@ -1,4 +1,3 @@
1
-
2
1
  # --*- ruby -*--
3
2
  # This is based on yoshidam's oracle.rb.
4
3
  #
@@ -68,12 +67,50 @@ else
68
67
  raise 'unsupported ruby engine: ' + RUBY_ENGINE
69
68
  end
70
69
 
70
+ dll_dir = nil
71
+ begin
72
+ require 'ruby_installer/runtime' # RubyInstaller2 for Windows
73
+
74
+ dll_arch = proc do |file|
75
+ begin
76
+ File.open(file, 'rb') do |f|
77
+ if f.read(2) == 'MZ' # IMAGE_DOS_HEADER.e_magic
78
+ f.seek(60, IO::SEEK_SET)
79
+ pe_offset = f.read(4).unpack('V')[0] # IMAGE_DOS_HEADER.e_lfanew
80
+ f.seek(pe_offset)
81
+ if f.read(4) == "PE\000\000" # IMAGE_NT_HEADERS.Signature
82
+ case f.read(2).unpack('v')[0] # IMAGE_FILE_HEADER.Machine
83
+ when 0x014c # IMAGE_FILE_MACHINE_I386
84
+ :x86
85
+ when 0x8664 # IMAGE_FILE_MACHINE_AMD64
86
+ :x64
87
+ end
88
+ end
89
+ end
90
+ end
91
+ rescue
92
+ nil
93
+ end
94
+ end
95
+
96
+ ruby_arch = [nil].pack('P').size == 8 ? :x64 : :x86
97
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
98
+ if dll_arch.call(File.join(path, 'OCI.DLL')) == ruby_arch
99
+ dll_dir = RubyInstaller::Runtime.add_dll_directory(path)
100
+ break
101
+ end
102
+ end
103
+ rescue LoadError
104
+ end
105
+
71
106
  begin
72
107
  require so_basename
73
108
  rescue LoadError, OCIError
74
109
  require 'oci8/check_load_error'
75
110
  OCI8::Util::check_load_error($!)
76
111
  raise
112
+ ensure
113
+ dll_dir.remove if dll_dir
77
114
  end
78
115
 
79
116
  require 'oci8/version.rb'
@@ -58,15 +58,16 @@ class OCI8
58
58
  # # ...or...
59
59
  # cursor.bind_param(':ename', 'SMITH') # bind by name
60
60
  #
61
- # To bind as number, Fixnum and Float are available, but Bignum is
62
- # not supported. If its initial value is NULL, please set nil to
63
- # +type+ and Fixnum or Float to +val+.
61
+ # To bind as number, set the number intself to +val+. If its initial value
62
+ # is NULL, please set nil to +type+ and Integer, Float or OraNumber to +val+.
64
63
  #
65
64
  # example:
66
- # cursor.bind_param(1, 1234) # bind as Fixnum, Initial value is 1234.
65
+ # cursor.bind_param(1, 1234) # bind as Integer, Initial value is 1234.
67
66
  # cursor.bind_param(1, 1234.0) # bind as Float, Initial value is 1234.0.
68
- # cursor.bind_param(1, nil, Fixnum) # bind as Fixnum, Initial value is NULL.
67
+ # cursor.bind_param(1, nil, Integer) # bind as Integer, Initial value is NULL.
69
68
  # cursor.bind_param(1, nil, Float) # bind as Float, Initial value is NULL.
69
+ # cursor.bind_param(1, OraNumber(1234)) # bind as OraNumber, Initial value is 1234.
70
+ # cursor.bind_param(1, nil, OraNumber) # bind as OraNumber, Initial value is NULL.
70
71
  #
71
72
  # In case of binding a string, set the string itself to
72
73
  # +val+. When the bind variable is used as output, set the
@@ -379,7 +380,7 @@ class OCI8
379
380
  #
380
381
  # FYI: Rails oracle adaptor uses 100 by default.
381
382
  #
382
- # @param [Fixnum] rows The number of rows to be prefetched
383
+ # @param [Integer] rows The number of rows to be prefetched
383
384
  def prefetch_rows=(rows)
384
385
  attr_set_ub4(11, rows) # OCI_ATTR_PREFETCH_ROWS(11)
385
386
  end
@@ -430,12 +431,12 @@ class OCI8
430
431
  # * OCI8::STMT_ALTER
431
432
  # * OCI8::STMT_BEGIN (PL/SQL block which starts with a BEGIN keyword)
432
433
  # * OCI8::STMT_DECLARE (PL/SQL block which starts with a DECLARE keyword)
433
- # * Other Fixnum value undocumented in Oracle manuals.
434
+ # * Other Integer value undocumented in Oracle manuals.
434
435
  #
435
436
  # <em>Changes between ruby-oci8 1.0 and 2.0.</em>
436
437
  #
437
438
  # [ruby-oci8 2.0] OCI8::STMT_* are Symbols. (:select_stmt, :update_stmt, etc.)
438
- # [ruby-oci8 1.0] OCI8::STMT_* are Fixnums. (1, 2, 3, etc.)
439
+ # [ruby-oci8 1.0] OCI8::STMT_* are Integers. (1, 2, 3, etc.)
439
440
  #
440
441
  def type
441
442
  # http://docs.oracle.com/cd/E11882_01/appdev.112/e10646/ociaahan.htm#sthref5506
@@ -117,8 +117,9 @@ class OCI8
117
117
  else
118
118
  tcp_connect_timeout = OCI8::properties[:tcp_connect_timeout]
119
119
  connect_timeout = OCI8::properties[:connect_timeout]
120
- if tcp_connect_timeout || connect_timeout
121
- dbname = to_connect_descriptor(dbname, tcp_connect_timeout, connect_timeout)
120
+ tcp_keepalive = OCI8::properties[:tcp_keepalive]
121
+ if tcp_connect_timeout || connect_timeout || tcp_keepalive
122
+ dbname = to_connect_descriptor(dbname, tcp_connect_timeout, connect_timeout, tcp_keepalive)
122
123
  end
123
124
  end
124
125
  if stmt_cache_size
@@ -558,7 +559,7 @@ class OCI8
558
559
  # and add TRANSPORT_CONNECT_TIMEOUT or CONNECT_TIMEOUT.
559
560
  #
560
561
  # @private
561
- def to_connect_descriptor(database, tcp_connect_timeout, connect_timeout)
562
+ def to_connect_descriptor(database, tcp_connect_timeout, connect_timeout, tcp_keepalive)
562
563
  if @@easy_connect_naming_regex =~ database && ($1 || $2 || $4 || $5 || $6 || $7)
563
564
  connect_data = []
564
565
  connect_data << "(SERVICE_NAME=#$5)"
@@ -573,6 +574,9 @@ class OCI8
573
574
  if connect_timeout
574
575
  desc << "(CONNECT_TIMEOUT=#{connect_timeout})"
575
576
  end
577
+ if tcp_keepalive
578
+ desc << "(ENABLE=BROKEN)"
579
+ end
576
580
  "(DESCRIPTION=#{desc.join})"
577
581
  else
578
582
  database
@@ -17,6 +17,8 @@ class OCI8
17
17
  :connect_timeout => nil,
18
18
  :send_timeout => nil,
19
19
  :recv_timeout => nil,
20
+ :tcp_keepalive => false,
21
+ :tcp_keepalive_time => nil,
20
22
  }
21
23
 
22
24
  # @private
@@ -62,6 +64,14 @@ class OCI8
62
64
  val = val.to_i
63
65
  raise ArgumentError, "The property value for :#{name} must be nil or a positive integer." if val <= 0
64
66
  end
67
+ when :tcp_keepalive
68
+ val = val ? true : false
69
+ when :tcp_keepalive_time
70
+ if !val.nil?
71
+ val = val.to_i
72
+ raise ArgumentError, "The property value for :#{name} must be nil or a positive integer." if val <= 0
73
+ end
74
+ OCI8.__set_prop(4, val)
65
75
  end
66
76
  super(name, val)
67
77
  end
@@ -165,6 +175,18 @@ class OCI8
165
175
  #
166
176
  # *Since:* 2.2.2
167
177
  #
178
+ # [:tcp_keepalive]
179
+ #
180
+ # See {file:docs/hanging-after-inactivity.md.md}
181
+ #
182
+ # *Since:* 2.2.4
183
+ #
184
+ # [:tcp_keepalive_time]
185
+ #
186
+ # See {file:docs/hanging-after-inactivity.md.md}
187
+ #
188
+ # *Since:* 2.2.4
189
+ #
168
190
  # @return [a customized Hash]
169
191
  # @since 2.0.5
170
192
  #
@@ -1,3 +1,3 @@
1
1
  class OCI8
2
- VERSION = "2.2.3"
2
+ VERSION = "2.2.4"
3
3
  end
@@ -64,11 +64,7 @@ EOS
64
64
  raise "No compiled binary are found. Run make in advance."
65
65
  when 1
66
66
  puts "Binary gem for ruby #{so_vers.first}"
67
- if so_vers[0] < '2.0.0'
68
- s.required_ruby_version = "~> #{so_vermin}"
69
- else
70
- s.required_ruby_version = "~> #{so_vermin}.0"
71
- end
67
+ s.required_ruby_version = "~> #{so_vermin}"
72
68
  else
73
69
  puts "Binary gem for ruby #{so_vers.join(', ')}"
74
70
  s.required_ruby_version = ">= #{so_vermin}"