1#[derive(Clone, Debug, Eq, PartialEq)]
3pub struct NestedAttribute {
4 pub name_index: u16,
6 pub owner: NestedAttributeOwner,
8 pub order: usize,
10 pub declared_length: u32,
12 pub bytes: Vec<u8>,
14 pub origin: AttributeOrigin,
16}
17#[derive(Clone, Copy, Debug, Eq, PartialEq)]
19pub enum NestedAttributeOwner {
20 Code,
22 RecordComponent,
24}
25
26#[derive(Clone, Copy, Debug, Eq, PartialEq)]
28pub struct CodeException {
29 pub start_pc: u16,
31 pub end_pc: u16,
33 pub handler_pc: u16,
35 pub catch_type: u16,
37}
38
39#[derive(Clone, Debug, Eq, PartialEq)]
41pub struct CodeAttribute {
42 pub max_stack: u16,
44 pub max_locals: u16,
46 pub code: Vec<u8>,
48 pub exception_table: Vec<CodeException>,
50 pub attributes: Vec<NestedAttribute>,
52}
53
54impl CodeAttribute {
55 pub fn decode(reader: &mut ByteReader<'_>) -> Result<Self, AttributeError> {
57 let max_stack = reader.read_u2()?;
58 let max_locals = reader.read_u2()?;
59 let code_len = usize::try_from(reader.read_u4()?).map_err(|_| {
60 error(
61 AttributeErrorKind::CountOverflow,
62 reader.offset(),
63 "code length is not addressable",
64 )
65 })?;
66 reader.preflight_allocation(code_len)?;
67 let code = reader.take(code_len)?.to_vec();
68 let exception_count = usize::from(reader.read_u2()?);
69 reader.preflight_allocation(exception_count)?;
70 let mut exception_table = Vec::with_capacity(exception_count);
71 for _ in 0..exception_count {
72 exception_table.push(CodeException {
73 start_pc: reader.read_u2()?,
74 end_pc: reader.read_u2()?,
75 handler_pc: reader.read_u2()?,
76 catch_type: reader.read_u2()?,
77 });
78 }
79 validate_code_shape(code.len(), &exception_table)?;
80 let attribute_count = usize::from(reader.read_u2()?);
81 reader.preflight_allocation(attribute_count)?;
82 let mut attributes = Vec::with_capacity(attribute_count);
83 for order in 0..attribute_count {
84 let start = reader.offset();
85 let name_index = reader.read_u2()?;
86 let declared_length = reader.read_u4()?;
87 let length = usize::try_from(declared_length).map_err(|_| {
88 error(
89 AttributeErrorKind::CountOverflow,
90 reader.offset(),
91 "nested attribute length is not addressable",
92 )
93 })?;
94 reader.preflight_allocation(length)?;
95 attributes.push(NestedAttribute {
96 name_index,
97 owner: NestedAttributeOwner::Code,
98 order,
99 declared_length,
100 bytes: reader.take(length)?.to_vec(),
101 origin: annotation_origin(start, reader),
102 });
103 }
104 finish(reader)?;
105 Ok(Self {
106 max_stack,
107 max_locals,
108 code,
109 exception_table,
110 attributes,
111 })
112 }
113
114 pub fn encode(&self, budget: usize) -> Result<Vec<u8>, AttributeError> {
116 validate_code_shape(self.code.len(), &self.exception_table)?;
117 let mut out = ByteWriter::new(budget);
118 out.write_u2(self.max_stack)?;
119 out.write_u2(self.max_locals)?;
120 out.write_u4(
121 u32::try_from(self.code.len())
122 .map_err(|_| error(AttributeErrorKind::CountOverflow, 0, "code is too long"))?,
123 )?;
124 out.write_bytes(&self.code)?;
125 out.write_u2(count(self.exception_table.len(), "exception handlers")?)?;
126 for row in &self.exception_table {
127 out.write_u2(row.start_pc)?;
128 out.write_u2(row.end_pc)?;
129 out.write_u2(row.handler_pc)?;
130 out.write_u2(row.catch_type)?;
131 }
132 out.write_u2(count(self.attributes.len(), "nested attributes")?)?;
133 for attribute in &self.attributes {
134 if usize::try_from(attribute.declared_length).ok() != Some(attribute.bytes.len()) {
135 return Err(error(
136 AttributeErrorKind::StaticConstraint,
137 attribute.origin.start,
138 "nested attribute declared length differs from retained bytes",
139 ));
140 }
141 out.write_u2(attribute.name_index)?;
142 out.write_u4(attribute.declared_length)?;
143 out.write_bytes(&attribute.bytes)?;
144 }
145 Ok(out.into_bytes())
146 }
147}
148
149fn validate_code_shape(
150 code_length: usize,
151 exceptions: &[CodeException],
152) -> Result<(), AttributeError> {
153 if !(1..=u16::MAX as usize).contains(&code_length) {
154 return Err(error(
155 AttributeErrorKind::StaticConstraint,
156 0,
157 format!("Code array length {code_length} is outside 1..=65535"),
158 ));
159 }
160 for exception in exceptions {
161 let start = usize::from(exception.start_pc);
162 let end = usize::from(exception.end_pc);
163 let handler = usize::from(exception.handler_pc);
164 if start >= end || end > code_length || handler >= code_length {
165 return Err(error(
166 AttributeErrorKind::StaticConstraint,
167 start,
168 format!(
169 "exception range {start}..{end} with handler {handler} is outside Code length {code_length}"
170 ),
171 ));
172 }
173 }
174 Ok(())
175}
176
177#[derive(Clone, Copy, Debug, Eq, PartialEq)]
179pub enum VerificationType {
180 Top,
182 Integer,
184 Float,
186 Double,
188 Long,
190 Null,
192 UninitializedThis,
194 Object(u16),
196 Uninitialized(u16),
198}
199
200#[derive(Clone, Debug, Eq, PartialEq)]
202pub enum StackMapFrame {
203 Same {
205 frame_type: u8,
207 },
208 SameLocalsOneStack {
210 frame_type: u8,
212 stack: VerificationType,
214 },
215 SameLocalsOneStackExtended {
217 offset_delta: u16,
219 stack: VerificationType,
221 },
222 Chop {
224 frame_type: u8,
226 offset_delta: u16,
228 },
229 SameExtended {
231 offset_delta: u16,
233 },
234 Append {
236 frame_type: u8,
238 offset_delta: u16,
240 locals: Vec<VerificationType>,
242 },
243 Full {
245 offset_delta: u16,
247 locals: Vec<VerificationType>,
249 stack: Vec<VerificationType>,
251 },
252}
253
254#[derive(Clone, Debug, Eq, PartialEq)]
256pub struct StackMapTableAttribute {
257 pub frames: Vec<StackMapFrame>,
259}
260
261impl StackMapTableAttribute {
262 pub fn decode(reader: &mut ByteReader<'_>) -> Result<Self, AttributeError> {
264 let n = usize::from(reader.read_u2()?);
265 reader.preflight_allocation(n)?;
266 let mut frames = Vec::with_capacity(n);
267 for _ in 0..n {
268 frames.push(decode_frame(reader)?);
269 }
270 finish(reader)?;
271 Ok(Self { frames })
272 }
273 pub fn encode(&self, budget: usize) -> Result<Vec<u8>, AttributeError> {
275 let mut out = ByteWriter::new(budget);
276 out.write_u2(count(self.frames.len(), "stack-map frames")?)?;
277 for frame in &self.frames {
278 encode_frame(frame, &mut out)?;
279 }
280 Ok(out.into_bytes())
281 }
282}
283
284fn decode_type(reader: &mut ByteReader<'_>) -> Result<VerificationType, AttributeError> {
285 let at = reader.offset();
286 Ok(match reader.read_u1()? {
287 0 => VerificationType::Top,
288 1 => VerificationType::Integer,
289 2 => VerificationType::Float,
290 3 => VerificationType::Double,
291 4 => VerificationType::Long,
292 5 => VerificationType::Null,
293 6 => VerificationType::UninitializedThis,
294 7 => VerificationType::Object(reader.read_u2()?),
295 8 => VerificationType::Uninitialized(reader.read_u2()?),
296 tag => {
297 return Err(error(
298 AttributeErrorKind::ReservedTag,
299 at,
300 format!("reserved verification type tag {tag}"),
301 ));
302 }
303 })
304}
305
306fn encode_type(value: VerificationType, out: &mut ByteWriter) -> Result<(), AttributeError> {
307 let (tag, extra) = match value {
308 VerificationType::Top => (0, None),
309 VerificationType::Integer => (1, None),
310 VerificationType::Float => (2, None),
311 VerificationType::Double => (3, None),
312 VerificationType::Long => (4, None),
313 VerificationType::Null => (5, None),
314 VerificationType::UninitializedThis => (6, None),
315 VerificationType::Object(v) => (7, Some(v)),
316 VerificationType::Uninitialized(v) => (8, Some(v)),
317 };
318 out.write_u1(tag)?;
319 if let Some(v) = extra {
320 out.write_u2(v)?;
321 }
322 Ok(())
323}
324
325fn decode_frame(r: &mut ByteReader<'_>) -> Result<StackMapFrame, AttributeError> {
326 let at = r.offset();
327 let tag = r.read_u1()?;
328 Ok(match tag {
329 0..=63 => StackMapFrame::Same { frame_type: tag },
330 64..=127 => StackMapFrame::SameLocalsOneStack {
331 frame_type: tag,
332 stack: decode_type(r)?,
333 },
334 128..=246 => {
335 return Err(error(
336 AttributeErrorKind::ReservedTag,
337 at,
338 format!("reserved stack-map frame tag {tag}"),
339 ));
340 }
341 247 => StackMapFrame::SameLocalsOneStackExtended {
342 offset_delta: r.read_u2()?,
343 stack: decode_type(r)?,
344 },
345 248..=250 => StackMapFrame::Chop {
346 frame_type: tag,
347 offset_delta: r.read_u2()?,
348 },
349 251 => StackMapFrame::SameExtended {
350 offset_delta: r.read_u2()?,
351 },
352 252..=254 => {
353 let offset_delta = r.read_u2()?;
354 let mut locals = Vec::with_capacity(usize::from(tag - 251));
355 for _ in 0..tag - 251 {
356 locals.push(decode_type(r)?);
357 }
358 StackMapFrame::Append {
359 frame_type: tag,
360 offset_delta,
361 locals,
362 }
363 }
364 255 => {
365 let offset_delta = r.read_u2()?;
366 let nl = usize::from(r.read_u2()?);
367 r.preflight_allocation(nl)?;
368 let mut locals = Vec::with_capacity(nl);
369 for _ in 0..nl {
370 locals.push(decode_type(r)?);
371 }
372 let ns = usize::from(r.read_u2()?);
373 r.preflight_allocation(ns)?;
374 let mut stack = Vec::with_capacity(ns);
375 for _ in 0..ns {
376 stack.push(decode_type(r)?);
377 }
378 StackMapFrame::Full {
379 offset_delta,
380 locals,
381 stack,
382 }
383 }
384 })
385}
386
387fn encode_frame(f: &StackMapFrame, out: &mut ByteWriter) -> Result<(), AttributeError> {
388 match f {
389 StackMapFrame::Same { frame_type: t } if *t <= 63 => out.write_u1(*t)?,
390 StackMapFrame::SameLocalsOneStack {
391 frame_type: t,
392 stack,
393 } if (64..=127).contains(t) => {
394 out.write_u1(*t)?;
395 encode_type(*stack, out)?
396 }
397 StackMapFrame::SameLocalsOneStackExtended {
398 offset_delta,
399 stack,
400 } => {
401 out.write_u1(247)?;
402 out.write_u2(*offset_delta)?;
403 encode_type(*stack, out)?
404 }
405 StackMapFrame::Chop {
406 frame_type: t,
407 offset_delta,
408 } if (248..=250).contains(t) => {
409 out.write_u1(*t)?;
410 out.write_u2(*offset_delta)?
411 }
412 StackMapFrame::SameExtended { offset_delta } => {
413 out.write_u1(251)?;
414 out.write_u2(*offset_delta)?
415 }
416 StackMapFrame::Append {
417 frame_type: t,
418 offset_delta,
419 locals,
420 } if (252..=254).contains(t) && locals.len() == usize::from(*t - 251) => {
421 out.write_u1(*t)?;
422 out.write_u2(*offset_delta)?;
423 for v in locals {
424 encode_type(*v, out)?
425 }
426 }
427 StackMapFrame::Full {
428 offset_delta,
429 locals,
430 stack,
431 } => {
432 out.write_u1(255)?;
433 out.write_u2(*offset_delta)?;
434 out.write_u2(count(locals.len(), "full-frame locals")?)?;
435 for v in locals {
436 encode_type(*v, out)?
437 }
438 out.write_u2(count(stack.len(), "full-frame stack entries")?)?;
439 for v in stack {
440 encode_type(*v, out)?
441 }
442 }
443 _ => {
444 return Err(error(
445 AttributeErrorKind::ReservedTag,
446 0,
447 "frame variant contains a tag or arity outside its static format",
448 ));
449 }
450 }
451 Ok(())
452}