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}