@@ -77,8 +77,9 @@ typedef struct {
7777typedef struct {
7878 HANDLE handle ;
7979 USHORT version ;
80- USHORT channel_count ; /* named channels only */
81- ULONG measure_buf_size ; /* buffer for ALL channels (incl. unnamed) */
80+ USHORT channel_count ; /* named channels only */
81+ ULONG measure_buf_size ; /* buffer size for ALL channels (incl. unnamed) */
82+ BYTE * measure_buf ; /* pre-allocated measurement buffer */
8283 emi_channel_t channels [MAX_CHANNELS ];
8384} emi_device_t ;
8485
@@ -140,6 +141,7 @@ static unsigned int parse_uint(const char *s)
140141 */
141142static int normalize_name (const WCHAR * wname , char * out , size_t out_size )
142143{
144+ if (out_size == 0 ) return 0 ;
143145 size_t i = 0 ;
144146 for (const WCHAR * p = wname ; * p && i < out_size - 1 ; p ++ ) {
145147 char c ;
@@ -237,6 +239,12 @@ static int open_emi_devices(emi_device_t *devs, int max_devs)
237239 continue ;
238240 }
239241
242+ if (msize .MetadataSize == 0 ) {
243+ fprintf (stderr , "Warning: EMI device %lu reported zero metadata size — skipping\n" , idx );
244+ CloseHandle (h );
245+ continue ;
246+ }
247+
240248 BYTE * meta = malloc (msize .MetadataSize );
241249 if (!meta ) { CloseHandle (h ); continue ; }
242250
@@ -260,25 +268,40 @@ static int open_emi_devices(emi_device_t *devs, int max_devs)
260268 dev -> measure_buf_size = sizeof (EMI_CHANNEL_MEASUREMENT_DATA );
261269
262270 } else { /* V2 */
263- const EMI_METADATA_V2 * m = (const EMI_METADATA_V2 * )meta ;
264- const EMI_CHANNEL_V2 * ch = m -> Channels ;
271+ const EMI_METADATA_V2 * m = (const EMI_METADATA_V2 * )meta ;
272+ const EMI_CHANNEL_V2 * ch = m -> Channels ;
273+ const BYTE * meta_end = meta + msize .MetadataSize ;
265274 USHORT valid = 0 ;
266275
267276 for (USHORT c = 0 ; c < m -> ChannelCount ; c ++ ) {
277+ /* Bound check: current entry must fit inside the metadata buffer */
278+ if ((const BYTE * )ch + sizeof (EMI_CHANNEL_V2 ) > meta_end ) {
279+ fprintf (stderr , "Warning: EMI metadata truncated on device %lu at channel %u — stopping\n" , idx , c );
280+ break ;
281+ }
282+
268283 if (valid < MAX_CHANNELS &&
269284 normalize_name (ch -> ChannelName ,
270285 dev -> channels [valid ].name , MAX_NAME_LEN )) {
271286 dev -> channels [valid ].buf_index = c ;
272287 valid ++ ;
273288 }
289+
274290 /*
275291 * Advance to the next EMI_CHANNEL_V2 entry.
276292 * ChannelNameSize includes the null terminator, in bytes.
277293 * The SDK requires 8-byte alignment between entries.
278294 */
279295 size_t stride = offsetof(EMI_CHANNEL_V2 , ChannelName ) + ch -> ChannelNameSize ;
280296 stride = (stride + 7 ) & ~(size_t )7 ;
281- ch = (const EMI_CHANNEL_V2 * )((const BYTE * )ch + stride );
297+
298+ /* Bound check: next entry must not start past the metadata buffer */
299+ const BYTE * next = (const BYTE * )ch + stride ;
300+ if (c + 1 < m -> ChannelCount && next >= meta_end ) {
301+ fprintf (stderr , "Warning: EMI metadata layout invalid on device %lu — truncating at channel %u\n" , idx , c );
302+ break ;
303+ }
304+ ch = (const EMI_CHANNEL_V2 * )next ;
282305 }
283306 dev -> channel_count = valid ;
284307 /*
@@ -297,6 +320,14 @@ static int open_emi_devices(emi_device_t *devs, int max_devs)
297320 continue ;
298321 }
299322
323+ /* Pre-allocate the measurement buffer once; reused every sample tick */
324+ dev -> measure_buf = malloc (dev -> measure_buf_size );
325+ if (!dev -> measure_buf ) {
326+ fprintf (stderr , "Warning: out of memory for EMI device %lu measurement buffer — skipping\n" , idx );
327+ CloseHandle (h );
328+ continue ;
329+ }
330+
300331 count ++ ;
301332 }
302333
@@ -338,20 +369,16 @@ static void sample_devices(emi_device_t *devs, int count, const clock_state_t *c
338369 for (int i = 0 ; i < count ; i ++ ) {
339370 emi_device_t * dev = & devs [i ];
340371
341- BYTE * buf = malloc (dev -> measure_buf_size );
342- if (!buf ) continue ;
343-
344372 DWORD ret = 0 ;
345373 if (!DeviceIoControl (dev -> handle , IOCTL_EMI_GET_MEASUREMENT ,
346- NULL , 0 , buf , dev -> measure_buf_size , & ret , NULL )) {
374+ NULL , 0 , dev -> measure_buf , dev -> measure_buf_size , & ret , NULL )) {
347375 fprintf (stderr , "Warning: IOCTL_EMI_GET_MEASUREMENT failed for device %d (%lu)\n" ,
348376 i , GetLastError ());
349- free (buf );
350377 continue ;
351378 }
352379
353380 const EMI_CHANNEL_MEASUREMENT_DATA * data =
354- (const EMI_CHANNEL_MEASUREMENT_DATA * )buf ;
381+ (const EMI_CHANNEL_MEASUREMENT_DATA * )dev -> measure_buf ;
355382
356383 for (USHORT c = 0 ; c < dev -> channel_count ; c ++ ) {
357384 emi_channel_t * ch = & dev -> channels [c ];
@@ -379,8 +406,6 @@ static void sample_devices(emi_device_t *devs, int count, const clock_state_t *c
379406 ch -> prev_energy = energy ;
380407 ch -> has_prev = 1 ;
381408 }
382-
383- free (buf );
384409 }
385410}
386411
@@ -410,8 +435,10 @@ int main(int argc, char *argv[])
410435 }
411436
412437 if (check_mode ) {
413- for (int i = 0 ; i < device_count ; i ++ )
438+ for (int i = 0 ; i < device_count ; i ++ ) {
439+ free (devs [i ].measure_buf );
414440 CloseHandle (devs [i ].handle );
441+ }
415442 return 0 ;
416443 }
417444
@@ -434,7 +461,9 @@ int main(int argc, char *argv[])
434461
435462 /* Not reached in normal operation; shown for completeness */
436463 timeEndPeriod (1 );
437- for (int i = 0 ; i < device_count ; i ++ )
464+ for (int i = 0 ; i < device_count ; i ++ ) {
465+ free (devs [i ].measure_buf );
438466 CloseHandle (devs [i ].handle );
467+ }
439468 return 0 ;
440469}
0 commit comments