source: rtems/cpukit/score/src/objectextendinformation.c

Last change on this file was 659a79e, checked in by Kinsey Moore <kinsey.moore@…>, on 01/16/24 at 19:58:58

cpukit/score: Avoid overflow in multiplication

Change extend_count to uint32_t from uint16_t to avoid a possible
premature integer overflow when it is later used for multiplication.

  • Property mode set to 100644
File size: 8.4 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @ingroup RTEMSScoreObject
7 *
8 * @brief This source file contains the implementation of
9 *   _Objects_Extend_information().
10 */
11
12/*
13 *  COPYRIGHT (c) 1989-1999.
14 *  On-Line Applications Research Corporation (OAR).
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 *    notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 *    notice, this list of conditions and the following disclaimer in the
23 *    documentation and/or other materials provided with the distribution.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#endif
41
42#include <rtems/score/objectimpl.h>
43#include <rtems/score/address.h>
44#include <rtems/score/assert.h>
45#include <rtems/score/chainimpl.h>
46#include <rtems/score/isrlevel.h>
47#include <rtems/score/sysstate.h>
48#include <rtems/score/wkspace.h>
49
50#include <string.h>  /* for memcpy() */
51
52Objects_Maximum _Objects_Extend_information(
53  Objects_Information *information
54)
55{
56  Objects_Control  *the_object;
57  uint32_t          block_count;
58  uint32_t          block;
59  uint32_t          index_base;
60  uint32_t          index_end;
61  uint32_t          index;
62  uint32_t          extend_count;
63  Objects_Maximum   old_maximum;
64  uint32_t          new_maximum;
65  size_t            object_block_size;
66  Objects_Control  *new_object_block;
67  bool              do_extend;
68  Objects_Id        api_class_and_node;
69
70  _Assert(
71    _Objects_Allocator_is_owner()
72      || !_System_state_Is_up( _System_state_Get() )
73  );
74  _Assert( _Objects_Is_auto_extend( information ) );
75
76  extend_count = _Objects_Extend_size( information );
77  old_maximum = _Objects_Get_maximum_index( information );
78  new_maximum = (uint32_t) old_maximum + extend_count;
79  api_class_and_node = information->maximum_id & ~OBJECTS_INDEX_MASK;
80
81  /*
82   *  Search for a free block of indexes. If we do NOT need to allocate or
83   *  extend the block table, then we will change do_extend.
84   */
85  do_extend     = true;
86  index_base    = extend_count;
87  block         = 1;
88
89  if ( information->object_blocks == NULL ) {
90    block_count = 1;
91  } else {
92    block_count = old_maximum / extend_count;
93
94    for ( ; block < block_count; block++ ) {
95      if ( information->object_blocks[ block ] == NULL ) {
96        do_extend = false;
97        break;
98      } else
99        index_base += extend_count;
100    }
101  }
102
103  index_end = index_base + extend_count;
104
105  /*
106   *  We need to limit the number of objects to the maximum number
107   *  representable in the index portion of the object Id.  In the
108   *  case of 16-bit Ids, this is only 256 object instances.
109   */
110  if ( new_maximum > OBJECTS_ID_FINAL_INDEX ) {
111    return 0;
112  }
113
114  /*
115   * Allocate the name table, and the objects and if it fails either return or
116   * generate a fatal error depending on auto-extending being active.
117   */
118  object_block_size = extend_count * information->object_size;
119  new_object_block = _Workspace_Allocate( object_block_size );
120  if ( new_object_block == NULL ) {
121    return 0;
122  }
123
124  /*
125   *  Do we need to grow the tables?
126   */
127  if ( do_extend ) {
128    ISR_lock_Context  lock_context;
129    Objects_Control **object_blocks;
130    Objects_Control **local_table;
131    Objects_Maximum  *inactive_per_block;
132    void             *old_tables;
133    size_t            table_size;
134    uintptr_t         object_blocks_size;
135    uintptr_t         local_table_size;
136
137    /*
138     *  Growing the tables means allocating a new area, doing a copy and
139     *  updating the information table.
140     *
141     *  If the maximum is minimum we do not have a table to copy. First
142     *  time through.
143     *
144     *  The allocation has:
145     *
146     *      Objects_Control *object_blocks[ block_count ];
147     *      Objects_Control *local_table[ maximum ];
148     *      Objects_Maximum  inactive_count[ block_count ];
149     *
150     *  This is the order in memory. Watch changing the order. See the memcpy
151     *  below.
152     */
153
154    /*
155     *  Up the block count and maximum.
156     */
157    block_count++;
158
159    /*
160     *  Allocate the tables and break it up.
161     */
162    object_blocks_size = block_count * sizeof( *object_blocks );
163    local_table_size =  new_maximum * sizeof( *local_table );
164    table_size = object_blocks_size
165      + local_table_size
166      + block_count * sizeof( *inactive_per_block );
167    object_blocks = _Workspace_Allocate( table_size );
168    if ( object_blocks == NULL ) {
169      _Workspace_Free( new_object_block );
170      return 0;
171    }
172
173    /*
174     *  Break the block into the various sections.
175     */
176    local_table = _Addresses_Add_offset(
177      object_blocks,
178      object_blocks_size
179    );
180    inactive_per_block = _Addresses_Add_offset(
181      local_table,
182      local_table_size
183    );
184
185    /*
186     *  Take the block count down. Saves all the (block_count - 1)
187     *  in the copies.
188     */
189    block_count--;
190
191    if ( old_maximum > extend_count ) {
192      /*
193       * Coverity thinks there is a way for this to be NULL (CID #26033).
194       * After much time spent analyzing this, no one has identified the
195       * conditions where this can actually occur. Adding this _Assert ensures
196       * that it is never NULL. If this assert is triggered, condition
197       * generating this case will have been identified and it can be revisted.
198       * This is being done out of an abundance of caution since we could have
199       * easily flagged this as a false positive and ignored it completely.
200       */
201      _Assert(information->object_blocks != NULL);
202
203      /*
204       *  Copy each section of the table over. This has to be performed as
205       *  separate parts as size of each block has changed.
206       */
207      memcpy(
208        object_blocks,
209        information->object_blocks,
210        block_count * sizeof( *object_blocks )
211      );
212      memcpy(
213        inactive_per_block,
214        information->inactive_per_block,
215        block_count * sizeof( *inactive_per_block )
216      );
217    } else {
218      object_blocks[ 0 ] = NULL;
219      inactive_per_block[ 0 ] = 0;
220    }
221
222    memcpy(
223      local_table,
224      information->local_table,
225      old_maximum * sizeof( *local_table )
226    );
227
228    /*
229     *  Initialise the new entries in the table.
230     */
231    for ( index = index_base ; index < index_end ; ++index ) {
232      local_table[ index ] = NULL;
233    }
234
235    /* FIXME: https://devel.rtems.org/ticket/2280 */
236    _ISR_lock_ISR_disable( &lock_context );
237
238    old_tables = information->object_blocks;
239
240    information->object_blocks = object_blocks;
241    information->inactive_per_block = inactive_per_block;
242    information->local_table = local_table;
243    information->maximum_id = api_class_and_node
244      | (new_maximum << OBJECTS_INDEX_START_BIT);
245
246    _ISR_lock_ISR_enable( &lock_context );
247
248    _Workspace_Free( old_tables );
249
250    block_count++;
251  }
252
253  /*
254   *  Assign the new object block to the object block table.
255   */
256  information->object_blocks[ block ] = new_object_block;
257  information->inactive_per_block[ block ] = information->objects_per_block;
258  information->inactive += information->objects_per_block;
259
260  /*
261   *  Append to inactive chain.
262   */
263  the_object = new_object_block;
264  for ( index = index_base ; index < index_end ; ++index ) {
265    the_object->id = api_class_and_node
266      | ( ( index + OBJECTS_INDEX_MINIMUM ) << OBJECTS_INDEX_START_BIT );
267
268    _Chain_Initialize_node( &the_object->Node );
269    _Chain_Append_unprotected( &information->Inactive, &the_object->Node );
270
271    the_object = _Addresses_Add_offset( the_object, information->object_size );
272  }
273
274  return block;
275}
Note: See TracBrowser for help on using the repository browser.