releasetag/lib.rs
1/// Placing a formatted byte-string on process-stack eventually propagating into crash core-dumps.
2///
3/// This macro takes a number of comma-separated byte string literals, byte-arrays or
4/// content of includes forming a single byte-sequence on stack with leading and trailing
5/// zero-bytes, terminating the strings.
6///
7/// These arrays and included files must not cotain and zero-string. The code would compile, and the
8/// data would reside in core files, but tools like 'strings' would extract not a single string but
9/// multiple strings.
10///
11/// That said: if you do not depend on tools like 'strings' extracting zero-terminated strings from binaries,
12/// your tag and files may be formed by any kind of byte-sequence.
13///
14/// # Example
15///
16/// ```rust
17/// #[macro_use(releasetag)]
18/// extern crate releasetag;
19///
20/// fn main() {
21/// releasetag!(b"BUILD_TAG=pre");
22/// releasetag!(b"BUILD_TAG=", b"MAIN_2016-wk16-05-AAAA-BBBB-CCCC-DDDD-EEEE-FFFF-GGGG-HHHH-IIII-JJJJ-KKKK");
23///
24/// // Including data from one or multiple files or compile time env params.
25/// // Note: the content mustn't contain any newline or linebreak as those would interfer with zero terminated strings!!
26/// let mut version: [u8; 5] = [0; 5];
27/// version.copy_from_slice(env!("CARGO_PKG_VERSION").as_bytes());
28/// releasetag!(b"BUILD_VERSION=", &version);
29/// releasetag!(b"BUILD_TAG=", &version, b"/", include_bytes!("../AUTHOR"));
30///
31/// // or as byte array
32/// releasetag!(b"BUILD_HOST=", &[0x30u8, 0x31u8, 0x33u8]);
33///
34/// // your application logic here
35/// }
36/// ```
37#[macro_export]
38macro_rules! releasetag {
39 // Thanks to Japaric's help, this crate no longer depends on nightly features.
40 ($tag:expr) => {
41 let _tag = {
42 // Prevent reordering of struct-members
43 #[repr(C)]
44 struct EmbeddedOctetBuf<T> {
45 pad0 : usize, // Leading '\0' using default integer alignment
46 txt0 : T, // User defined array or static string
47 pad1 : u8, // Trailing '\0' consecutive to array
48 }
49
50 // Define stacktag, with leading (and aligned) 0 and trailing \0, fencing the string.
51 let stacktag = EmbeddedOctetBuf{pad0: 0, txt0 : *$tag, pad1: 0x0u8};
52
53 stacktag
54 };
55 // "Volatile" will prevent compiler from
56 // * optimizing the unused value out
57 // * turning the stack value into a static value
58 let _myref = unsafe { std::ptr::read_volatile(&&_tag); };
59 };
60
61 ($tag:expr, $val1:expr) => {
62 let _tag = {
63 // Prevent reordering of struct-members
64 #[repr(C)]
65 struct EmbeddedOctetBuf<T, V> {
66 pad0 : usize, // Leading '\0' using default integer alignment
67 txt0 : T, // User defined array or static byte string (byte array [u8])
68 txt1 : V, // User defined array or static byte string (byte array [u8])
69 pad1 : u8, // Trailing '\0' consecutive to array
70 }
71
72 // Define stacktag, with leading (and aligned) 0 and trailing \0, fencing the string.
73 let stacktag = EmbeddedOctetBuf{pad0: 0, txt0 : *$tag, txt1 : *$val1, pad1: 0x0u8};
74
75 stacktag
76 };
77 // "Volatile" will prevent compiler from
78 // * optimizing the unused value out
79 // * turning the stack value into a static value
80 let _myref = unsafe { std::ptr::read_volatile(&&_tag); };
81 };
82
83 ($tag:expr, $val1:expr, $val2:expr) => {
84 let _tag = {
85 // Prevent reordering of struct-members
86 #[repr(C)]
87 struct EmbeddedOctetBuf<T, V, W> {
88 pad0 : usize, // Leading '\0' using default integer alignment
89 txt0 : T, // User defined array or static byte string (byte array [u8])
90 txt1 : V, // User defined array or static byte string (byte array [u8])
91 txt2 : W, // User defined array or static byte string (byte array [u8])
92 pad1 : u8, // Trailing '\0' consecutive to array
93 }
94
95 // Define stacktag, with leading (and aligned) 0 and trailing \0, fencing the string.
96 let stacktag = EmbeddedOctetBuf{pad0: 0, txt0 : *$tag, txt1 : *$val1, txt2 : *$val2, pad1: 0x0u8};
97
98 stacktag
99 };
100 // "Volatile" will prevent compiler from
101 // * optimizing the unused value out
102 // * turning the stack value into a static value
103 let _myref = unsafe { std::ptr::read_volatile(&&_tag); };
104 };
105
106 ($tag:expr, $val1:expr, $val2:expr, $val3:expr) => {
107 let _tag = {
108 // Prevent reordering of struct-members
109 #[repr(C)]
110 struct EmbeddedOctetBuf<T, V, W, X> {
111 pad0 : usize, // Leading '\0' using default integer alignment
112 txt0 : T, // User defined array or static byte string (byte array [u8])
113 txt1 : V, // User defined array or static byte string (byte array [u8])
114 txt2 : W, // User defined array or static byte string (byte array [u8])
115 txt3 : X, // User defined array or static byte string (byte array [u8])
116 pad1 : u8, // Trailing '\0' consecutive to array
117 }
118
119 // Define stacktag, with leading (and aligned) 0 and trailing \0, fencing the string.
120 let stacktag = EmbeddedOctetBuf{pad0: 0, txt0 : *$tag, txt1 : *$val1, txt2 : *$val2, txt3 : *$val3, pad1: 0x0u8};
121
122 stacktag
123 };
124 // "Volatile" will prevent compiler from
125 // * optimizing the unused value out
126 // * turning the stack value into a static value
127 let _myref = unsafe { std::ptr::read_volatile(&&_tag); };
128 };
129}
130
131
132#[cfg(test)]
133mod tests {
134 /// Testing syntax only, please use test/run_test.sh testing the successfull extraction from core-file.
135 #[test]
136 fn valid_macro() {
137 #[allow(dead_code)]
138 releasetag!(b"TAG1=123");
139 releasetag!(b"TAG2", b"ABC");
140 releasetag!(b"TAG3", b"=", b"ABC" );
141 releasetag!(b"TAG4", b"[", &[0x30u8, 0x31u8, 0x33u8], b"]");
142 let mut version: [u8; 5] = [0; 5];
143 version.copy_from_slice(env!("CARGO_PKG_VERSION").as_bytes());
144 releasetag!(b"TAG4=", &version);
145 releasetag!(b"TAG4", b"[", include_bytes!("../AUTHOR"), b"]");
146 }
147}