1 /* Copyright (C) 1991-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 /* Mark symbols hidden in static PIE for early self relocation to work.  */
19 #if BUILD_PIE_DEFAULT
20 # pragma GCC visibility push(hidden)
21 #endif
22 #include <errno.h>
23 #include <libc-internal.h>
24 #include <stdbool.h>
25 #include <stdint.h>
26 #include <unistd.h>
27 
28 /* Defined in brk.c.  */
29 extern void *__curbrk;
30 extern int __brk (void *addr);
31 
32 /* Extend the process's data space by INCREMENT.
33    If INCREMENT is negative, shrink data space by - INCREMENT.
34    Return start of new space allocated, or -1 for errors.  */
35 void *
__sbrk(intptr_t increment)36 __sbrk (intptr_t increment)
37 {
38   /* Controls whether __brk (0) is called to read the brk value from
39      the kernel.  */
40   bool update_brk = __curbrk == NULL;
41 
42 #if defined (SHARED) && ! IS_IN (rtld)
43   if (!__libc_initial)
44     {
45       if (increment != 0)
46 	{
47 	  /* Do not allow changing the brk from an inner libc because
48 	     it cannot be synchronized with the outer libc's brk.  */
49 	  __set_errno (ENOMEM);
50 	  return (void *) -1;
51 	}
52       /* Querying the kernel's brk value from an inner namespace is
53 	 fine.  */
54       update_brk = true;
55     }
56 #endif
57 
58   if (update_brk)
59     if (__brk (0) < 0)		/* Initialize the break.  */
60       return (void *) -1;
61 
62   if (increment == 0)
63     return __curbrk;
64 
65   void *oldbrk = __curbrk;
66   if (increment > 0
67       ? ((uintptr_t) oldbrk + (uintptr_t) increment < (uintptr_t) oldbrk)
68       : ((uintptr_t) oldbrk < (uintptr_t) -increment))
69     {
70       __set_errno (ENOMEM);
71       return (void *) -1;
72     }
73 
74   if (__brk (oldbrk + increment) < 0)
75     return (void *) -1;
76 
77   return oldbrk;
78 }
79 libc_hidden_def (__sbrk)
80 weak_alias (__sbrk, sbrk)
81