ruby-oci8 2.2.3 → 2.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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}"