libsqreen 0.3.0.0.3 → 0.6.1.0.0
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.
- checksums.yaml +4 -4
- data/ext/env_overrides.rb +5 -0
- data/ext/libsqreen_extension/extconf.rb +67 -19
- data/ext/libsqreen_extension/libsqreen_extension.c +285 -280
- data/ext/libsqreen_extension/logging.c +207 -0
- data/ext/libsqreen_extension/logging.h +29 -0
- data/ext/libsqreen_extension/stub/libsqreen_stub.c +2 -0
- data/lib/libsqreen.rb +1 -8
- data/lib/libsqreen/version.rb +1 -1
- data/libsqreen.gemspec +11 -1
- data/vendor/libsqreen/include/waf.h +31 -12
- data/vendor/libsqreen/x86_64/darwin/libsqreen.a +0 -0
- data/vendor/libsqreen/x86_64/linux/libsqreen.a +0 -0
- metadata +34 -14
- data/.gitignore +0 -6
- data/.gitmodules +0 -3
- data/Makefile +0 -206
- data/Rakefile +0 -33
- data/azure-pipelines.yml +0 -28
- data/ext/libsqreen/arch.rb +0 -23
- data/ext/libsqreen/extconf.rb +0 -20
- data/ext/libsqreen/libsqreen.c +0 -29
- data/ext/libsqreen/location.rb +0 -78
- data/ext/libsqreen/paths.rb +0 -53
- data/s3get +0 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b2850167f572c0e567ef756d51190d20b5405f891d59de71748b485931793ba4
|
4
|
+
data.tar.gz: 47bb4f25a4a71e66bff95c1883eb02109b0e0e56b5d928ff7a7bf3b583d4cb92
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5191657554a0705f61ad7b78644f51630ebdb337d8e40e24ab1058ce2803cc9e2250e620af55f7417479ef8ec94b906dfd4a1879712bd5332c8cb8d72939b680
|
7
|
+
data.tar.gz: 5e7fed1e0ea2f85d4f6e39215bd092a5c4230674901efed98ce648d4be5d294e5bf01668f4cc64a91333ca0bc2a5f5058241da7ce8b83e15afbd5a6cba945922
|
@@ -1,27 +1,75 @@
|
|
1
1
|
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
2
|
# Please refer to our terms for more information: https://www.sqreen.com/terms.html
|
3
3
|
|
4
|
+
require_relative '../env_overrides.rb'
|
4
5
|
require 'mkmf'
|
6
|
+
require 'shellwords'
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
rescue LibSqreen::Location::Vendor::HeaderNotFound
|
12
|
-
puts 'could not find header. fallback to stubbing.'
|
13
|
-
$defs.push('-DLIBSQREEN_STUB')
|
14
|
-
rescue LibSqreen::Location::Vendor::ArchiveNotFound
|
15
|
-
puts "could not find binary archive: native features for platform #{RUBY_PLATFORM} not supported. fallback to stubbing."
|
16
|
-
$defs.push('-DLIBSQREEN_STUB')
|
17
|
-
else
|
18
|
-
location.configure
|
19
|
-
|
20
|
-
$CFLAGS += ' -std=c99'
|
21
|
-
if RUBY_PLATFORM =~ /linux/
|
22
|
-
version_script_path = File.expand_path(File.join(File.dirname(__FILE__), '../../ext/libsqreen_extension/libsqreen_extension.version'))
|
23
|
-
$LDFLAGS += " -lpthread -Wl,--version-script='#{version_script_path}'"
|
8
|
+
module Paths
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def include_paths
|
12
|
+
[File.join(vendored_source_path, 'libsqreen', 'include')]
|
24
13
|
end
|
14
|
+
|
15
|
+
def object_paths
|
16
|
+
objects = [
|
17
|
+
File.join(vendored_source_path, 'libsqreen', cpu, platform, libname),
|
18
|
+
]
|
19
|
+
|
20
|
+
return objects if platform == 'darwin'
|
21
|
+
|
22
|
+
objects << File.join(vendored_source_path, 'libc++', cpu, platform, 'libc++.a')
|
23
|
+
objects << File.join(vendored_source_path, 'libc++', cpu, platform, 'libc++abi.a')
|
24
|
+
objects << File.join(vendored_source_path, 'libc++', cpu, platform, 'libunwind.a')
|
25
|
+
|
26
|
+
objects
|
27
|
+
end
|
28
|
+
|
29
|
+
def has_object_files?
|
30
|
+
object_paths.all? { |p| File.file?(p) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def config
|
34
|
+
RbConfig::MAKEFILE_CONFIG
|
35
|
+
end
|
36
|
+
|
37
|
+
def platform
|
38
|
+
RUBY_PLATFORM =~ /(solaris|darwin|linux(?=-.*$)|linux$)/ && $1
|
39
|
+
end
|
40
|
+
|
41
|
+
def cpu
|
42
|
+
RUBY_PLATFORM =~ /^(universal\.|)(.*?)-/ && $2
|
43
|
+
end
|
44
|
+
|
45
|
+
def libname
|
46
|
+
"libsqreen.#{config['LIBEXT']}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def vendored_source_path
|
50
|
+
File.expand_path('../../../vendor', __FILE__)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
$INCFLAGS << ' ' + Paths.include_paths.map { |x| '-I' + Shellwords.escape(x) }.join(' ')
|
55
|
+
$LDFLAGS << ' ' + Paths.object_paths.map { |x| Shellwords.escape(x) }.join(' ')
|
56
|
+
|
57
|
+
WARNINGS = %w(no-declaration-after-statement
|
58
|
+
unused-parameter missing-prototypes unused-function
|
59
|
+
sign-conversion)
|
60
|
+
|
61
|
+
$CFLAGS += " -std=c99 #{WARNINGS.map { |x| "-W#{x}" }.join(' ')}"
|
62
|
+
|
63
|
+
src_prefix = nil
|
64
|
+
unless Paths.has_object_files?
|
65
|
+
puts "WARNING: Could not find binary objects. " \
|
66
|
+
"Native features for platform #{RUBY_PLATFORM} not supported. Fallback to stubbing."
|
67
|
+
src_prefix = File.join($srcdir, 'stub')
|
68
|
+
end
|
69
|
+
|
70
|
+
if RUBY_PLATFORM =~ /linux/
|
71
|
+
version_script_path = File.expand_path(File.join(File.dirname(__FILE__), '../../ext/libsqreen_extension/libsqreen_extension.version'))
|
72
|
+
$LDFLAGS += " -lpthread -Wl,--version-script='#{version_script_path}'"
|
25
73
|
end
|
26
74
|
|
27
|
-
create_makefile('libsqreen_extension')
|
75
|
+
create_makefile('libsqreen_extension', src_prefix)
|
@@ -3,16 +3,40 @@
|
|
3
3
|
|
4
4
|
#include <ruby.h>
|
5
5
|
#include <stdbool.h>
|
6
|
+
#include <stdint.h>
|
7
|
+
#include <time.h>
|
6
8
|
|
7
|
-
|
9
|
+
void Init_libsqreen_extension(void);
|
8
10
|
|
9
11
|
#include <waf.h>
|
12
|
+
#include "logging.h"
|
13
|
+
#include <ruby/encoding.h>
|
14
|
+
|
15
|
+
static const rb_encoding *utf8_enc;
|
16
|
+
static const rb_encoding *latin1_enc;
|
17
|
+
static const rb_encoding *ascii8bit_enc;
|
18
|
+
static const rb_encoding *usascii_enc;
|
19
|
+
static VALUE utf8_str;
|
20
|
+
static VALUE iso8859_1_str;
|
21
|
+
|
22
|
+
extern VALUE waf_mod;
|
23
|
+
VALUE waf_mod;
|
24
|
+
static VALUE waf_args_cls;
|
25
|
+
|
26
|
+
static const PWArgs pw_args_invalid = { .type = PWI_INVALID };
|
27
|
+
|
28
|
+
static const PWConfig pw_config = {
|
29
|
+
.maxArrayLength = UINT64_MAX,
|
30
|
+
.maxMapDepth = UINT64_MAX,
|
31
|
+
};
|
32
|
+
|
33
|
+
static VALUE cvt_ruby_str_to_utf8(VALUE value);
|
10
34
|
|
11
|
-
/* boxes */
|
12
35
|
|
13
36
|
// PWArgs box
|
14
37
|
struct libsqreen_waf_args {
|
15
|
-
|
38
|
+
// owned; value should not be shared
|
39
|
+
PWArgs pw_args;
|
16
40
|
};
|
17
41
|
|
18
42
|
static void
|
@@ -23,96 +47,77 @@ libsqreen_waf_args_free(void *b) {
|
|
23
47
|
return;
|
24
48
|
}
|
25
49
|
|
26
|
-
|
27
|
-
|
28
|
-
}
|
29
|
-
|
30
|
-
box->boxed = NULL;
|
50
|
+
powerwaf_freeInput(&box->pw_args, false);
|
51
|
+
box->pw_args = pw_args_invalid;
|
31
52
|
}
|
32
53
|
|
33
54
|
static VALUE
|
34
55
|
libsqreen_waf_args_alloc(VALUE klass) {
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
obj = Data_Make_Struct(klass, struct libsqreen_waf_args, NULL, libsqreen_waf_args_free, box);
|
39
|
-
|
40
|
-
box->boxed = NULL;
|
41
|
-
|
42
|
-
return obj;
|
43
|
-
}
|
56
|
+
VALUE obj;
|
57
|
+
struct libsqreen_waf_args *box;
|
44
58
|
|
45
|
-
|
46
|
-
|
47
|
-
VALUE mLibSqreen;
|
48
|
-
VALUE mWAF;
|
49
|
-
VALUE cArgs;
|
59
|
+
obj = Data_Make_Struct(klass, struct libsqreen_waf_args,
|
60
|
+
NULL /* gc_mark */, libsqreen_waf_args_free, box);
|
50
61
|
|
51
|
-
|
52
|
-
mWAF = rb_const_get(mLibSqreen, rb_intern("WAF"));
|
53
|
-
cArgs = rb_const_get(mWAF, rb_intern("Args"));
|
62
|
+
box->pw_args = pw_args_invalid;
|
54
63
|
|
55
|
-
return
|
64
|
+
return obj;
|
56
65
|
}
|
57
66
|
|
58
67
|
static VALUE
|
59
68
|
libsqreen_waf_args_new() {
|
60
|
-
|
61
|
-
|
62
|
-
VALUE waf_args;
|
63
|
-
|
64
|
-
cArgs = libsqreen_waf_args_klass();
|
65
|
-
new = rb_intern("new");
|
66
|
-
waf_args = rb_funcall(cArgs, new, 0);
|
69
|
+
ID new = rb_intern("new");
|
70
|
+
VALUE waf_args = rb_funcall(waf_args_cls, new, 0);
|
67
71
|
|
68
72
|
return waf_args;
|
69
73
|
}
|
70
74
|
|
71
75
|
static VALUE
|
72
76
|
libsqreen_waf_args_new_from_hash(VALUE hash) {
|
73
|
-
|
74
|
-
|
75
|
-
VALUE waf_args;
|
76
|
-
|
77
|
-
cArgs = libsqreen_waf_args_klass();
|
78
|
-
new = rb_intern("new");
|
79
|
-
waf_args = rb_funcall(cArgs, new, 1, hash);
|
77
|
+
ID new = rb_intern("new");
|
78
|
+
VALUE waf_args = rb_funcall(waf_args_cls, new, 1, hash);
|
80
79
|
|
81
80
|
return waf_args;
|
82
81
|
}
|
83
82
|
|
83
|
+
// transfers onwership
|
84
84
|
static void
|
85
|
-
libsqreen_waf_args_set_boxed(VALUE self, PWArgs
|
85
|
+
libsqreen_waf_args_set_boxed(VALUE self, PWArgs args) {
|
86
86
|
struct libsqreen_waf_args *box;
|
87
87
|
Data_Get_Struct(self, struct libsqreen_waf_args, box);
|
88
|
-
box->
|
88
|
+
box->pw_args = args;
|
89
89
|
}
|
90
90
|
|
91
91
|
static PWArgs *
|
92
92
|
libsqreen_waf_args_get_boxed(VALUE self) {
|
93
|
-
PWArgs *args;
|
94
|
-
|
95
93
|
struct libsqreen_waf_args *box;
|
96
94
|
Data_Get_Struct(self, struct libsqreen_waf_args, box);
|
97
|
-
|
98
|
-
return args;
|
95
|
+
return &box->pw_args;
|
99
96
|
}
|
100
97
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
98
|
+
// drops the reference, returns it, but doesn't invalidate it
|
99
|
+
static PWArgs
|
100
|
+
libsqreen_waf_args_relinquish(VALUE self) {
|
101
|
+
struct libsqreen_waf_args *box;
|
102
|
+
Data_Get_Struct(self, struct libsqreen_waf_args, box);
|
103
|
+
PWArgs ret = box->pw_args;
|
104
|
+
box->pw_args = pw_args_invalid;
|
105
|
+
return ret;
|
106
|
+
}
|
110
107
|
|
111
|
-
|
108
|
+
static void
|
109
|
+
libsqreen_waf_args_invalidate(VALUE self) {
|
110
|
+
struct libsqreen_waf_args *box;
|
111
|
+
Data_Get_Struct(self, struct libsqreen_waf_args, box);
|
112
|
+
libsqreen_waf_args_free(box);
|
112
113
|
}
|
113
114
|
|
115
|
+
/* wrappers */
|
116
|
+
|
114
117
|
static VALUE
|
115
118
|
libsqreen_version(VALUE self) {
|
119
|
+
(void) self;
|
120
|
+
|
116
121
|
PWVersion version;
|
117
122
|
VALUE result;
|
118
123
|
|
@@ -127,6 +132,7 @@ libsqreen_version(VALUE self) {
|
|
127
132
|
|
128
133
|
static VALUE
|
129
134
|
libsqreen_waf_set(VALUE self, VALUE name, VALUE rules) {
|
135
|
+
(void)self;
|
130
136
|
char * pw_name;
|
131
137
|
char * pw_rules;
|
132
138
|
bool pw_result;
|
@@ -137,7 +143,7 @@ libsqreen_waf_set(VALUE self, VALUE name, VALUE rules) {
|
|
137
143
|
|
138
144
|
pw_name = StringValueCStr(name);
|
139
145
|
pw_rules = StringValueCStr(rules);
|
140
|
-
pw_result =
|
146
|
+
pw_result = powerwaf_init(pw_name, pw_rules, &pw_config);
|
141
147
|
|
142
148
|
result = pw_result ? Qtrue : Qfalse;
|
143
149
|
|
@@ -146,6 +152,8 @@ libsqreen_waf_set(VALUE self, VALUE name, VALUE rules) {
|
|
146
152
|
|
147
153
|
static VALUE
|
148
154
|
libsqreen_waf_delete(VALUE self, VALUE name) {
|
155
|
+
(void)self;
|
156
|
+
|
149
157
|
char * pw_name;
|
150
158
|
|
151
159
|
Check_Type(name, T_STRING);
|
@@ -158,16 +166,17 @@ libsqreen_waf_delete(VALUE self, VALUE name) {
|
|
158
166
|
|
159
167
|
static VALUE
|
160
168
|
libsqreen_waf_clear(VALUE self) {
|
169
|
+
(void)self;
|
170
|
+
|
161
171
|
powerwaf_clearAll();
|
162
172
|
|
163
173
|
return Qnil;
|
164
174
|
}
|
165
175
|
|
166
|
-
static
|
167
|
-
|
168
|
-
int on_hash_iteration(VALUE key, VALUE val, VALUE args);
|
176
|
+
static int on_hash_iteration(VALUE key, VALUE val, VALUE args);
|
169
177
|
|
170
|
-
PWArgs
|
178
|
+
static PWArgs
|
179
|
+
value_to_pw_args(VALUE val) {
|
171
180
|
PWArgs pw_val;
|
172
181
|
|
173
182
|
switch (TYPE(val)) {
|
@@ -175,9 +184,10 @@ PWArgs value_to_pw_args(VALUE val) {
|
|
175
184
|
{
|
176
185
|
char *pw_string;
|
177
186
|
size_t pw_len;
|
187
|
+
VALUE utf8_val = cvt_ruby_str_to_utf8(val);
|
178
188
|
|
179
|
-
pw_string = StringValuePtr(
|
180
|
-
pw_len = RSTRING_LEN(
|
189
|
+
pw_string = StringValuePtr(utf8_val);
|
190
|
+
pw_len = (size_t)RSTRING_LEN(utf8_val);
|
181
191
|
pw_val = powerwaf_createStringWithLength(pw_string, pw_len);
|
182
192
|
}
|
183
193
|
break;
|
@@ -191,17 +201,24 @@ PWArgs value_to_pw_args(VALUE val) {
|
|
191
201
|
break;
|
192
202
|
case T_HASH:
|
193
203
|
{
|
194
|
-
VALUE waf_args;
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
204
|
+
VALUE waf_args = libsqreen_waf_args_new();
|
205
|
+
libsqreen_waf_args_set_boxed(waf_args, powerwaf_createMap());
|
206
|
+
// can in principle raise exception, but the WAF allocated
|
207
|
+
// memory (included the partial list of allocated values
|
208
|
+
// inserted in the map by on_hash_iteration) is already
|
209
|
+
// wrapped so is reachable by the GC
|
199
210
|
rb_hash_foreach(val, on_hash_iteration, waf_args);
|
211
|
+
|
212
|
+
// relinquish ownership to the caller to avoid double frees
|
213
|
+
pw_val = libsqreen_waf_args_relinquish(waf_args);
|
200
214
|
}
|
201
215
|
break;
|
202
216
|
case T_ARRAY:
|
203
217
|
{
|
204
|
-
|
218
|
+
VALUE waf_args = libsqreen_waf_args_new();
|
219
|
+
libsqreen_waf_args_set_boxed(waf_args, powerwaf_createArray());
|
220
|
+
PWArgs *array_p = libsqreen_waf_args_get_boxed(waf_args);
|
221
|
+
|
205
222
|
for (int i = 0; i < RARRAY_LEN(val); i++) {
|
206
223
|
VALUE e;
|
207
224
|
PWArgs pw_e;
|
@@ -213,44 +230,58 @@ PWArgs value_to_pw_args(VALUE val) {
|
|
213
230
|
continue;
|
214
231
|
}
|
215
232
|
|
233
|
+
// can in principle raise
|
216
234
|
pw_e = value_to_pw_args(e);
|
217
|
-
ok = powerwaf_addToPWArgsArray(
|
235
|
+
ok = powerwaf_addToPWArgsArray(array_p, pw_e);
|
218
236
|
if (!ok) {
|
219
237
|
powerwaf_freeInput(&pw_e, false);
|
220
238
|
}
|
221
239
|
}
|
240
|
+
|
241
|
+
pw_val = libsqreen_waf_args_relinquish(waf_args);
|
222
242
|
}
|
223
243
|
break;
|
224
244
|
case T_NIL:
|
225
|
-
|
226
|
-
break;
|
245
|
+
/* break intentionally missing */
|
227
246
|
default:
|
228
|
-
|
247
|
+
RUBY_LOG(PWL_INFO, "Found argument of unaccepted type: %d", TYPE(val));
|
248
|
+
/* 0.6.1 doesn't cancel the whole rule, but it still complains
|
249
|
+
* in the log if the values in the top map are missing. Replace all
|
250
|
+
* invalid values with an empty map (this uses more maps than needed,
|
251
|
+
but also doesn't hurt) */
|
252
|
+
pw_val = powerwaf_createMap();
|
229
253
|
break;
|
230
254
|
}
|
231
255
|
|
232
256
|
return pw_val;
|
233
257
|
}
|
234
258
|
|
235
|
-
int
|
236
|
-
|
259
|
+
static int
|
260
|
+
on_hash_iteration(volatile VALUE key, VALUE val, VALUE waf_value) {
|
237
261
|
char *pw_key;
|
238
|
-
|
262
|
+
size_t pw_len;
|
239
263
|
bool ok;
|
240
264
|
|
241
|
-
|
242
|
-
|
265
|
+
if (RB_TYPE_P(key, T_SYMBOL)) {
|
266
|
+
key = rb_sym_to_s(key); // can't fail
|
267
|
+
// will go to next if
|
268
|
+
}
|
243
269
|
|
244
|
-
if (
|
270
|
+
if (RB_TYPE_P(key, T_STRING)) {
|
271
|
+
pw_key = StringValuePtr(key);
|
272
|
+
pw_len = (size_t)RSTRING_LEN(key);
|
273
|
+
} else {
|
245
274
|
return ST_CONTINUE;
|
246
275
|
}
|
247
276
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
277
|
+
PWArgs *parent = libsqreen_waf_args_get_boxed(waf_value);
|
278
|
+
// can throw, but nothing allocated by powerwaf yet
|
279
|
+
PWArgs value_to_add = value_to_pw_args(val);
|
280
|
+
// key is volatile because between its last usage
|
281
|
+
// and the usage of its component pw_key, GC may run
|
282
|
+
ok = powerwaf_addToPWArgsMap(parent, pw_key, pw_len, value_to_add);
|
252
283
|
if (!ok) {
|
253
|
-
powerwaf_freeInput(&
|
284
|
+
powerwaf_freeInput(&value_to_add, false);
|
254
285
|
}
|
255
286
|
|
256
287
|
return ST_CONTINUE;
|
@@ -258,11 +289,7 @@ int on_hash_iteration(VALUE key, VALUE val, VALUE args) {
|
|
258
289
|
|
259
290
|
static VALUE
|
260
291
|
libsqreen_waf_args_initialize(VALUE self, VALUE args) {
|
261
|
-
|
262
|
-
long len;
|
263
|
-
PWArgs pw_args;
|
264
|
-
|
265
|
-
len = RARRAY_LEN(args);
|
292
|
+
long len = RARRAY_LEN(args);
|
266
293
|
if (len > 2) {
|
267
294
|
rb_raise(rb_eArgError, "wrong number of arguments");
|
268
295
|
}
|
@@ -270,17 +297,18 @@ libsqreen_waf_args_initialize(VALUE self, VALUE args) {
|
|
270
297
|
return self;
|
271
298
|
}
|
272
299
|
|
273
|
-
hash = rb_ary_entry(args, 0);
|
300
|
+
VALUE hash = rb_ary_entry(args, 0);
|
274
301
|
Check_Type(hash, T_HASH);
|
275
302
|
|
276
|
-
pw_args = value_to_pw_args(hash);
|
277
|
-
libsqreen_waf_args_set_boxed(self,
|
303
|
+
PWArgs pw_args = value_to_pw_args(hash);
|
304
|
+
libsqreen_waf_args_set_boxed(self, pw_args);
|
278
305
|
|
279
306
|
return self;
|
280
307
|
}
|
281
308
|
|
282
309
|
|
283
|
-
VALUE
|
310
|
+
static VALUE
|
311
|
+
ret_code_to_sym(PW_RET_CODE level) {
|
284
312
|
VALUE sym;
|
285
313
|
|
286
314
|
switch (level) {
|
@@ -312,199 +340,187 @@ VALUE ret_code_to_sym(PW_RET_CODE level) {
|
|
312
340
|
sym = ID2SYM(rb_intern("block"));
|
313
341
|
break;
|
314
342
|
default:
|
315
|
-
sym = Qnil;
|
316
343
|
rb_raise(rb_eArgError, "not valid value");
|
317
|
-
break;
|
318
344
|
}
|
319
345
|
|
320
346
|
return sym;
|
321
347
|
}
|
322
348
|
|
323
|
-
static VALUE
|
324
|
-
libsqreen_waf_run(VALUE self, VALUE name, VALUE args, VALUE budget) {
|
325
|
-
VALUE waf_args;
|
326
|
-
char *pw_name;
|
327
|
-
PWArgs pw_args;
|
328
|
-
size_t pw_budget;
|
329
|
-
PWRet *pw_ret;
|
330
|
-
VALUE result;
|
331
349
|
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
pw_ret = powerwaf_runPowerWAF(pw_name, &pw_args, pw_budget);
|
350
|
+
static int64_t
|
351
|
+
get_max_run_budget(VALUE arg_max_run_budg) {
|
352
|
+
if (NIL_P(arg_max_run_budg)) {
|
353
|
+
// use default value provided by waf headers
|
354
|
+
RUBY_LOG(PWL_DEBUG, "Using %d us as run timeout (default)",
|
355
|
+
PW_RUN_TIMEOUT);
|
356
|
+
return PW_RUN_TIMEOUT; // 5000 us as of this time
|
357
|
+
}
|
341
358
|
|
342
|
-
|
343
|
-
|
344
|
-
|
359
|
+
if (!FIXNUM_P(arg_max_run_budg)) {
|
360
|
+
RUBY_LOG(PWL_ERROR, "Max run budget is not a fixnum; "
|
361
|
+
"using default %d us", PW_RUN_TIMEOUT);
|
362
|
+
return PW_RUN_TIMEOUT; // 5000 us as of this time
|
363
|
+
}
|
345
364
|
|
346
|
-
|
347
|
-
|
365
|
+
long res = FIX2LONG(arg_max_run_budg);
|
366
|
+
if (res <= 0) {
|
367
|
+
RUBY_LOG(PWL_DEBUG, "Max run budget is not positive; "
|
368
|
+
"using default %d us", PW_RUN_TIMEOUT);
|
369
|
+
return PW_RUN_TIMEOUT;
|
370
|
+
}
|
348
371
|
|
349
|
-
|
372
|
+
RUBY_LOG(PWL_DEBUG, "Using %ld us as max run timeout override", res);
|
373
|
+
return (int64_t)res;
|
350
374
|
}
|
351
375
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
sym = ID2SYM(rb_intern("debug"));
|
361
|
-
break;
|
362
|
-
case PWL_INFO:
|
363
|
-
sym = ID2SYM(rb_intern("info"));
|
364
|
-
break;
|
365
|
-
case PWL_WARN:
|
366
|
-
sym = ID2SYM(rb_intern("warn"));
|
367
|
-
break;
|
368
|
-
case PWL_ERROR:
|
369
|
-
sym = ID2SYM(rb_intern("error"));
|
370
|
-
break;
|
371
|
-
default:
|
372
|
-
sym = Qnil;
|
373
|
-
rb_raise(rb_eArgError, "not valid value");
|
374
|
-
break;
|
376
|
+
static inline struct timespec
|
377
|
+
get_time_mono() {
|
378
|
+
struct timespec out;
|
379
|
+
int res = clock_gettime(CLOCK_MONOTONIC, &out);
|
380
|
+
if (res) {
|
381
|
+
// this should never fail, but...
|
382
|
+
RUBY_LOG(PWL_INFO, "clock_gettime failed");
|
383
|
+
return (struct timespec) {0};
|
375
384
|
}
|
376
|
-
|
377
|
-
return sym;
|
385
|
+
return out;
|
378
386
|
}
|
379
387
|
|
380
|
-
|
381
|
-
|
388
|
+
static inline int64_t
|
389
|
+
timespec_diff_us(struct timespec a, struct timespec b)
|
390
|
+
{
|
391
|
+
return (((int64_t)a.tv_sec - (int64_t)b.tv_sec) * 1000000000L +
|
392
|
+
((int64_t)a.tv_nsec - (int64_t)b.tv_nsec)) / 1000;
|
393
|
+
}
|
382
394
|
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
rb_raise(rb_eArgError, "not valid value");
|
402
|
-
break;
|
395
|
+
static inline size_t
|
396
|
+
calc_run_budget(struct timespec start,
|
397
|
+
int64_t gen_budget,
|
398
|
+
VALUE arg_max_run_budg) {
|
399
|
+
struct timespec after_conv = get_time_mono();
|
400
|
+
int64_t spent_conv = timespec_diff_us(after_conv, start);
|
401
|
+
int64_t rem_gen_budget = gen_budget - spent_conv;
|
402
|
+
if (rem_gen_budget < 0) {
|
403
|
+
rem_gen_budget = 0;
|
404
|
+
}
|
405
|
+
RUBY_LOG(PWL_DEBUG, "Conversion of WAF arguments took %" PRId64
|
406
|
+
" us; remaining general budget is %" PRId64 " us",
|
407
|
+
spent_conv, rem_gen_budget);
|
408
|
+
if (rem_gen_budget == 0) {
|
409
|
+
RUBY_LOG(PWL_INFO, "General budget of %" PRId64 " us exhausted after "
|
410
|
+
"native conversion (spent %" PRId64 " us)",
|
411
|
+
gen_budget, spent_conv);
|
412
|
+
return 0;
|
403
413
|
}
|
404
414
|
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
if (SYM2ID(sym) == rb_intern("trace")) {
|
414
|
-
level = PWL_TRACE;
|
415
|
-
} else if (SYM2ID(sym) == rb_intern("debug")) {
|
416
|
-
level = PWL_DEBUG;
|
417
|
-
} else if (SYM2ID(sym) == rb_intern("info")) {
|
418
|
-
level = PWL_INFO;
|
419
|
-
} else if (SYM2ID(sym) == rb_intern("warn")) {
|
420
|
-
level = PWL_WARN;
|
421
|
-
} else if (SYM2ID(sym) == rb_intern("error")) {
|
422
|
-
level = PWL_ERROR;
|
415
|
+
size_t run_budget;
|
416
|
+
int64_t max_run_budget = get_max_run_budget(arg_max_run_budg);
|
417
|
+
if (rem_gen_budget > max_run_budget) {
|
418
|
+
run_budget = (size_t)max_run_budget;
|
419
|
+
RUBY_LOG(PWL_DEBUG, "Using run budget of % " PRId64 " us instead of "
|
420
|
+
"remaining general budget of %" PRId64 " us",
|
421
|
+
run_budget, rem_gen_budget);
|
423
422
|
} else {
|
424
|
-
|
425
|
-
level = _PWL_AFTER_LAST;
|
423
|
+
run_budget = (size_t)rem_gen_budget;
|
426
424
|
}
|
427
|
-
|
428
|
-
return level;
|
425
|
+
return run_budget;
|
429
426
|
}
|
430
427
|
|
431
|
-
void on_log(PW_LOG_LEVEL level, const char *function, const char *file, int line, const char *message, size_t message_len);
|
432
|
-
|
433
428
|
static VALUE
|
434
|
-
|
435
|
-
|
429
|
+
libsqreen_waf_run(int argc, const VALUE *argv, VALUE self) {
|
430
|
+
(void)self;
|
436
431
|
|
437
|
-
|
432
|
+
VALUE name, args, budget, max_run_budget;
|
438
433
|
|
439
|
-
|
440
|
-
powerwaf_setupLogging((powerwaf_logging_cb_t)on_log, level);
|
434
|
+
rb_scan_args(argc, argv, "31", &name, &args, &budget, &max_run_budget);
|
441
435
|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
static VALUE
|
446
|
-
libsqreen_waf_log_disable(VALUE self) {
|
447
|
-
PW_LOG_LEVEL level = PWL_ERROR;
|
448
|
-
|
449
|
-
powerwaf_setupLogging(NULL, level);
|
450
|
-
|
451
|
-
return Qnil;
|
452
|
-
}
|
436
|
+
PWRet *pw_ret;
|
437
|
+
VALUE result = rb_ary_new();
|
453
438
|
|
454
|
-
|
455
|
-
|
456
|
-
|
439
|
+
Check_Type(name, T_STRING);
|
440
|
+
Check_Type(args, T_HASH);
|
441
|
+
Check_Type(budget, T_FIXNUM);
|
442
|
+
if (!NIL_P(max_run_budget)) {
|
443
|
+
Check_Type(max_run_budget, T_FIXNUM);
|
444
|
+
}
|
457
445
|
|
458
|
-
|
459
|
-
|
446
|
+
int64_t gen_budget = (int64_t)FIX2LONG(budget); // in us
|
447
|
+
struct timespec start = get_time_mono();
|
448
|
+
|
449
|
+
VALUE waf_args = libsqreen_waf_args_new_from_hash(args);
|
450
|
+
PWArgs *pw_args = libsqreen_waf_args_get_boxed(waf_args);
|
451
|
+
const char *pw_name = StringValueCStr(name);
|
452
|
+
size_t run_budget = calc_run_budget(start, gen_budget, max_run_budget);
|
453
|
+
if (run_budget == 0) {
|
454
|
+
rb_ary_push(result, ID2SYM(rb_intern("timeout")));
|
455
|
+
rb_ary_push(result, Qnil);
|
456
|
+
return result;
|
460
457
|
}
|
461
458
|
|
462
|
-
|
463
|
-
rb_ivar_set(self, i_logger, logger);
|
459
|
+
pw_ret = powerwaf_run(pw_name, pw_args, run_budget);
|
464
460
|
|
465
|
-
|
466
|
-
|
467
|
-
|
461
|
+
rb_ary_push(result, ret_code_to_sym(pw_ret->action));
|
462
|
+
rb_ary_push(result, pw_ret->data == NULL ? Qnil : rb_str_new2(pw_ret->data));
|
463
|
+
|
464
|
+
libsqreen_waf_args_invalidate(waf_args);
|
465
|
+
powerwaf_freeReturn(pw_ret);
|
468
466
|
|
469
|
-
return
|
467
|
+
return result;
|
470
468
|
}
|
471
469
|
|
472
470
|
static VALUE
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
i_logger = rb_intern("@logger");
|
478
|
-
logger = rb_ivar_get(self, i_logger);
|
471
|
+
encode_as_utf8(VALUE string) {
|
472
|
+
return rb_funcall(string, rb_intern("encode"), 1, utf8_str);
|
473
|
+
}
|
479
474
|
|
480
|
-
|
475
|
+
static VALUE
|
476
|
+
fall_back_encode_as_utf8(VALUE string) {
|
477
|
+
VALUE dup = rb_funcall(string, rb_intern("dup"), 0);
|
478
|
+
VALUE latin1_str = rb_funcall(
|
479
|
+
dup, rb_intern("force_encoding"), 1, iso8859_1_str);
|
480
|
+
return encode_as_utf8(latin1_str);
|
481
481
|
}
|
482
482
|
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
483
|
+
static VALUE
|
484
|
+
cvt_ruby_str_to_utf8(VALUE value) {
|
485
|
+
rb_encoding *const enc = rb_enc_get(value);
|
486
|
+
|
487
|
+
bool is_utf8 = enc == utf8_enc || enc == usascii_enc;
|
488
|
+
if (!is_utf8 && (enc == ascii8bit_enc || enc == latin1_enc)) {
|
489
|
+
char *str = RSTRING_PTR(value);
|
490
|
+
long len = RSTRING_LEN(value);
|
491
|
+
// still some hope left
|
492
|
+
is_utf8 = true;
|
493
|
+
for (long i = 0; i < len; i++) {
|
494
|
+
if ((unsigned char) str[i] >= 0x80) {
|
495
|
+
is_utf8 = false;
|
496
|
+
break;
|
497
|
+
}
|
498
|
+
}
|
494
499
|
}
|
495
500
|
|
496
|
-
|
497
|
-
|
498
|
-
return;
|
501
|
+
if (is_utf8) {
|
502
|
+
// may not be valid_encoding?, but the WAF tolerates this
|
503
|
+
return value;
|
499
504
|
}
|
500
505
|
|
501
|
-
|
502
|
-
|
503
|
-
|
506
|
+
// attempt conversion
|
507
|
+
int excepted;
|
508
|
+
VALUE result = rb_protect(encode_as_utf8, value, &excepted);
|
509
|
+
if (excepted) {
|
510
|
+
RUBY_LOG(PWL_DEBUG, "Error converting string to UTF-8. Encoding: %s",
|
511
|
+
ONIGENC_NAME(enc));
|
512
|
+
// conversion failed, try fallback
|
513
|
+
result = rb_protect(fall_back_encode_as_utf8, value, &excepted);
|
514
|
+
if (excepted) {
|
515
|
+
RUBY_LOG(PWL_INFO, "Fallback conversion -> latin1 -> utf8 also "
|
516
|
+
"failed!");
|
517
|
+
// fallback also failed; stop attempting conversion
|
518
|
+
return value;
|
519
|
+
}
|
520
|
+
}
|
521
|
+
return result;
|
504
522
|
}
|
505
523
|
|
506
|
-
#endif
|
507
|
-
|
508
524
|
// extension initializer
|
509
525
|
void
|
510
526
|
Init_libsqreen_extension(void) {
|
@@ -512,48 +528,37 @@ Init_libsqreen_extension(void) {
|
|
512
528
|
|
513
529
|
mLibSqreen = rb_define_module("LibSqreen");
|
514
530
|
|
515
|
-
// record load order
|
516
|
-
{
|
517
|
-
ID i_load_order;
|
518
|
-
VALUE load_order;
|
519
|
-
|
520
|
-
i_load_order = rb_intern("@load_order");
|
521
|
-
load_order = rb_ivar_get(mLibSqreen, i_load_order);
|
522
|
-
if (load_order == Qnil) {
|
523
|
-
load_order = rb_ary_new();
|
524
|
-
rb_ivar_set(mLibSqreen, i_load_order, load_order);
|
525
|
-
}
|
526
|
-
|
527
|
-
rb_ary_push(load_order, ID2SYM(rb_intern("libsqreen_extension.c")));
|
528
|
-
}
|
529
|
-
|
530
|
-
#ifndef LIBSQREEN_STUB
|
531
|
-
|
532
531
|
// define C API bindings
|
533
532
|
{
|
534
533
|
rb_define_module_function(mLibSqreen, "version", libsqreen_version, 0);
|
535
534
|
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
rb_define_alloc_func(cArgs, libsqreen_waf_args_alloc);
|
553
|
-
rb_define_method(cArgs, "initialize", libsqreen_waf_args_initialize, -2);
|
554
|
-
}
|
555
|
-
}
|
535
|
+
waf_mod = rb_define_module_under(mLibSqreen, "WAF");
|
536
|
+
rb_gc_register_mark_object(waf_mod);
|
537
|
+
rb_define_module_function(waf_mod, "[]=", libsqreen_waf_set, 2);
|
538
|
+
rb_define_module_function(waf_mod, "set", libsqreen_waf_set, 2);
|
539
|
+
rb_define_module_function(waf_mod, "delete", libsqreen_waf_delete, 1);
|
540
|
+
rb_define_module_function(waf_mod, "clear", libsqreen_waf_clear, 0);
|
541
|
+
rb_define_module_function(waf_mod, "run", libsqreen_waf_run, -1);
|
542
|
+
rb_define_module_function(waf_mod, "logger", libsqreen_waf_get_logger, 0);
|
543
|
+
rb_define_module_function(waf_mod, "logger=", libsqreen_waf_set_logger, 1);
|
544
|
+
rb_define_module_function(waf_mod, "log_level=", libsqreen_waf_log_enable, 1);
|
545
|
+
rb_define_module_function(waf_mod, "log_disable", libsqreen_waf_log_disable, 0);
|
546
|
+
|
547
|
+
waf_args_cls = rb_define_class_under(waf_mod, "Args", rb_cData);
|
548
|
+
rb_define_alloc_func(waf_args_cls, libsqreen_waf_args_alloc);
|
549
|
+
rb_define_method(waf_args_cls, "initialize", libsqreen_waf_args_initialize, -2);
|
550
|
+
rb_gc_register_mark_object(waf_args_cls);
|
556
551
|
}
|
557
552
|
|
558
|
-
|
553
|
+
utf8_enc = rb_enc_find("utf-8");
|
554
|
+
latin1_enc = rb_enc_find("iso-8859-1");
|
555
|
+
ascii8bit_enc = rb_ascii8bit_encoding();
|
556
|
+
usascii_enc = rb_usascii_encoding();
|
557
|
+
|
558
|
+
utf8_str = rb_str_new2("utf-8");
|
559
|
+
rb_gc_register_mark_object(utf8_str);
|
560
|
+
iso8859_1_str = rb_str_new2("iso-8859-1");
|
561
|
+
rb_gc_register_mark_object(iso8859_1_str);
|
562
|
+
|
563
|
+
log_init();
|
559
564
|
}
|