diff options
author | tedu <> | 2014-07-09 19:11:00 +0000 |
---|---|---|
committer | tedu <> | 2014-07-09 19:11:00 +0000 |
commit | 6b9a0f99def5b0e95e23f0456bdac32ba04e517d (patch) | |
tree | 3bf75ebe719a90fe490000b1ac826edeede14ae3 /src | |
parent | 11a127ccc73e8028c49fcc091006c04dd20830ff (diff) | |
download | openbsd-6b9a0f99def5b0e95e23f0456bdac32ba04e517d.tar.gz openbsd-6b9a0f99def5b0e95e23f0456bdac32ba04e517d.tar.bz2 openbsd-6b9a0f99def5b0e95e23f0456bdac32ba04e517d.zip |
reduce obvious dependency on global g_pool by moving to local aliases
ok otto
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/libc/stdlib/malloc.c | 90 |
1 files changed, 48 insertions, 42 deletions
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c index efb8e76a45..a800ea17be 100644 --- a/src/lib/libc/stdlib/malloc.c +++ b/src/lib/libc/stdlib/malloc.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: malloc.c,v 1.169 2014/06/27 18:17:03 deraadt Exp $ */ | 1 | /* $OpenBSD: malloc.c,v 1.170 2014/07/09 19:11:00 tedu Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2008, 2010, 2011 Otto Moerbeek <otto@drijf.net> | 3 | * Copyright (c) 2008, 2010, 2011 Otto Moerbeek <otto@drijf.net> |
4 | * Copyright (c) 2012 Matthew Dempsky <matthew@openbsd.org> | 4 | * Copyright (c) 2012 Matthew Dempsky <matthew@openbsd.org> |
@@ -167,7 +167,7 @@ struct chunk_info { | |||
167 | }; | 167 | }; |
168 | 168 | ||
169 | struct malloc_readonly { | 169 | struct malloc_readonly { |
170 | struct dir_info *g_pool; /* Main bookkeeping information */ | 170 | struct dir_info *malloc_pool; /* Main bookkeeping information */ |
171 | int malloc_abort; /* abort() on error */ | 171 | int malloc_abort; /* abort() on error */ |
172 | int malloc_freenow; /* Free quickly - disable chunk rnd */ | 172 | int malloc_freenow; /* Free quickly - disable chunk rnd */ |
173 | int malloc_freeunmap; /* mprotect free pages PROT_NONE? */ | 173 | int malloc_freeunmap; /* mprotect free pages PROT_NONE? */ |
@@ -181,7 +181,7 @@ struct malloc_readonly { | |||
181 | #ifdef MALLOC_STATS | 181 | #ifdef MALLOC_STATS |
182 | int malloc_stats; /* dump statistics at end */ | 182 | int malloc_stats; /* dump statistics at end */ |
183 | #endif | 183 | #endif |
184 | u_int32_t malloc_canary; /* Matched against ones in g_pool */ | 184 | u_int32_t malloc_canary; /* Matched against ones in malloc_pool */ |
185 | }; | 185 | }; |
186 | 186 | ||
187 | /* This object is mapped PROT_READ after initialisation to prevent tampering */ | 187 | /* This object is mapped PROT_READ after initialisation to prevent tampering */ |
@@ -190,7 +190,7 @@ static union { | |||
190 | u_char _pad[MALLOC_PAGESIZE]; | 190 | u_char _pad[MALLOC_PAGESIZE]; |
191 | } malloc_readonly __attribute__((aligned(MALLOC_PAGESIZE))); | 191 | } malloc_readonly __attribute__((aligned(MALLOC_PAGESIZE))); |
192 | #define mopts malloc_readonly.mopts | 192 | #define mopts malloc_readonly.mopts |
193 | #define g_pool mopts.g_pool | 193 | #define getpool() mopts.malloc_pool |
194 | 194 | ||
195 | char *malloc_options; /* compile-time options */ | 195 | char *malloc_options; /* compile-time options */ |
196 | static char *malloc_func; /* current function */ | 196 | static char *malloc_func; /* current function */ |
@@ -794,7 +794,7 @@ delete(struct dir_info *d, struct region_info *ri) | |||
794 | if (d->regions_total & (d->regions_total - 1)) | 794 | if (d->regions_total & (d->regions_total - 1)) |
795 | wrterror("regions_total not 2^x", NULL); | 795 | wrterror("regions_total not 2^x", NULL); |
796 | d->regions_free++; | 796 | d->regions_free++; |
797 | STATS_INC(g_pool->deletes); | 797 | STATS_INC(getpool()->deletes); |
798 | 798 | ||
799 | i = ri - d->r; | 799 | i = ri - d->r; |
800 | for (;;) { | 800 | for (;;) { |
@@ -810,7 +810,7 @@ delete(struct dir_info *d, struct region_info *ri) | |||
810 | (j < i && i <= r)) | 810 | (j < i && i <= r)) |
811 | continue; | 811 | continue; |
812 | d->r[j] = d->r[i]; | 812 | d->r[j] = d->r[i]; |
813 | STATS_INC(g_pool->delete_moves); | 813 | STATS_INC(getpool()->delete_moves); |
814 | break; | 814 | break; |
815 | } | 815 | } |
816 | 816 | ||
@@ -1046,6 +1046,7 @@ free_bytes(struct dir_info *d, struct region_info *r, void *ptr) | |||
1046 | static void * | 1046 | static void * |
1047 | omalloc(size_t sz, int zero_fill, void *f) | 1047 | omalloc(size_t sz, int zero_fill, void *f) |
1048 | { | 1048 | { |
1049 | struct dir_info *pool = getpool(); | ||
1049 | void *p; | 1050 | void *p; |
1050 | size_t psz; | 1051 | size_t psz; |
1051 | 1052 | ||
@@ -1056,13 +1057,13 @@ omalloc(size_t sz, int zero_fill, void *f) | |||
1056 | } | 1057 | } |
1057 | sz += mopts.malloc_guard; | 1058 | sz += mopts.malloc_guard; |
1058 | psz = PAGEROUND(sz); | 1059 | psz = PAGEROUND(sz); |
1059 | p = map(g_pool, psz, zero_fill); | 1060 | p = map(pool, psz, zero_fill); |
1060 | if (p == MAP_FAILED) { | 1061 | if (p == MAP_FAILED) { |
1061 | errno = ENOMEM; | 1062 | errno = ENOMEM; |
1062 | return NULL; | 1063 | return NULL; |
1063 | } | 1064 | } |
1064 | if (insert(g_pool, p, sz, f)) { | 1065 | if (insert(pool, p, sz, f)) { |
1065 | unmap(g_pool, p, psz); | 1066 | unmap(pool, p, psz); |
1066 | errno = ENOMEM; | 1067 | errno = ENOMEM; |
1067 | return NULL; | 1068 | return NULL; |
1068 | } | 1069 | } |
@@ -1070,7 +1071,7 @@ omalloc(size_t sz, int zero_fill, void *f) | |||
1070 | if (mprotect((char *)p + psz - mopts.malloc_guard, | 1071 | if (mprotect((char *)p + psz - mopts.malloc_guard, |
1071 | mopts.malloc_guard, PROT_NONE)) | 1072 | mopts.malloc_guard, PROT_NONE)) |
1072 | wrterror("mprotect", NULL); | 1073 | wrterror("mprotect", NULL); |
1073 | STATS_ADD(g_pool->malloc_guarded, mopts.malloc_guard); | 1074 | STATS_ADD(pool->malloc_guarded, mopts.malloc_guard); |
1074 | } | 1075 | } |
1075 | 1076 | ||
1076 | if (mopts.malloc_move && | 1077 | if (mopts.malloc_move && |
@@ -1098,7 +1099,7 @@ omalloc(size_t sz, int zero_fill, void *f) | |||
1098 | 1099 | ||
1099 | } else { | 1100 | } else { |
1100 | /* takes care of SOME_JUNK */ | 1101 | /* takes care of SOME_JUNK */ |
1101 | p = malloc_bytes(g_pool, sz, f); | 1102 | p = malloc_bytes(pool, sz, f); |
1102 | if (zero_fill && p != NULL && sz > 0) | 1103 | if (zero_fill && p != NULL && sz > 0) |
1103 | memset(p, 0, sz); | 1104 | memset(p, 0, sz); |
1104 | } | 1105 | } |
@@ -1128,7 +1129,7 @@ malloc_recurse(void) | |||
1128 | static int | 1129 | static int |
1129 | malloc_init(void) | 1130 | malloc_init(void) |
1130 | { | 1131 | { |
1131 | if (omalloc_init(&g_pool)) { | 1132 | if (omalloc_init(&mopts.malloc_pool)) { |
1132 | _MALLOC_UNLOCK(); | 1133 | _MALLOC_UNLOCK(); |
1133 | if (mopts.malloc_xmalloc) | 1134 | if (mopts.malloc_xmalloc) |
1134 | wrterror("out of memory", NULL); | 1135 | wrterror("out of memory", NULL); |
@@ -1146,10 +1147,11 @@ malloc(size_t size) | |||
1146 | 1147 | ||
1147 | _MALLOC_LOCK(); | 1148 | _MALLOC_LOCK(); |
1148 | malloc_func = "malloc():"; | 1149 | malloc_func = "malloc():"; |
1149 | if (g_pool == NULL) { | 1150 | if (getpool() == NULL) { |
1150 | if (malloc_init() != 0) | 1151 | if (malloc_init() != 0) |
1151 | return NULL; | 1152 | return NULL; |
1152 | } | 1153 | } |
1154 | |||
1153 | if (malloc_active++) { | 1155 | if (malloc_active++) { |
1154 | malloc_recurse(); | 1156 | malloc_recurse(); |
1155 | return NULL; | 1157 | return NULL; |
@@ -1169,10 +1171,11 @@ malloc(size_t size) | |||
1169 | static void | 1171 | static void |
1170 | ofree(void *p) | 1172 | ofree(void *p) |
1171 | { | 1173 | { |
1174 | struct dir_info *pool = getpool(); | ||
1172 | struct region_info *r; | 1175 | struct region_info *r; |
1173 | size_t sz; | 1176 | size_t sz; |
1174 | 1177 | ||
1175 | r = find(g_pool, p); | 1178 | r = find(pool, p); |
1176 | if (r == NULL) { | 1179 | if (r == NULL) { |
1177 | wrterror("bogus pointer (double free?)", p); | 1180 | wrterror("bogus pointer (double free?)", p); |
1178 | return; | 1181 | return; |
@@ -1204,15 +1207,15 @@ ofree(void *p) | |||
1204 | PROT_READ | PROT_WRITE)) | 1207 | PROT_READ | PROT_WRITE)) |
1205 | wrterror("mprotect", NULL); | 1208 | wrterror("mprotect", NULL); |
1206 | } | 1209 | } |
1207 | STATS_SUB(g_pool->malloc_guarded, mopts.malloc_guard); | 1210 | STATS_SUB(pool->malloc_guarded, mopts.malloc_guard); |
1208 | } | 1211 | } |
1209 | if (mopts.malloc_junk && !mopts.malloc_freeunmap) { | 1212 | if (mopts.malloc_junk && !mopts.malloc_freeunmap) { |
1210 | size_t amt = mopts.malloc_junk == 1 ? MALLOC_MAXCHUNK : | 1213 | size_t amt = mopts.malloc_junk == 1 ? MALLOC_MAXCHUNK : |
1211 | PAGEROUND(sz) - mopts.malloc_guard; | 1214 | PAGEROUND(sz) - mopts.malloc_guard; |
1212 | memset(p, SOME_FREEJUNK, amt); | 1215 | memset(p, SOME_FREEJUNK, amt); |
1213 | } | 1216 | } |
1214 | unmap(g_pool, p, PAGEROUND(sz)); | 1217 | unmap(pool, p, PAGEROUND(sz)); |
1215 | delete(g_pool, r); | 1218 | delete(pool, r); |
1216 | } else { | 1219 | } else { |
1217 | void *tmp; | 1220 | void *tmp; |
1218 | int i; | 1221 | int i; |
@@ -1220,24 +1223,24 @@ ofree(void *p) | |||
1220 | if (mopts.malloc_junk && sz > 0) | 1223 | if (mopts.malloc_junk && sz > 0) |
1221 | memset(p, SOME_FREEJUNK, sz); | 1224 | memset(p, SOME_FREEJUNK, sz); |
1222 | if (!mopts.malloc_freenow) { | 1225 | if (!mopts.malloc_freenow) { |
1223 | if (find_chunknum(g_pool, r, p) == -1) | 1226 | if (find_chunknum(pool, r, p) == -1) |
1224 | return; | 1227 | return; |
1225 | i = getrbyte(g_pool) & MALLOC_DELAYED_CHUNK_MASK; | 1228 | i = getrbyte(pool) & MALLOC_DELAYED_CHUNK_MASK; |
1226 | tmp = p; | 1229 | tmp = p; |
1227 | p = g_pool->delayed_chunks[i]; | 1230 | p = pool->delayed_chunks[i]; |
1228 | if (tmp == p) { | 1231 | if (tmp == p) { |
1229 | wrterror("double free", p); | 1232 | wrterror("double free", p); |
1230 | return; | 1233 | return; |
1231 | } | 1234 | } |
1232 | g_pool->delayed_chunks[i] = tmp; | 1235 | pool->delayed_chunks[i] = tmp; |
1233 | } | 1236 | } |
1234 | if (p != NULL) { | 1237 | if (p != NULL) { |
1235 | r = find(g_pool, p); | 1238 | r = find(pool, p); |
1236 | if (r == NULL) { | 1239 | if (r == NULL) { |
1237 | wrterror("bogus pointer (double free?)", p); | 1240 | wrterror("bogus pointer (double free?)", p); |
1238 | return; | 1241 | return; |
1239 | } | 1242 | } |
1240 | free_bytes(g_pool, r, p); | 1243 | free_bytes(pool, r, p); |
1241 | } | 1244 | } |
1242 | } | 1245 | } |
1243 | } | 1246 | } |
@@ -1253,7 +1256,7 @@ free(void *ptr) | |||
1253 | 1256 | ||
1254 | _MALLOC_LOCK(); | 1257 | _MALLOC_LOCK(); |
1255 | malloc_func = "free():"; | 1258 | malloc_func = "free():"; |
1256 | if (g_pool == NULL) { | 1259 | if (getpool() == NULL) { |
1257 | _MALLOC_UNLOCK(); | 1260 | _MALLOC_UNLOCK(); |
1258 | wrterror("free() called before allocation", NULL); | 1261 | wrterror("free() called before allocation", NULL); |
1259 | return; | 1262 | return; |
@@ -1272,6 +1275,7 @@ free(void *ptr) | |||
1272 | static void * | 1275 | static void * |
1273 | orealloc(void *p, size_t newsz, void *f) | 1276 | orealloc(void *p, size_t newsz, void *f) |
1274 | { | 1277 | { |
1278 | struct dir_info *pool = getpool(); | ||
1275 | struct region_info *r; | 1279 | struct region_info *r; |
1276 | size_t oldsz, goldsz, gnewsz; | 1280 | size_t oldsz, goldsz, gnewsz; |
1277 | void *q; | 1281 | void *q; |
@@ -1279,7 +1283,7 @@ orealloc(void *p, size_t newsz, void *f) | |||
1279 | if (p == NULL) | 1283 | if (p == NULL) |
1280 | return omalloc(newsz, 0, f); | 1284 | return omalloc(newsz, 0, f); |
1281 | 1285 | ||
1282 | r = find(g_pool, p); | 1286 | r = find(pool, p); |
1283 | if (r == NULL) { | 1287 | if (r == NULL) { |
1284 | wrterror("bogus pointer (double free?)", p); | 1288 | wrterror("bogus pointer (double free?)", p); |
1285 | return NULL; | 1289 | return NULL; |
@@ -1311,20 +1315,20 @@ orealloc(void *p, size_t newsz, void *f) | |||
1311 | void *hint = (char *)p + roldsz; | 1315 | void *hint = (char *)p + roldsz; |
1312 | size_t needed = rnewsz - roldsz; | 1316 | size_t needed = rnewsz - roldsz; |
1313 | 1317 | ||
1314 | STATS_INC(g_pool->cheap_realloc_tries); | 1318 | STATS_INC(pool->cheap_realloc_tries); |
1315 | zapcacheregion(g_pool, hint, needed); | 1319 | zapcacheregion(pool, hint, needed); |
1316 | q = MQUERY(hint, needed); | 1320 | q = MQUERY(hint, needed); |
1317 | if (q == hint) | 1321 | if (q == hint) |
1318 | q = MMAPA(hint, needed); | 1322 | q = MMAPA(hint, needed); |
1319 | else | 1323 | else |
1320 | q = MAP_FAILED; | 1324 | q = MAP_FAILED; |
1321 | if (q == hint) { | 1325 | if (q == hint) { |
1322 | STATS_ADD(g_pool->malloc_used, needed); | 1326 | STATS_ADD(pool->malloc_used, needed); |
1323 | if (mopts.malloc_junk == 2) | 1327 | if (mopts.malloc_junk == 2) |
1324 | memset(q, SOME_JUNK, needed); | 1328 | memset(q, SOME_JUNK, needed); |
1325 | r->size = newsz; | 1329 | r->size = newsz; |
1326 | STATS_SETF(r, f); | 1330 | STATS_SETF(r, f); |
1327 | STATS_INC(g_pool->cheap_reallocs); | 1331 | STATS_INC(pool->cheap_reallocs); |
1328 | return p; | 1332 | return p; |
1329 | } else if (q != MAP_FAILED) { | 1333 | } else if (q != MAP_FAILED) { |
1330 | if (munmap(q, needed)) | 1334 | if (munmap(q, needed)) |
@@ -1342,7 +1346,7 @@ orealloc(void *p, size_t newsz, void *f) | |||
1342 | PROT_NONE)) | 1346 | PROT_NONE)) |
1343 | wrterror("mprotect", NULL); | 1347 | wrterror("mprotect", NULL); |
1344 | } | 1348 | } |
1345 | unmap(g_pool, (char *)p + rnewsz, roldsz - rnewsz); | 1349 | unmap(pool, (char *)p + rnewsz, roldsz - rnewsz); |
1346 | r->size = gnewsz; | 1350 | r->size = gnewsz; |
1347 | STATS_SETF(r, f); | 1351 | STATS_SETF(r, f); |
1348 | return p; | 1352 | return p; |
@@ -1382,7 +1386,7 @@ realloc(void *ptr, size_t size) | |||
1382 | 1386 | ||
1383 | _MALLOC_LOCK(); | 1387 | _MALLOC_LOCK(); |
1384 | malloc_func = "realloc():"; | 1388 | malloc_func = "realloc():"; |
1385 | if (g_pool == NULL) { | 1389 | if (getpool() == NULL) { |
1386 | if (malloc_init() != 0) | 1390 | if (malloc_init() != 0) |
1387 | return NULL; | 1391 | return NULL; |
1388 | } | 1392 | } |
@@ -1418,7 +1422,7 @@ calloc(size_t nmemb, size_t size) | |||
1418 | 1422 | ||
1419 | _MALLOC_LOCK(); | 1423 | _MALLOC_LOCK(); |
1420 | malloc_func = "calloc():"; | 1424 | malloc_func = "calloc():"; |
1421 | if (g_pool == NULL) { | 1425 | if (getpool() == NULL) { |
1422 | if (malloc_init() != 0) | 1426 | if (malloc_init() != 0) |
1423 | return NULL; | 1427 | return NULL; |
1424 | } | 1428 | } |
@@ -1491,6 +1495,7 @@ mapalign(struct dir_info *d, size_t alignment, size_t sz, int zero_fill) | |||
1491 | static void * | 1495 | static void * |
1492 | omemalign(size_t alignment, size_t sz, int zero_fill, void *f) | 1496 | omemalign(size_t alignment, size_t sz, int zero_fill, void *f) |
1493 | { | 1497 | { |
1498 | struct dir_info *pool = getpool(); | ||
1494 | size_t psz; | 1499 | size_t psz; |
1495 | void *p; | 1500 | void *p; |
1496 | 1501 | ||
@@ -1512,14 +1517,14 @@ omemalign(size_t alignment, size_t sz, int zero_fill, void *f) | |||
1512 | sz += mopts.malloc_guard; | 1517 | sz += mopts.malloc_guard; |
1513 | psz = PAGEROUND(sz); | 1518 | psz = PAGEROUND(sz); |
1514 | 1519 | ||
1515 | p = mapalign(g_pool, alignment, psz, zero_fill); | 1520 | p = mapalign(pool, alignment, psz, zero_fill); |
1516 | if (p == NULL) { | 1521 | if (p == NULL) { |
1517 | errno = ENOMEM; | 1522 | errno = ENOMEM; |
1518 | return NULL; | 1523 | return NULL; |
1519 | } | 1524 | } |
1520 | 1525 | ||
1521 | if (insert(g_pool, p, sz, f)) { | 1526 | if (insert(pool, p, sz, f)) { |
1522 | unmap(g_pool, p, psz); | 1527 | unmap(pool, p, psz); |
1523 | errno = ENOMEM; | 1528 | errno = ENOMEM; |
1524 | return NULL; | 1529 | return NULL; |
1525 | } | 1530 | } |
@@ -1528,7 +1533,7 @@ omemalign(size_t alignment, size_t sz, int zero_fill, void *f) | |||
1528 | if (mprotect((char *)p + psz - mopts.malloc_guard, | 1533 | if (mprotect((char *)p + psz - mopts.malloc_guard, |
1529 | mopts.malloc_guard, PROT_NONE)) | 1534 | mopts.malloc_guard, PROT_NONE)) |
1530 | wrterror("mprotect", NULL); | 1535 | wrterror("mprotect", NULL); |
1531 | STATS_ADD(g_pool->malloc_guarded, mopts.malloc_guard); | 1536 | STATS_ADD(pool->malloc_guarded, mopts.malloc_guard); |
1532 | } | 1537 | } |
1533 | 1538 | ||
1534 | if (mopts.malloc_junk == 2) { | 1539 | if (mopts.malloc_junk == 2) { |
@@ -1554,7 +1559,7 @@ posix_memalign(void **memptr, size_t alignment, size_t size) | |||
1554 | 1559 | ||
1555 | _MALLOC_LOCK(); | 1560 | _MALLOC_LOCK(); |
1556 | malloc_func = "posix_memalign():"; | 1561 | malloc_func = "posix_memalign():"; |
1557 | if (g_pool == NULL) { | 1562 | if (getpool() == NULL) { |
1558 | if (malloc_init() != 0) | 1563 | if (malloc_init() != 0) |
1559 | goto err; | 1564 | goto err; |
1560 | } | 1565 | } |
@@ -1804,24 +1809,25 @@ malloc_dump1(int fd, struct dir_info *d) | |||
1804 | void | 1809 | void |
1805 | malloc_dump(int fd) | 1810 | malloc_dump(int fd) |
1806 | { | 1811 | { |
1812 | struct dir_info *pool = getpool(); | ||
1807 | int i; | 1813 | int i; |
1808 | void *p; | 1814 | void *p; |
1809 | struct region_info *r; | 1815 | struct region_info *r; |
1810 | int saved_errno = errno; | 1816 | int saved_errno = errno; |
1811 | 1817 | ||
1812 | for (i = 0; i < MALLOC_DELAYED_CHUNK_MASK + 1; i++) { | 1818 | for (i = 0; i < MALLOC_DELAYED_CHUNK_MASK + 1; i++) { |
1813 | p = g_pool->delayed_chunks[i]; | 1819 | p = pool->delayed_chunks[i]; |
1814 | if (p == NULL) | 1820 | if (p == NULL) |
1815 | continue; | 1821 | continue; |
1816 | r = find(g_pool, p); | 1822 | r = find(pool, p); |
1817 | if (r == NULL) | 1823 | if (r == NULL) |
1818 | wrterror("bogus pointer in malloc_dump", p); | 1824 | wrterror("bogus pointer in malloc_dump", p); |
1819 | free_bytes(g_pool, r, p); | 1825 | free_bytes(pool, r, p); |
1820 | g_pool->delayed_chunks[i] = NULL; | 1826 | pool->delayed_chunks[i] = NULL; |
1821 | } | 1827 | } |
1822 | /* XXX leak when run multiple times */ | 1828 | /* XXX leak when run multiple times */ |
1823 | RB_INIT(&leakhead); | 1829 | RB_INIT(&leakhead); |
1824 | malloc_dump1(fd, g_pool); | 1830 | malloc_dump1(fd, pool); |
1825 | errno = saved_errno; | 1831 | errno = saved_errno; |
1826 | } | 1832 | } |
1827 | 1833 | ||