Bug Summary

File:obj-scan-build/tmpfs/../../tmpfs/node.c
Location:line 238, column 19
Description:Call to 'alloca' has an allocation size of 0 bytes

Annotated Source Code

1/* Node state and file contents for tmpfs.
2 Copyright (C) 2000,01,02 Free Software Foundation, Inc.
3
4This file is part of the GNU Hurd.
5
6The GNU Hurd is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11The GNU Hurd is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with the GNU Hurd; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "tmpfs.h"
21#include <stddef.h>
22#include <stdlib.h>
23#include <fcntl.h>
24#include <hurd/hurd_types.h>
25#include <hurd/store.h>
26#include "default_pager_U.h"
27
28unsigned int num_files;
29static unsigned int gen;
30
31struct node *all_nodes;
32
33error_t
34diskfs_alloc_node (struct node *dp, mode_t mode, struct node **npp)
35{
36 struct disknode *dn;
37
38 dn = calloc (1, sizeof *dn);
39 if (dn == 0)
40 return ENOSPC((0x10 << 26) | ((28) & 0x3fff));
41 pthread_spin_lock (&diskfs_node_refcnt_lock);
42 if (round_page (tmpfs_space_used + sizeof *dn)((((vm_offset_t) (tmpfs_space_used + sizeof *dn) + __vm_page_size
- 1) / __vm_page_size) * __vm_page_size)
/ vm_page_size
43 > tmpfs_page_limit)
44 {
45 pthread_spin_unlock (&diskfs_node_refcnt_lock);
46 free (dn);
47 return ENOSPC((0x10 << 26) | ((28) & 0x3fff));
48 }
49 dn->gen = gen++;
50 ++num_files;
51 tmpfs_space_used += sizeof *dn;
52 pthread_spin_unlock (&diskfs_node_refcnt_lock);
53
54 dn->type = IFTODT (mode & S_IFMT)(((mode & 0170000) & 0170000) >> 12);
55 return diskfs_cached_lookup ((ino_t) (uintptr_t) dn, npp);
56}
57
58void
59diskfs_free_node (struct node *np, mode_t mode)
60{
61 switch (np->dn->type)
62 {
63 case DT_REGDT_REG:
64 if (np->dn->u.reg.memobj != MACH_PORT_NULL((mach_port_t) 0)) {
65 vm_deallocate (mach_task_self ()((__mach_task_self_ + 0)), np->dn->u.reg.memref, 4096);
66 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), np->dn->u.reg.memobj);
67 }
68 break;
69 case DT_DIRDT_DIR:
70 assert (np->dn->u.dir.entries == 0)((np->dn->u.dir.entries == 0) ? (void) (0) : __assert_fail
("np->dn->u.dir.entries == 0", "../../tmpfs/node.c", 70
, __PRETTY_FUNCTION__))
;
71 break;
72 case DT_LNKDT_LNK:
73 free (np->dn->u.lnk);
74 break;
75 }
76 *np->dn->hprevp = np->dn->hnext;
77 if (np->dn->hnext != 0)
78 np->dn->hnext->dn->hprevp = np->dn->hprevp;
79 free (np->dn);
80 np->dn = 0;
81
82 --num_files;
83 tmpfs_space_used -= sizeof *np->dn;
84}
85
86void
87diskfs_node_norefs (struct node *np)
88{
89 if (np->dn != 0)
90 {
91 /* We don't bother to do this in diskfs_write_disknode, since it only
92 ever matters here. The node state goes back into the `struct
93 disknode' while it has no associated diskfs node. */
94
95 np->dn->size = np->dn_stat.st_size;
96 np->dn->mode = np->dn_stat.st_mode;
97 np->dn->nlink = np->dn_stat.st_nlink;
98 np->dn->uid = np->dn_stat.st_uid;
99 np->dn->author = np->dn_stat.st_author;
100 np->dn->gid = np->dn_stat.st_gid;
101 np->dn->atime = np->dn_stat.st_atim;
102 np->dn->mtime = np->dn_stat.st_mtim;
103 np->dn->ctime = np->dn_stat.st_ctim;
104 np->dn->flags = np->dn_stat.st_flags;
105
106 switch (np->dn->type)
107 {
108 case DT_REGDT_REG:
109 assert (np->allocsize % vm_page_size == 0)((np->allocsize % vm_page_size == 0) ? (void) (0) : __assert_fail
("np->allocsize % vm_page_size == 0", "../../tmpfs/node.c"
, 109, __PRETTY_FUNCTION__))
;
110 np->dn->u.reg.allocpages = np->allocsize / vm_page_size;
111 break;
112 case DT_CHRDT_CHR:
113 case DT_BLKDT_BLK:
114 np->dn->u.chr = np->dn_stat.st_rdev;
115 break;
116 }
117
118 /* Remove this node from the cache list rooted at `all_nodes'. */
119 *np->dn->hprevp = np->dn->hnext;
120 if (np->dn->hnext != 0)
121 np->dn->hnext->dn->hprevp = np->dn->hprevp;
122 np->dn->hnext = 0;
123 np->dn->hprevp = 0;
124 }
125
126 free (np);
127}
128
129static void
130recompute_blocks (struct node *np)
131{
132 struct disknode *const dn = np->dn;
133 struct stat *const st = &np->dn_stat;
134
135 st->st_blocks = sizeof *dn + dn->translen;
136 switch (dn->type)
137 {
138 case DT_REGDT_REG:
139 np->allocsize = dn->u.reg.allocpages * vm_page_size;
140 st->st_blocks += np->allocsize;
141 break;
142 case DT_LNKDT_LNK:
143 st->st_blocks += st->st_size + 1;
144 break;
145 case DT_CHRDT_CHR:
146 case DT_BLKDT_BLK:
147 st->st_rdev = dn->u.chr;
148 break;
149 case DT_DIRDT_DIR:
150 st->st_blocks += dn->size;
151 break;
152 }
153 st->st_blocks = (st->st_blocks + 511) / 512;
154}
155
156/* Fetch inode INUM, set *NPP to the node structure;
157 gain one user reference and lock the node. */
158error_t
159diskfs_cached_lookup (ino_t inum, struct node **npp)
160{
161 struct disknode *dn = (void *) (uintptr_t) inum;
162 struct node *np;
163
164 assert (npp)((npp) ? (void) (0) : __assert_fail ("npp", "../../tmpfs/node.c"
, 164, __PRETTY_FUNCTION__))
;
165
166 if (dn->hprevp != 0) /* There is already a node. */
167 {
168 np = *dn->hprevp;
169 assert (np->dn == dn)((np->dn == dn) ? (void) (0) : __assert_fail ("np->dn == dn"
, "../../tmpfs/node.c", 169, __PRETTY_FUNCTION__))
;
170 assert (*dn->hprevp == np)((*dn->hprevp == np) ? (void) (0) : __assert_fail ("*dn->hprevp == np"
, "../../tmpfs/node.c", 170, __PRETTY_FUNCTION__))
;
171
172 diskfs_nref (np);
173 }
174 else
175 /* Create the new node. */
176 {
177 struct stat *st;
178
179 np = diskfs_make_node (dn);
180 np->cache_id = (ino_t) (uintptr_t) dn;
181
182 pthread_spin_lock (&diskfs_node_refcnt_lock);
183 dn->hnext = all_nodes;
184 if (dn->hnext)
185 dn->hnext->dn->hprevp = &dn->hnext;
186 dn->hprevp = &all_nodes;
187 all_nodes = np;
188 pthread_spin_unlock (&diskfs_node_refcnt_lock);
189
190 st = &np->dn_stat;
191 memset (st, 0, sizeof *st);
192 st->st_fstype = FSTYPE_MEMFS0x00000019;
193 st->st_fsid = getpid ();
194 st->st_blksize = vm_page_size;
195
196 st->st_ino = (ino_t) (uintptr_t) dn;
197 st->st_gen = dn->gen;
198
199 st->st_size = dn->size;
200 st->st_mode = dn->mode;
201 st->st_nlink = dn->nlink;
202 st->st_uid = dn->uid;
203 st->st_author = dn->author;
204 st->st_gid = dn->gid;
205 st->st_atim = dn->atime;
206 st->st_mtim = dn->mtime;
207 st->st_ctim = dn->ctime;
208 st->st_flags = dn->flags;
209
210 st->st_rdev = 0;
211 np->allocsize = 0;
212 recompute_blocks (np);
213 }
214
215 pthread_mutex_lock (&np->lock);
216 *npp = np;
217 return 0;
218}
219
220error_t
221diskfs_node_iterate (error_t (*fun) (struct node *))
222{
223 error_t err = 0;
224 unsigned int num_nodes = 0;
225 struct node *node, **node_list, **p;
226
227 pthread_spin_lock (&diskfs_node_refcnt_lock);
228
229 /* We must copy everything from the hash table into another data structure
230 to avoid running into any problems with the hash-table being modified
231 during processing (normally we delegate access to hash-table with
232 diskfs_node_refcnt_lock, but we can't hold this while locking the
233 individual node locks). */
234
235 for (node = all_nodes; node != 0; node = node->dn->hnext)
1
Assuming 'node' is equal to null
2
Loop condition is false. Execution continues on line 238
236 num_nodes++;
237
238 p = node_list = alloca (num_nodes * sizeof (struct node *))__builtin_alloca (num_nodes * sizeof (struct node *));
3
Within the expansion of the macro 'alloca':
a
Call to 'alloca' has an allocation size of 0 bytes
239 for (node = all_nodes; node != 0; node = node->dn->hnext)
240 {
241 *p++ = node;
242 node->references++;
243 }
244
245 pthread_spin_unlock (&diskfs_node_refcnt_lock);
246
247 p = node_list;
248 while (num_nodes-- > 0)
249 {
250 node = *p++;
251 if (!err)
252 {
253 pthread_mutex_lock (&node->lock);
254 err = (*fun) (node);
255 pthread_mutex_unlock (&node->lock);
256 }
257 diskfs_nrele (node);
258 }
259
260 return err;
261}
262
263/* The user must define this function. Node NP has some light
264 references, but has just lost its last hard references. Take steps
265 so that if any light references can be freed, they are. NP is locked
266 as is the pager refcount lock. This function will be called after
267 diskfs_lost_hardrefs. */
268void
269diskfs_try_dropping_softrefs (struct node *np)
270{
271}
272
273/* The user must define this funcction. Node NP has some light
274 references but has just lost its last hard reference. NP is locked. */
275void
276diskfs_lost_hardrefs (struct node *np)
277{
278}
279
280/* The user must define this function. Node NP has just acquired
281 a hard reference where it had none previously. It is thus now
282 OK again to have light references without real users. NP is
283 locked. */
284void
285diskfs_new_hardrefs (struct node *np)
286{
287}
288
289
290
291error_t
292diskfs_get_translator (struct node *np, char **namep, u_int *namelen)
293{
294 *namelen = np->dn->translen;
295 if (*namelen == 0)
296 return 0;
297 *namep = malloc (*namelen);
298 if (*namep == 0)
299 return ENOMEM((0x10 << 26) | ((12) & 0x3fff));
300 memcpy (*namep, np->dn->trans, *namelen);
301 return 0;
302}
303
304error_t
305diskfs_set_translator (struct node *np,
306 const char *name, u_int namelen,
307 struct protid *cred)
308{
309 char *new;
310 if (namelen == 0)
311 {
312 free (np->dn->trans);
313 new = 0;
314 np->dn_stat.st_mode &= ~S_IPTRANS000010000000;
315 }
316 else
317 {
318 new = realloc (np->dn->trans, namelen);
319 if (new == 0)
320 return ENOSPC((0x10 << 26) | ((28) & 0x3fff));
321 memcpy (new, name, namelen);
322 np->dn_stat.st_mode |= S_IPTRANS000010000000;
323 }
324 adjust_used (namelen - np->dn->translen);
325 np->dn->trans = new;
326 np->dn->translen = namelen;
327 recompute_blocks (np);
328 return 0;
329}
330
331static error_t
332create_symlink_hook (struct node *np, const char *target)
333{
334 assert (np->dn->u.lnk == 0)((np->dn->u.lnk == 0) ? (void) (0) : __assert_fail ("np->dn->u.lnk == 0"
, "../../tmpfs/node.c", 334, __PRETTY_FUNCTION__))
;
335 np->dn_stat.st_size = strlen (target);
336 if (np->dn_stat.st_size > 0)
337 {
338 const size_t size = np->dn_stat.st_size + 1;
339 np->dn->u.lnk = malloc (size);
340 if (np->dn->u.lnk == 0)
341 return ENOSPC((0x10 << 26) | ((28) & 0x3fff));
342 memcpy (np->dn->u.lnk, target, size);
343 np->dn->type = DT_LNKDT_LNK;
344 adjust_used (size);
345 recompute_blocks (np);
346 }
347 return 0;
348}
349error_t (*diskfs_create_symlink_hook)(struct node *np, const char *target)
350 = create_symlink_hook;
351
352static error_t
353read_symlink_hook (struct node *np, char *target)
354{
355 memcpy (target, np->dn->u.lnk, np->dn_stat.st_size + 1);
356 return 0;
357}
358error_t (*diskfs_read_symlink_hook)(struct node *np, char *target)
359 = read_symlink_hook;
360
361void
362diskfs_write_disknode (struct node *np, int wait)
363{
364}
365
366void
367diskfs_file_update (struct node *np, int wait)
368{
369 diskfs_node_update (np, wait);
370}
371
372error_t
373diskfs_node_reload (struct node *node)
374{
375 return 0;
376}
377
378
379/* The user must define this function. Truncate locked node NP to be SIZE
380 bytes long. (If NP is already less than or equal to SIZE bytes
381 long, do nothing.) If this is a symlink (and diskfs_shortcut_symlink
382 is set) then this should clear the symlink, even if
383 diskfs_create_symlink_hook stores the link target elsewhere. */
384error_t
385diskfs_truncate (struct node *np, off_t size)
386{
387 if (np->dn->type == DT_LNKDT_LNK)
388 {
389 free (np->dn->u.lnk);
390 adjust_used (size - np->dn_stat.st_size);
391 np->dn->u.lnk = 0;
392 np->dn_stat.st_size = size;
393 return 0;
394 }
395
396 if (np->allocsize <= size)
397 return 0;
398
399 assert (np->dn->type == DT_REG)((np->dn->type == DT_REG) ? (void) (0) : __assert_fail (
"np->dn->type == DT_REG", "../../tmpfs/node.c", 399, __PRETTY_FUNCTION__
))
;
400
401 if (default_pager == MACH_PORT_NULL((mach_port_t) 0))
402 return EIO((0x10 << 26) | ((5) & 0x3fff));
403
404 np->dn_stat.st_size = size;
405
406 off_t set_size = size;
407 size = round_page (size)((((vm_offset_t) (size) + __vm_page_size - 1) / __vm_page_size
) * __vm_page_size)
;
408
409 if (np->dn->u.reg.memobj != MACH_PORT_NULL((mach_port_t) 0))
410 {
411 error_t err = default_pager_object_set_size (np->dn->u.reg.memobj, set_size);
412 if (err == MIG_BAD_ID-303)
413 /* This is an old default pager. We have no way to truncate the
414 memory object. Note that the behavior here will be wrong in
415 two ways: user accesses past the end won't fault; and, more
416 importantly, later growing the file won't zero the contents
417 past the size we just supposedly truncated to. For proper
418 behavior, use a new default pager. */
419 return 0;
420 if (err)
421 return err;
422 }
423 /* Otherwise it never had any real contents. */
424
425 adjust_used (size - np->allocsize);
426 np->dn_stat.st_blocks += (size - np->allocsize) / 512;
427 np->allocsize = size;
428
429 return 0;
430}
431
432/* The user must define this function. Grow the disk allocated to locked node
433 NP to be at least SIZE bytes, and set NP->allocsize to the actual
434 allocated size. (If the allocated size is already SIZE bytes, do
435 nothing.) CRED identifies the user responsible for the call. */
436error_t
437diskfs_grow (struct node *np, off_t size, struct protid *cred)
438{
439 assert (np->dn->type == DT_REG)((np->dn->type == DT_REG) ? (void) (0) : __assert_fail (
"np->dn->type == DT_REG", "../../tmpfs/node.c", 439, __PRETTY_FUNCTION__
))
;
440
441 if (np->allocsize >= size)
442 return 0;
443
444 off_t set_size = size;
445 size = round_page (size)((((vm_offset_t) (size) + __vm_page_size - 1) / __vm_page_size
) * __vm_page_size)
;
446 if (round_page (tmpfs_space_used + size - np->allocsize)((((vm_offset_t) (tmpfs_space_used + size - np->allocsize)
+ __vm_page_size - 1) / __vm_page_size) * __vm_page_size)
447 / vm_page_size > tmpfs_page_limit)
448 return ENOSPC((0x10 << 26) | ((28) & 0x3fff));
449
450 if (default_pager == MACH_PORT_NULL((mach_port_t) 0))
451 return EIO((0x10 << 26) | ((5) & 0x3fff));
452
453 if (np->dn->u.reg.memobj != MACH_PORT_NULL((mach_port_t) 0))
454 {
455 /* Increase the limit the memory object will allow to be accessed. */
456 error_t err = default_pager_object_set_size (np->dn->u.reg.memobj, set_size);
457 if (err == MIG_BAD_ID-303) /* Old default pager, never limited it. */
458 err = 0;
459 if (err)
460 return err;
461 }
462
463 adjust_used (size - np->allocsize);
464 np->dn_stat.st_blocks += (size - np->allocsize) / 512;
465 np->allocsize = size;
466 return 0;
467}
468
469mach_port_t
470diskfs_get_filemap (struct node *np, vm_prot_t prot)
471{
472 error_t err;
473
474 if (np->dn->type != DT_REGDT_REG)
475 {
476 errno(*__errno_location ()) = EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); /* ? */
477 return MACH_PORT_NULL((mach_port_t) 0);
478 }
479
480 if (default_pager == MACH_PORT_NULL((mach_port_t) 0))
481 {
482 errno(*__errno_location ()) = EIO((0x10 << 26) | ((5) & 0x3fff));
483 return MACH_PORT_NULL((mach_port_t) 0);
484 }
485
486 /* We don't bother to create the memory object until the first time we
487 need it (i.e. first mapping or i/o). This way we might have a clue
488 what size it's going to be beforehand, so we can tell the default
489 pager how big to make its bitmaps. This is just an optimization for
490 the default pager; the memory object can be expanded at any time just
491 by accessing more of it. (It also optimizes the case of empty files
492 so we might never make a memory object at all.) */
493 if (np->dn->u.reg.memobj == MACH_PORT_NULL((mach_port_t) 0))
494 {
495 error_t err = default_pager_object_create (default_pager,
496 &np->dn->u.reg.memobj,
497 np->allocsize);
498 if (err)
499 {
500 errno(*__errno_location ()) = err;
501 return MACH_PORT_NULL((mach_port_t) 0);
502 }
503 assert (np->dn->u.reg.memobj != MACH_PORT_NULL)((np->dn->u.reg.memobj != ((mach_port_t) 0)) ? (void) (
0) : __assert_fail ("np->dn->u.reg.memobj != ((mach_port_t) 0)"
, "../../tmpfs/node.c", 503, __PRETTY_FUNCTION__))
;
504
505 /* XXX we need to keep a reference to the object, or GNU Mach
506 will terminate it when we release the map. */
507 vm_map (mach_task_self ()((__mach_task_self_ + 0)), &np->dn->u.reg.memref, 4096, 0, 1,
508 np->dn->u.reg.memobj, 0, 0, VM_PROT_NONE((vm_prot_t) 0x00), VM_PROT_NONE((vm_prot_t) 0x00),
509 VM_INHERIT_NONE((vm_inherit_t) 2));
510 assert_perror (err)(!(err) ? (void) (0) : __assert_perror_fail ((err), "../../tmpfs/node.c"
, 510, __PRETTY_FUNCTION__))
;
511 }
512
513 /* XXX always writable */
514
515 /* Add a reference for each call, the caller will deallocate it. */
516 err = mach_port_mod_refs (mach_task_self ()((__mach_task_self_ + 0)), np->dn->u.reg.memobj,
517 MACH_PORT_RIGHT_SEND((mach_port_right_t) 0), +1);
518 assert_perror (err)(!(err) ? (void) (0) : __assert_perror_fail ((err), "../../tmpfs/node.c"
, 518, __PRETTY_FUNCTION__))
;
519
520 return np->dn->u.reg.memobj;
521}
522
523/* The user must define this function. Return a `struct pager *' suitable
524 for use as an argument to diskfs_register_memory_fault_area that
525 refers to the pager returned by diskfs_get_filemap for node NP.
526 NP is locked. */
527struct pager *
528diskfs_get_filemap_pager_struct (struct node *np)
529{
530 return 0;
531}
532
533/* We have no pager of our own, so there is no need to worry about
534 users of it, or to shut it down. */
535int
536diskfs_pager_users ()
537{
538 return 0;
539}
540void
541diskfs_shutdown_pager ()
542{
543}
544
545/* The purpose of this is to decide that it's ok to make the fs read-only.
546 Turning a temporary filesystem read-only seem pretty useless. */
547vm_prot_t
548diskfs_max_user_pager_prot ()
549{
550 return VM_PROT_READ((vm_prot_t) 0x01); /* Probable lie that lets us go read-only. */
551}
552
553error_t
554diskfs_S_file_get_storage_info (struct protid *cred,
555 mach_port_t **ports,
556 mach_msg_type_name_t *ports_type,
557 mach_msg_type_number_t *num_ports,
558 int **ints, mach_msg_type_number_t *num_ints,
559 off_t **offsets,
560 mach_msg_type_number_t *num_offsets,
561 char **data, mach_msg_type_number_t *data_len)
562{
563 mach_port_t memobj = diskfs_get_filemap (cred->po->np, VM_PROT_ALL(((vm_prot_t) 0x01)|((vm_prot_t) 0x02)|((vm_prot_t) 0x04)));
564 if (memobj == MACH_PORT_NULL((mach_port_t) 0))
565 return errno(*__errno_location ());
566
567 assert (*num_ports >= 1)((*num_ports >= 1) ? (void) (0) : __assert_fail ("*num_ports >= 1"
, "../../tmpfs/node.c", 567, __PRETTY_FUNCTION__))
; /* mig always gives us some */
568 *num_ports = 1;
569 *ports_type = MACH_MSG_TYPE_MOVE_SEND17;
570 (*ports)[0]
571 = (cred->po->openstat & O_RDWR(0x0001|0x0002)) == O_RDWR(0x0001|0x0002) ? memobj : MACH_PORT_NULL((mach_port_t) 0);
572
573 assert (*num_offsets >= 2)((*num_offsets >= 2) ? (void) (0) : __assert_fail ("*num_offsets >= 2"
, "../../tmpfs/node.c", 573, __PRETTY_FUNCTION__))
; /* mig always gives us some */
574 *num_offsets = 2;
575 (*offsets)[0] = 0;
576 (*offsets)[1] = cred->po->np->dn_stat.st_size;
577
578 assert (*num_ints >= 6)((*num_ints >= 6) ? (void) (0) : __assert_fail ("*num_ints >= 6"
, "../../tmpfs/node.c", 578, __PRETTY_FUNCTION__))
; /* mig always gives us some */
579 *num_ints = 6;
580 (*ints)[0] = STORAGE_MEMORY;
581 (*ints)[1] = (cred->po->openstat & O_WRITE0x0002) ? 0 : STORE_READONLY0x0100;
582 (*ints)[2] = 1; /* block size */
583 (*ints)[3] = 1; /* 1 run in offsets list */
584 (*ints)[4] = 0; /* name len */
585 (*ints)[5] = 0; /* misc len */
586
587 *data_len = 0;
588
589 return 0;
590}