1/*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
3 * Licensed under Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 *          http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
8 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
9 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 * Description: memset_s function
12 * Create: 2014-02-25
13 */
14/*
15 * [Standardize-exceptions] Use unsafe function: Portability
16 * [reason] Use unsafe function to implement security function to maintain platform compatibility.
17 *          And sufficient input validation is performed before calling
18 */
19
20#include "securecutil.h"
21
22#define SECUREC_MEMSET_PARAM_OK(dest, destMax, count) (SECUREC_LIKELY((destMax) <= SECUREC_MEM_MAX_LEN && \
23    (dest) != NULL && (count) <= (destMax)))
24
25#if SECUREC_WITH_PERFORMANCE_ADDONS
26
27/* Use union to clear strict-aliasing warning */
28typedef union {
29    SecStrBuf32 buf32;
30    SecStrBuf31 buf31;
31    SecStrBuf30 buf30;
32    SecStrBuf29 buf29;
33    SecStrBuf28 buf28;
34    SecStrBuf27 buf27;
35    SecStrBuf26 buf26;
36    SecStrBuf25 buf25;
37    SecStrBuf24 buf24;
38    SecStrBuf23 buf23;
39    SecStrBuf22 buf22;
40    SecStrBuf21 buf21;
41    SecStrBuf20 buf20;
42    SecStrBuf19 buf19;
43    SecStrBuf18 buf18;
44    SecStrBuf17 buf17;
45    SecStrBuf16 buf16;
46    SecStrBuf15 buf15;
47    SecStrBuf14 buf14;
48    SecStrBuf13 buf13;
49    SecStrBuf12 buf12;
50    SecStrBuf11 buf11;
51    SecStrBuf10 buf10;
52    SecStrBuf9 buf9;
53    SecStrBuf8 buf8;
54    SecStrBuf7 buf7;
55    SecStrBuf6 buf6;
56    SecStrBuf5 buf5;
57    SecStrBuf4 buf4;
58    SecStrBuf3 buf3;
59    SecStrBuf2 buf2;
60} SecStrBuf32Union;
61/* C standard initializes the first member of the consortium. */
62static const SecStrBuf32 g_allZero = {{
63    0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U,
64    0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U,
65    0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U,
66    0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U
67}};
68static const SecStrBuf32 g_allFF = {{
69    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
70    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
71    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
72    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
73}};
74
75/* Clear conversion warning strict aliasing" */
76SECUREC_INLINE const SecStrBuf32Union *SecStrictAliasingCast(const SecStrBuf32 *buf)
77{
78    return (const SecStrBuf32Union *)buf;
79}
80
81#ifndef SECUREC_MEMSET_THRESHOLD_SIZE
82#define SECUREC_MEMSET_THRESHOLD_SIZE 32UL
83#endif
84
85#define SECUREC_UNALIGNED_SET(dest, c, count) do { \
86    unsigned char *pDest_ = (unsigned char *)(dest); \
87    switch (count) { \
88        case 32: \
89            *(pDest_++) = (unsigned char)(c); \
90            /* fall-through */ /* FALLTHRU */ \
91        case 31: \
92            *(pDest_++) = (unsigned char)(c); \
93            /* fall-through */ /* FALLTHRU */ \
94        case 30: \
95            *(pDest_++) = (unsigned char)(c); \
96            /* fall-through */ /* FALLTHRU */ \
97        case 29: \
98            *(pDest_++) = (unsigned char)(c); \
99            /* fall-through */ /* FALLTHRU */ \
100        case 28: \
101            *(pDest_++) = (unsigned char)(c); \
102            /* fall-through */ /* FALLTHRU */ \
103        case 27: \
104            *(pDest_++) = (unsigned char)(c); \
105            /* fall-through */ /* FALLTHRU */ \
106        case 26: \
107            *(pDest_++) = (unsigned char)(c); \
108            /* fall-through */ /* FALLTHRU */ \
109        case 25: \
110            *(pDest_++) = (unsigned char)(c); \
111            /* fall-through */ /* FALLTHRU */ \
112        case 24: \
113            *(pDest_++) = (unsigned char)(c); \
114            /* fall-through */ /* FALLTHRU */ \
115        case 23: \
116            *(pDest_++) = (unsigned char)(c); \
117            /* fall-through */ /* FALLTHRU */ \
118        case 22: \
119            *(pDest_++) = (unsigned char)(c); \
120            /* fall-through */ /* FALLTHRU */ \
121        case 21: \
122            *(pDest_++) = (unsigned char)(c); \
123            /* fall-through */ /* FALLTHRU */ \
124        case 20: \
125            *(pDest_++) = (unsigned char)(c); \
126            /* fall-through */ /* FALLTHRU */ \
127        case 19: \
128            *(pDest_++) = (unsigned char)(c); \
129            /* fall-through */ /* FALLTHRU */ \
130        case 18: \
131            *(pDest_++) = (unsigned char)(c); \
132            /* fall-through */ /* FALLTHRU */ \
133        case 17: \
134            *(pDest_++) = (unsigned char)(c); \
135            /* fall-through */ /* FALLTHRU */ \
136        case 16: \
137            *(pDest_++) = (unsigned char)(c); \
138            /* fall-through */ /* FALLTHRU */ \
139        case 15: \
140            *(pDest_++) = (unsigned char)(c); \
141            /* fall-through */ /* FALLTHRU */ \
142        case 14: \
143            *(pDest_++) = (unsigned char)(c); \
144            /* fall-through */ /* FALLTHRU */ \
145        case 13: \
146            *(pDest_++) = (unsigned char)(c); \
147            /* fall-through */ /* FALLTHRU */ \
148        case 12: \
149            *(pDest_++) = (unsigned char)(c); \
150            /* fall-through */ /* FALLTHRU */ \
151        case 11: \
152            *(pDest_++) = (unsigned char)(c); \
153            /* fall-through */ /* FALLTHRU */ \
154        case 10: \
155            *(pDest_++) = (unsigned char)(c); \
156            /* fall-through */ /* FALLTHRU */ \
157        case 9: \
158            *(pDest_++) = (unsigned char)(c); \
159            /* fall-through */ /* FALLTHRU */ \
160        case 8: \
161            *(pDest_++) = (unsigned char)(c); \
162            /* fall-through */ /* FALLTHRU */ \
163        case 7: \
164            *(pDest_++) = (unsigned char)(c); \
165            /* fall-through */ /* FALLTHRU */ \
166        case 6: \
167            *(pDest_++) = (unsigned char)(c); \
168            /* fall-through */ /* FALLTHRU */ \
169        case 5: \
170            *(pDest_++) = (unsigned char)(c); \
171            /* fall-through */ /* FALLTHRU */ \
172        case 4: \
173            *(pDest_++) = (unsigned char)(c); \
174            /* fall-through */ /* FALLTHRU */ \
175        case 3: \
176            *(pDest_++) = (unsigned char)(c); \
177            /* fall-through */ /* FALLTHRU */ \
178        case 2: \
179            *(pDest_++) = (unsigned char)(c); \
180            /* fall-through */ /* FALLTHRU */ \
181        case 1: \
182            *(pDest_++) = (unsigned char)(c); \
183            /* fall-through */ /* FALLTHRU */ \
184        default: \
185            /* Do nothing */ \
186            break; \
187    } \
188} SECUREC_WHILE_ZERO
189
190#define SECUREC_SET_VALUE_BY_STRUCT(dest, dataName, n) do { \
191    *(SecStrBuf##n *)(dest) = *(const SecStrBuf##n *)(&((SecStrictAliasingCast(&(dataName)))->buf##n)); \
192} SECUREC_WHILE_ZERO
193
194#define SECUREC_ALIGNED_SET_OPT_ZERO_FF(dest, c, count) do { \
195    switch (c) { \
196        case 0: \
197            switch (count) { \
198                case 1: \
199                    *(unsigned char *)(dest) = (unsigned char)0; \
200                    break; \
201                case 2: \
202                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 2); \
203                    break; \
204                case 3: \
205                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 3); \
206                    break; \
207                case 4: \
208                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 4); \
209                    break; \
210                case 5: \
211                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 5); \
212                    break; \
213                case 6: \
214                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 6); \
215                    break; \
216                case 7: \
217                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 7); \
218                    break; \
219                case 8: \
220                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 8); \
221                    break; \
222                case 9: \
223                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 9); \
224                    break; \
225                case 10: \
226                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 10); \
227                    break; \
228                case 11: \
229                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 11); \
230                    break; \
231                case 12: \
232                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 12); \
233                    break; \
234                case 13: \
235                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 13); \
236                    break; \
237                case 14: \
238                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 14); \
239                    break; \
240                case 15: \
241                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 15); \
242                    break; \
243                case 16: \
244                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 16); \
245                    break; \
246                case 17: \
247                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 17); \
248                    break; \
249                case 18: \
250                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 18); \
251                    break; \
252                case 19: \
253                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 19); \
254                    break; \
255                case 20: \
256                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 20); \
257                    break; \
258                case 21: \
259                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 21); \
260                    break; \
261                case 22: \
262                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 22); \
263                    break; \
264                case 23: \
265                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 23); \
266                    break; \
267                case 24: \
268                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 24); \
269                    break; \
270                case 25: \
271                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 25); \
272                    break; \
273                case 26: \
274                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 26); \
275                    break; \
276                case 27: \
277                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 27); \
278                    break; \
279                case 28: \
280                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 28); \
281                    break; \
282                case 29: \
283                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 29); \
284                    break; \
285                case 30: \
286                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 30); \
287                    break; \
288                case 31: \
289                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 31); \
290                    break; \
291                case 32: \
292                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allZero, 32); \
293                    break; \
294                default: \
295                    /* Do nothing */ \
296                    break; \
297            } \
298            break; \
299        case 0xFF: \
300            switch (count) { \
301                case 1: \
302                    *(unsigned char *)(dest) = (unsigned char)0xffU; \
303                    break; \
304                case 2: \
305                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 2); \
306                    break; \
307                case 3: \
308                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 3); \
309                    break; \
310                case 4: \
311                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 4); \
312                    break; \
313                case 5: \
314                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 5); \
315                    break; \
316                case 6: \
317                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 6); \
318                    break; \
319                case 7: \
320                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 7); \
321                    break; \
322                case 8: \
323                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 8); \
324                    break; \
325                case 9: \
326                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 9); \
327                    break; \
328                case 10: \
329                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 10); \
330                    break; \
331                case 11: \
332                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 11); \
333                    break; \
334                case 12: \
335                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 12); \
336                    break; \
337                case 13: \
338                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 13); \
339                    break; \
340                case 14: \
341                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 14); \
342                    break; \
343                case 15: \
344                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 15); \
345                    break; \
346                case 16: \
347                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 16); \
348                    break; \
349                case 17: \
350                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 17); \
351                    break; \
352                case 18: \
353                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 18); \
354                    break; \
355                case 19: \
356                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 19); \
357                    break; \
358                case 20: \
359                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 20); \
360                    break; \
361                case 21: \
362                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 21); \
363                    break; \
364                case 22: \
365                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 22); \
366                    break; \
367                case 23: \
368                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 23); \
369                    break; \
370                case 24: \
371                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 24); \
372                    break; \
373                case 25: \
374                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 25); \
375                    break; \
376                case 26: \
377                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 26); \
378                    break; \
379                case 27: \
380                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 27); \
381                    break; \
382                case 28: \
383                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 28); \
384                    break; \
385                case 29: \
386                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 29); \
387                    break; \
388                case 30: \
389                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 30); \
390                    break; \
391                case 31: \
392                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 31); \
393                    break; \
394                case 32: \
395                    SECUREC_SET_VALUE_BY_STRUCT((dest), g_allFF, 32); \
396                    break; \
397                default: \
398                    /* Do nothing */ \
399                    break; \
400            } \
401            break; \
402        default: \
403            SECUREC_UNALIGNED_SET((dest), (c), (count)); \
404            break; \
405    } /* END switch */ \
406} SECUREC_WHILE_ZERO
407
408#define SECUREC_SMALL_MEM_SET(dest, c, count) do { \
409    if (SECUREC_ADDR_ALIGNED_8((dest))) { \
410        SECUREC_ALIGNED_SET_OPT_ZERO_FF((dest), (c), (count)); \
411    } else { \
412        SECUREC_UNALIGNED_SET((dest), (c), (count)); \
413    } \
414} SECUREC_WHILE_ZERO
415
416/*
417 * Performance optimization
418 */
419#define SECUREC_MEMSET_OPT(dest, c, count) do { \
420    if ((count) > SECUREC_MEMSET_THRESHOLD_SIZE) { \
421        SECUREC_MEMSET_PREVENT_DSE((dest), (c), (count)); \
422    } else { \
423        SECUREC_SMALL_MEM_SET((dest), (c), (count)); \
424    } \
425} SECUREC_WHILE_ZERO
426#endif
427
428/*
429 * Handling errors
430 */
431SECUREC_INLINE errno_t SecMemsetError(void *dest, size_t destMax, int c)
432{
433    /* Check destMax is 0 compatible with _sp macro */
434    if (destMax == 0 || destMax > SECUREC_MEM_MAX_LEN) {
435        SECUREC_ERROR_INVALID_RANGE("memset_s");
436        return ERANGE;
437    }
438    if (dest == NULL) {
439        SECUREC_ERROR_INVALID_PARAMTER("memset_s");
440        return EINVAL;
441    }
442    SECUREC_MEMSET_PREVENT_DSE(dest, c, destMax); /* Set entire buffer to value c */
443    SECUREC_ERROR_INVALID_RANGE("memset_s");
444    return ERANGE_AND_RESET;
445}
446
447/*
448 * <FUNCTION DESCRIPTION>
449 *    The memset_s function copies the value of c (converted to an unsigned char)
450 *     into each of the first count characters of the object pointed to by dest.
451 *
452 * <INPUT PARAMETERS>
453 *    dest                Pointer to destination.
454 *    destMax             The size of the buffer.
455 *    c                   Character to set.
456 *    count               Number of characters.
457 *
458 * <OUTPUT PARAMETERS>
459 *    dest buffer         is updated.
460 *
461 * <RETURN VALUE>
462 *    EOK                 Success
463 *    EINVAL              dest == NULL and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN
464 *    ERANGE              destMax > SECUREC_MEM_MAX_LEN or (destMax is 0 and count > destMax)
465 *    ERANGE_AND_RESET    count > destMax and destMax != 0 and destMax <= SECUREC_MEM_MAX_LEN and dest != NULL
466 *
467 *    if return ERANGE_AND_RESET then fill dest to c ,fill length is destMax
468 */
469errno_t memset_s(void *dest, size_t destMax, int c, size_t count)
470{
471    if (SECUREC_MEMSET_PARAM_OK(dest, destMax, count)) {
472        SECUREC_MEMSET_PREVENT_DSE(dest, c, count);
473        return EOK;
474    }
475    /* Meet some runtime violation, return error code */
476    return SecMemsetError(dest, destMax, c);
477}
478
479#if SECUREC_EXPORT_KERNEL_SYMBOL
480EXPORT_SYMBOL(memset_s);
481#endif
482
483#if SECUREC_WITH_PERFORMANCE_ADDONS
484/*
485 * Performance optimization
486 */
487errno_t memset_sOptAsm(void *dest, size_t destMax, int c, size_t count)
488{
489    if (SECUREC_MEMSET_PARAM_OK(dest, destMax, count)) {
490        SECUREC_MEMSET_OPT(dest, c, count);
491        return EOK;
492    }
493    /* Meet some runtime violation, return error code */
494    return SecMemsetError(dest, destMax, c);
495}
496
497/*
498 * Performance optimization, trim judgement on "destMax <= SECUREC_MEM_MAX_LEN"
499 */
500errno_t memset_sOptTc(void *dest, size_t destMax, int c, size_t count)
501{
502    if (SECUREC_LIKELY(count <= destMax && dest != NULL)) {
503        SECUREC_MEMSET_OPT(dest, c, count);
504        return EOK;
505    }
506    /* Meet some runtime violation, return error code */
507    return SecMemsetError(dest, destMax, c);
508}
509#endif
510
511