validate: fix type stack and leaks
[m6w6/ext-psi] / README.md
1 # ext-psi
2
3 [![Join the chat at https://gitter.im/m6w6/ext-psi](https://badges.gitter.im/m6w6/ext-psi.svg)](https://gitter.im/m6w6/ext-psi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4 [![Build Status](https://travis-ci.org/m6w6/ext-psi.svg?branch=master)](https://travis-ci.org/m6w6/ext-psi)
5
6 PSI is a PHP extension, which provides a foreign function interface through
7 `libffi` and/or `libjit`.
8
9 The acronym PSI may be read as:
10 * PHP System Interface
11 * POSIX Standard Interface
12
13 The latter because PSI can be configured to include declarations for most of the
14 [base definitions and system interfaces of POSIX.1-2008](http://pubs.opengroup.org/onlinepubs/9699919799/).
15
16 > **WARNING:**
17 > This is heavy WIP. Only a small part of configuration and implementation has been completed yet.
18
19 ## Features
20
21 * standard scalar types mapped to stdint types
22 * structs, unions, enums and typedefs
23 * simple numeric expressions
24 * string and int constants
25 * vararg calls
26
27 ## Installing
28
29 > **WARNING:**
30 > This is heavy WIP. Installation only works from a source checkout yet.
31
32 ### PECL
33
34 This extension is distributed through [PECL](http://pecl.php.net) and can be
35 installed with [PEAR](http://pear.php.net)'s pecl command:
36
37 pecl install psi
38
39 ### PHARext
40
41 Watch out for [PECL replicates](https://replicator.pharext.org?psi)
42 and [pharext](https://github.com/pharext) packages attached to
43 [releases](https://github.com/m6w6/ext-psi/releases).
44
45 ### Checkout
46
47 This extension is hosted at [Github](https://github.com/m6w6/ext-psi) with a
48 personal [mirror](https://git.m6w6.name/?p=m6w6/ext-psi) available.
49
50 git clone github.com:m6w6/ext-psi
51
52 cd ext-psi
53
54 /path/to/phpize
55 ./configure --with-php-config=/path/to/php-config
56 make
57 sudo make install
58
59 ## Configuring PSI at build time
60
61 PSI supports the following configure switches:
62
63 ### --enable-psi
64 **Enable PHP System Interface support.**
65
66 This is only relevant for an in-tree build. Use `--enable-psi` to include
67 the PSI extension in the build.
68
69 ### --enable-psi-posix
70 **Pre-define POSIX decls.**
71
72 Use `--enable-psi-posix=all` to enable all available POSIX checks.
73
74 Use `--enable-psi-posix=section,another,onemore` to enable specific modules only.
75
76 The following modules are included by default:
77
78 [stdint](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stdint.h.html),
79 [stddef](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stddef.h.html),
80 [stdlib](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stdlib.h.html),
81 [sys/types](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_types.h.html)
82
83 The following modules are available to select:
84
85 [errno](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html),
86 [fcntl](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/fcntl.h.html),
87 [glob](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/glob.h.html),
88 [locale](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/locale.h.html),
89 [ndbm](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/ndbm.h.html),
90 [netdb](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netdb.h.html),
91 [netinet/in](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html),
92 [netinet/tcp](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_tcp.h.html),
93 [poll](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/poll.h.html),
94 [signal](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html),
95 [stdio](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stdio.h.html),
96 [sys/select](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_select.h.html),
97 [sys/socket](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html),
98 [sys/stat](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_stat.h.html),
99 [sys/time](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_time.h.html),
100 [sys/times](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_times.h.html),
101 [sys/uio](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_uio.h.html),
102 [sys/utsname](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_utsname.h.html),
103 [syslog](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/syslog.h.html),
104 [time](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/time.h.html),
105 [unistd](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html),
106 [wchar](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/wchar.h.html),
107 [wctype](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/wctype.h.html),
108
109 ### --with-psi-libjit
110 **Path to libjit.**
111
112 > **WARNING:**
113 > We currently rely on a patched libjit, because of an apparent bug in how
114 > libjit creates closures, which still needs to be verified, though.
115 > See https://github.com/m6w6/libjit for the preliminary patch.
116
117 ### --with-psi-libffi
118 **Path to libffi.**
119
120 ## Configuring PSI at runtime
121
122 ### psi.engine
123
124 The backend that PSI should use as FFI, either _jit_ for `libjit` or _ffi_ for `libffi`. Defaults to "ffi".
125
126 ### psi.directory
127
128 A colon separated list of directories to scan for `*.psi` files. Defaults to "psi.d".
129
130 ## PSI files
131
132 ### Comments
133
134 * C style multi line comments
135 * C++ style single line comments
136
137 ```c
138 // this is a one line comment
139 /* followed
140 by a multi
141 line comment
142 */
143 ```
144
145 ### Typedefs
146
147 ```c
148 typedef unsigned char xmlChar;
149 ```
150
151 They follow the basic C-style `typedef` syntax.
152
153 ```c
154 typedef struct str {
155 char *p;
156 size_t l;
157 } str_t;
158 ```
159 You can also `typedef` unions and enums that way.
160
161 ### Structs
162
163 The following example results in exactly the same interpretation as the previous:
164
165 ```c
166 typedef struct str str_t;
167 struct str {
168 char *p;
169 size_t l;
170 }
171 ```
172
173 A struct will have the size of all its elements plus padding combined and an
174 alignment equal to that of the largest element's alignment.
175
176 ### Enums
177
178 Enums are considered to be of type `int`.
179
180 ```c
181 enum STATUS {
182 FAILURE = -1,
183 SUCCESS
184 }
185 ```
186
187 Enums will be registered as userland constants with the following pattern:
188
189 * `psi\STATUS\FAILURE` with value -1
190 * `psi\STATUS\SUCCESS` with value 0
191
192 ### Unions
193
194 ```c
195 union anyval {
196 char c;
197 short s;
198 int i;
199 long l;
200 float f;
201 double d;
202 str_t str;
203 }
204 ```
205
206 Unions will have the size and alignment of the largest element they contain.
207
208 ### Lib
209
210 ```c
211 lib "awesome";
212 ```
213
214 These statements define what library should be `dlopen()`-ed to look up symbols from declarations.
215 They must only occur once in a file. When a `lib` statement is omitted, stdlib is assumed.
216
217 ### Declarations
218
219 Declarations provide all information needed to make a foreign function call.
220
221 ```c
222 extern char *strerror(int errnum);
223 ```
224
225 You may specify a non-standard calling convention in place of `extern`, where `default` and `cdecl` have the same meaning as `extern`.
226
227 Additionally recognized calling conventions include: `stdcall` and `fastcall`.
228
229 ### Constants
230
231 ```c
232 const int num\ZERO = 0;
233 const string pwd\TOKEN = "4WlOjXGL";
234 ```
235
236 Constants must have a namespaced identifiers and are registered as userland constants.
237
238 ### Implementations
239
240 Implementations are the userland visible interfaces to the foreign function interface.
241
242 ```php
243 function str\error(int $num) : string {
244 let errnum = intval($num);
245 return to_string(strerror);
246 }
247 ```
248
249 Each implementation refers to exactly one declared foreign function referenced in its `return` statement. Each declaration, on the other hand, may have any number of implementations.
250
251 ## Complete example
252
253 ```c
254 // all declarations in this file should be looked up in libidn
255 lib "idn";
256
257 // IDNA errors
258 const int \IDNA_SUCCESS = 0;
259 const int \IDNA_STRINGPREP_ERROR = 1;
260 const int \IDNA_PUNYCODE_ERROR = 2;
261 const int \IDNA_CONTAINS_NON_LDH = 3;
262 const int \IDNA_CONTAINS_LDH = 3;
263 const int \IDNA_CONTAINS_MINUS = 4;
264 const int \IDNA_INVALID_LENGTH = 5;
265 const int \IDNA_NO_ACE_PREFIX = 6;
266 const int \IDNA_ROUNDTRIP_VERIFY_ERROR = 7;
267 const int \IDNA_CONTAINS_ACE_PREFIX = 8;
268 const int \IDNA_ICONV_ERROR = 9;
269 const int \IDNA_MALLOC_ERROR = 201;
270 const int \IDNA_DLOPEN_ERROR = 202;
271 // IDNA flags
272 const int \IDNA_ALLOW_UNASSIGNED = 1;
273 const int \IDNA_USE_STD3_ASCII_RULES = 2;
274
275 // nothing special about the declaration here
276 default int idna_to_ascii_8z(char *host, char **buffer, int flags);
277
278 function idn\utf8_to_ascii(string $host, string &$result, int $flags = 0) : int {
279 // there must be a `let` statement for each
280 // declared argument of the called function
281
282 // setup a pointer to NULL
283 let buffer = &NULL;
284
285 // setup a string pointer to $host
286 let host = strval($host);
287
288 // assing the integer value of $flags
289 let flags = intval($flags);
290
291 // the function to call is referenced in
292 // the return statement, along with the
293 // neccessary cast how to interpred the
294 // returned native value
295 return to_int(idna_to_ascii_8z);
296
297 // by-ref vars might receive output values
298 // through `set` statments, which also
299 // require a cast how to marshal the
300 // native data as PHP value
301 set $result = to_string(*buffer);
302
303 // after the buffer has been marshaled
304 // for the PHP engine, we have to free
305 // the buffer to avoid a memory leak
306 free free(*buffer);
307 // note that in this example we omit the
308 // declaration of the free() function called
309 // in our `free` statement for brevity
310 }
311
312 default char *idna_strerror(int rc);
313 function idn\strerror(int $rc) : string {
314 return to_string(idna_strerror);
315 let rc = intval($rc);
316 }
317 ```
318
319 ### Userland
320
321 ```php
322 $rc = idn\utf8_to_ascii("flöte.de", $result);
323 printf("<%s>\n", $result);
324 printf("%s\n", idn\strerror($rc));
325
326 $rc = idn\utf8_to_ascii("…asdf….de", $result, IDNA_USE_STD3_ASCII_RULES);
327 printf("<%s>\n", $result);
328 printf("%s\n", idn\strerror($rc));
329 ```
330
331 #### Output
332 ```
333 <xn--flte-6qa.de>
334 Success
335 <>
336 Non-digit/letter/hyphen in input
337 ```
338
339 ## ChangeLog
340
341 A comprehensive list of changes can be obtained from the
342 [PECL website](https://pecl.php.net/package-changelog.php?package=psi).
343
344 Known issues are listed in [BUGS](./BUGS) and future ideas can be found in [TODO](./TODO).
345
346 ## License
347
348 ext-psi is licensed under the 2-Clause-BSD license, which can be found in
349 the accompanying [LICENSE](./LICENSE) file.
350
351 ## Contributing
352
353 All forms of contribution are welcome! Please see the bundled
354 [CONTRIBUTING](./CONTRIBUTING.md) note for the general principles followed.
355
356 The list of past and current contributors is maintained in [THANKS](./THANKS).